在__init__中构造对象

时间:2010-08-31 03:09:02

标签: python constructor

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

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

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

5 个答案:

答案 0 :(得分: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__)

反汇编:

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

你可以看到STORE_ATTR只有在最后的第一种方式进行时才被调用。换句话说,STORE_ATTR仍然在开始时被调用,但现在LOAD_ATTR会在每次访问字典时被调用。分配越多,成本越高。其他每条指令都是一样的。这仍然是一个非常小的成本。

这个技巧可以被利用来使循环具有更多的迭代运行得更快。看到像

这样的事情并不罕见
foo = self.foo
factorial = math.factorial
for x in really_big_iterator:
    foo(factorial(x))

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

def fast(iterators, sum=sum):
    for i in iterator:
        yield sum(i)

现在总和在本地范围内。

答案 1 :(得分:3)

如果您担心复制对象引用的性能影响,您可能使用了错误的语言:)

做一些对您更具可读性的内容。在这种情况下,它取决于init方法的时间长度。

答案 2 :(得分:1)

我不确定我是否完全理解您的问题,但请记住,分配self.myObj = myObj只会分配一个引用,因此不太可能减慢速度。我的猜测是习惯用来保存程序员多次输入单词self

答案 3 :(得分:0)

两种方式都没有显着差异。创建局部变量的一个原因是,如果要在__init__中大量使用变量,则不必重复self.。 e.g。

def __init__(self, someargs):
    self.myObj = OtherClass()
    self.myDict = {}
    self.myDict[1] = self.myObj
    self.myDict[2] = self.myObj
    self.myDict[3] = self.myObj
    self.myDict[4] = self.myObj
    self.myObj = myObj
    self.myDict = myDict

v.s。

def __init__(self, someargs):
    obj = OtherClass()
    d = {}
    d[1] = obj
    d[2] = obj
    d[3] = obj
    d[4] = obj
    self.myObj = obj
    self.myDict = d

除非你有充分的理由,否则我不会太担心表现。

答案 4 :(得分:0)

分配引用并不会花费太多时间,但每次输入“self”确实需要时间。