我已经多次看到过,其中实例变量(例如obj_foo
和obj_bar
)被重新分配为本地方法变量(例如call
内):
class Example:
def __init__(self, obj_foo, obj_bar):
self.obj_foo = obj_foo
self.obj_bar = obj_bar
def call(self):
obj_foo, obj_bar = self.obj_foo, self.obj_bar
obj_foo.do_something()
obj_bar.do_something_else()
我不确定这是否符合惯例(易于阅读)或是否有更重要的目的?
这是不好的做法吗?
这会影响效果吗?
答案 0 :(得分:5)
通常,没有理由这样做,但在某些情况下可能是:
速度可能是这里更重要的因素。访问成员变量涉及需要一些时间来解决的各种机制(请参阅__getattr__
,__getattribute__
,__dict__
,descriptors)。此外,变量的getter可能会做更昂贵的事情。
另一方面,局部变量在编译时进行了CPython优化,因此实际上没有查找'obj_foo'
中名为__dict__
的变量,而是解释器只选择第一个本地变量变量,因为它知道obj_foo
是第一个局部变量而不需要搜索名称。
因此,如果在同一个函数中多次使用成员变量,并且分析显示访问该成员变量需要很长时间,那么使用局部变量可能会很有用。
通常情况下,这并没有太大的区别,但这是一个展示这个想法的例子:
class A:
def __init__(self,x):
self.x=x
def f(self):
for i in range(100):
self.x()
class B:
def __init__(self,x):
self.x=x
def f(self):
x=self.x
for i in range(100):
x()
时间几乎相同,但存在一些差异:
>>> timeit.timeit('a.f()', setup='a=A(lambda:None)', globals=locals())
13.119033042000638
>>>
>>> timeit.timeit('b.f()', setup='b=B(lambda:None)', globals=locals())
10.219889547632562
恕我直言,在这种情况下,差异几乎不足以证明添加一行代码是合理的。
答案 1 :(得分:1)
您可以这样做,以避免每次都写出self
。
但是,也可能有更重要的原因要做到这一点:它可以完全改变语义。例如:
def __init__(self, x):
self.x = 42
def theMethod(self):
x = self.x
self.x = 58
print(x)
print(self.x)
在此示例中,x
和self.x
不可互换,即使您已在x = self.x
的第一行指定了theMethod
。第一个print
将输出42
,第二个print
将输出58
。每次将某个成员变量分配给局部变量然后重写时,就会发生这种情况。
这对性能的影响并不完全明显,因为查找self.x
和x
都必须在字典中查找符号:在第一种情况下,成员变量的字典{ {2}},在第二种情况下,在当前范围内。它可能会对和产生负面影响,具体取决于每个范围中定义的变量数量和其他变量。在大多数非人为的案例中,可能对绩效产生微小的积极影响。
编辑:正如@zvone指出的那样,最后一段并不一定适用于python解释器的所有实现。