我已经多次看到下面的实例变量(例如 obj_foo 和 obj_bar)被重新分配为局部方法变量(例如在 调用):
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()
我不确定这是惯例(易于阅读)还是有更重要的目的?
这是不好的做法吗?
这会影响性能吗?
请您参考如下方法:
通常,没有理由这样做,但在某些情况下可能是:
- 更快(因为访问局部变量很快)
- 更易于阅读(因为它更短)
速度可能是这里更重要的因素。访问成员变量涉及各种机制(参见 __getattr__ 、 __getattribute__ 、 __dict__ 、 descriptors )需要一些时间来解决。此外,变量的 getter 可能会做一些更昂贵的事情。
另一方面,局部变量在 CPython 中是在编译时优化的,所以实际上没有在 __dict__ 中查找名为 'obj_foo' 的变量,但是相反,解释器只选择第一个局部变量,因为它知道 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
恕我直言,在这种情况下,差异几乎不足以证明添加一行代码是合理的。
