在__init__中构造对象

Col*_*lin 2 python constructor

我见过看起来像这样的代码:

class MyClass:
    def __init__(self, someargs):
        myObj = OtherClass()
        myDict = {}
        ...code to setup myObj, myDict...
        self.myObj = myObj
        self.myDict = myDict
Run Code Online (Sandbox Code Playgroud)

当我看到这个时,我的第一个想法是:为什么不在开始时使用self.myObj和self.myDict?构造本地对象似乎效率低下,然后将它们分配给成员.构造对象的代码可能会抛出异常,也许他们这样做了所以它不会留下一个半构造的对象?你这样做,还是直接构建成员?

aar*_*ing 8

构造对象然后将其附加到更快,更可读self.

class Test1(object):
    def __init__(self):
        d = {}
        d['a'] = 1
        d['b'] = 2
        d['c'] = 3
        self.d = d

class Test2(object):
    def __init__(self):
        self.d = {}
        self.d['a'] = 1
        self.d['b'] = 2
        self.d['c'] = 3

import dis
print "Test1.__init__"
dis.dis(Test1.__init__)

print "Test2.__init__"
dis.dis(Test2.__init__)
Run Code Online (Sandbox Code Playgroud)

反汇编:

Test1.__init__
  4           0 BUILD_MAP                0
              3 STORE_FAST               1 (d)

  5           6 LOAD_CONST               1 (1)
              9 LOAD_FAST                1 (d)
             12 LOAD_CONST               2 ('a')
             15 STORE_SUBSCR        

  6          16 LOAD_CONST               3 (2)
             19 LOAD_FAST                1 (d)
             22 LOAD_CONST               4 ('b')
             25 STORE_SUBSCR        

  7          26 LOAD_CONST               5 (3)
             29 LOAD_FAST                1 (d)
             32 LOAD_CONST               6 ('c')
             35 STORE_SUBSCR        

  8          36 LOAD_FAST                1 (d)
             39 LOAD_FAST                0 (self)
             42 STORE_ATTR               0 (d)
             45 LOAD_CONST               0 (None)
             48 RETURN_VALUE        
Test2.__init__
 12           0 BUILD_MAP                0
              3 LOAD_FAST                0 (self)
              6 STORE_ATTR               0 (d)

 13           9 LOAD_CONST               1 (1)
             12 LOAD_FAST                0 (self)
             15 LOAD_ATTR                0 (d)
             18 LOAD_CONST               2 ('a')
             21 STORE_SUBSCR        

 14          22 LOAD_CONST               3 (2)
             25 LOAD_FAST                0 (self)
             28 LOAD_ATTR                0 (d)
             31 LOAD_CONST               4 ('b')
             34 STORE_SUBSCR        

 15          35 LOAD_CONST               5 (3)
             38 LOAD_FAST                0 (self)
             41 LOAD_ATTR                0 (d)
             44 LOAD_CONST               6 ('c')
             47 STORE_SUBSCR        
             48 LOAD_CONST               0 (None)
             51 RETURN_VALUE
Run Code Online (Sandbox Code Playgroud)

你可以看到,STORE_ATTR只有在最后一次做到这一点时才会被调用.从另一个方面来说,STORE_ATTR仍然会在开始LOAD_ATTR时调用,但现在每次访问字典时都会调用它.分配越多,成本越高.其他每条指令都是一样的.它仍然是一个可笑的小成本.

这个技巧可以被利用来使循环具有更多的迭代运行更快.看到类似的事情并不罕见

foo = self.foo
factorial = math.factorial
for x in really_big_iterator:
    foo(factorial(x))
Run Code Online (Sandbox Code Playgroud)

另一个技巧是将全局函数作为默认参数传递给具有类似循环的函数,或者调用整个集合以保存一些属性查找:它位于本地范围内,这是第一个查看的范围.

def fast(iterators, sum=sum):
    for i in iterator:
        yield sum(i)
Run Code Online (Sandbox Code Playgroud)

现在总和是在当地范围内.