繁体   English   中英

Python | 使用子 class ZA8CFDE6331BD59EB2AC96F891DZ 从父 class 访问变量比从子 class 访问相同变量慢

[英]Python | Is accessing a variable from parent class slower than accessing the same variable from child class, using a child class object?

class Animal():
    def add(self):
        self.weight = 10
        self.color = 'Black'

class Bird(Animal):
    def add(self):
        self.feather_type = 'Long'
        super().add()


b = Bird()
b.add()
print(b.weight)
print(b.color)
print(b.feather_type) // will this be faster than above 2 statements ?

从父 class、子 class 的对象访问变量是否比直接从子 class 访问变量慢?

If there are lot of variables 10+ (including arrays and Data Model objects) in parent class, and each of them is used in child class, is it suggested to add those in each of child class and remove from parent class for better performance? (当我写这篇文章时听起来很愚蠢,因为这与整个 inheritance 概念相矛盾)

将它们作为局部变量存储在子 class 函数中,然后访问它们会更好吗? (如果多次使用)

在代码中,变量没有在__init__方法中初始化。 在这种情况下,这会使程序变慢吗? 这样做是因为 class 的所有属性对于所有操作操作都不是必需的。 因此,何时并根据需要对它们进行初始化和使用。 (注意:请注意在执行操作之前创建所需的属性)。

If there are lot of variables 10+ (including arrays and Data Model objects) in parent class, and each of them is used in child class, is it suggested to add those in each of child class and remove from parent class for better performance? (当我写这篇文章时听起来很愚蠢,因为这与整个 inheritance 概念相矛盾)

让我们对其进行基准测试并找出答案。 为了测试这样的事情,我喜欢使用我编写的模块: timerit

import timerit


class Animal():
    def add(self):
        self.weight = 10
        self.color = 'Black'


class Bird(Animal):
    def add(self):
        self.feather_type = 'Long'
        super().add()


b = Bird()
b.add()

ti = timerit.Timerit(1000000, bestof=100, verbose=2)
for timer in ti.reset('Access weight'):
    with timer:
        b.weight

for timer in ti.reset('Access color'):
    with timer:
        b.color

for timer in ti.reset('Access feather_type'):
    with timer:
        b.feather_type

这导致

Timed Access weight for: 1000000 loops, best of 100
    time per loop: best=347.005 ns, mean=370.222 ± 17.2 ns
Timed Access color for: 1000000 loops, best of 100
    time per loop: best=350.992 ns, mean=367.194 ± 9.5 ns
Timed Access feather_type for: 1000000 loops, best of 100
    time per loop: best=348.984 ns, mean=367.680 ± 11.9 ns

因此,不,它们之间似乎没有任何显着差异。

实例属性都将在实例 object 本身上创建。 父/子关系在那里无关紧要。

b.add()

这调用:

def add(self):
    ...

这里的self将是b 现在调用super.add() ,这又是:

def add(self):
    ...

这里的self仍然是b 属性全部直接添加到同一个object中。

可以说解决super().add()调用将是一个轻微的开销,但它绝对可以忽略不计。 如果存在的话,访问属性的任何区别也会如此。

实例属性存储在实例中,因此 inheritance 在这里完全无关紧要。 请记住,当在子实例上调用父 class 方法时,该方法作为第一个参数 ( self ) 得到的是子实例:

>>> class Foo:
...    def __init__(self):
...        print("In Foo.__init__, self is {}".format(self))
... 
>>> class Bar(Foo): pass
... 
>>> b = Bar()
In Foo.__init__, self is <__main__.Bar object at 0x7fd230244f60>
>>> 

将它们作为局部变量存储在子 class 函数中,然后访问它们会更好吗? (如果多次使用)

仅适用于紧密循环中使用的属性(属性解析比局部变量解析慢一点)并且分析显示此时存在瓶颈。 但也不要指望大幅加速......

实际上,如果您不得不担心这种微优化,真正的解决方案是重新考虑您的设计和实现,或者重新实现 C 中代码的关键部分。

在代码中,变量没有在init方法中初始化。 这会使程序变慢吗

不是真的,除了调用obj.add()的开销。 但是

这样做是因为,并非所有操作都需要 class 的所有属性。 因此,何时并根据需要对它们进行初始化和使用。

错误的设计。 如果您想对某些属性进行延迟初始化,请使用property或一些自定义描述符 这将确保您的对象无论发生什么都将始终具有预期的属性。

如果父 class 中有很多变量 10+(包括 arrays 和数据 Model 对象)

class 中的“很多”属性通常是一种设计气味。 这里没有硬性规定 - 有些情况确实需要相当多的属性 - 但您的 class 的职责可能太多,最好将其重构为一组最小的类,每个类都有一个明确定义的职责。

不,将父级的 class 属性初始化复制粘贴到子级 class 无论如何都不会加速您的代码 - 它只会使维护变得无用地更加困难,并增加在更改父级或子级 ZA2F2ED4F8EBC40AB1.0 时引入错误的风险。 我个人认为 label 这是一个完整的 WTF,但我并不以我与生俱来的外交意识而闻名;-)

编辑

实际上我在这里没有提到的一件事,我在 init 之外创建变量的另一个主要原因是因为我在我的代码中使用了工厂设计模式。 我正在使用动态创建类

def _create(pkg): 
    exec('import api.' + pkg + 'Helper as Creator'); 
    return eval('Creator' + '.' + pkg + 'Helper()' )

呃……你可能有兴趣了解 Python 的一些特性,比如importlib.import_modulegetattr 作为一般规则,每当您考虑使用evalexec时,请确保有更好的(=> 更安全、更明确且更易于维护)的解决方案。 我已经使用 Python 20 多年了(用于个人和专业项目),我仍然需要找到一个我有正当理由使用evalexec的案例。

此外,您没有发布实际上“动态创建类”但动态创建类不会施加任何限制或解决方法(与“静态”定义相比)的代码部分 - 您仍然可以为您的 class 提供适当的初始化程序,属性或任何其他自定义描述符等。如果您还使用exec̀̀ / eval来构建您的 class,那么这里还有更好的方法。

我的2美分...

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM