Python 类成员查找的底层机制

发布于 2024-12-09 09:46:07 字数 699 浏览 1 评论 0原文

在 Python 中,如果我定义三个类:

class A:
    name = 'oliver'
    hailstone_ending = [4,2,1]

class B:
    def __init__(self):
        self.name = 'oliver'
        self.hailstone_ending = [4,2,1]

class C:
    pass

c = C()
c.name = 'oliver'
c.hailstone_ending = [4,2,1]

在底层,每个类的成员查找功能是否以相同的方式运行?似乎 A 只需要字典即可查找所有实例的成员;另一方面,C 需要使用存储在每个实例中的字典。如果解释器非常智能,理论上它可以注意到 B 的所有实例 必须 包含成员 namehailstone_ending ;因此,它可能相当于A

但另一方面,如果在查找类成员的字典上允许执行 del 操作,则所有这些类中的查找机制可能是等效的,因为可用的成员将是依赖于实例的。

我的兴趣是,我有一些代码创建了数千个 C 类型的类,我注意到它非常慢并且占用内存。我最近用不同的方式重写了它,感觉效率更高(但我没有严格测试它,所以可能是一样的)。

非常感谢您的见解!

In Python, if I define three classes:

class A:
    name = 'oliver'
    hailstone_ending = [4,2,1]

class B:
    def __init__(self):
        self.name = 'oliver'
        self.hailstone_ending = [4,2,1]

class C:
    pass

c = C()
c.name = 'oliver'
c.hailstone_ending = [4,2,1]

Under the hood, does member lookup function in the same way for each class? It seems that A would only need on dictionary to lookup members for all instances; C, on the other hand, would need to use a dictionary stored within each of these instances. If the interpreter were very intelligent, it could theoretically notice that all instances of B must include members name and hailstone_ending; therefore, it could be equivalent to A.

But on the other hand, if the del operation is permitted on the dictionary that looks up class members, the machinery for lookup in all of these classes may be equivalent, because the available members would be instance-dependent.

My interest is that I had some code that created several thousand classes of type C and I noticed it was very slow and memory hungry. I rewrote it recently a different way, and it feels more efficient (but I haven't rigorously tested it, and so it may be the same).

Thanks a lot for your insight!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

诠释孤独 2024-12-16 09:46:07

在幕后,每个类的成员查找功能是否都以相同的方式进行?

除非您重写__getattribute__,否则属性查找首先检查对象属性,然后键入属性。它并不关心班级是如何形成的。

看起来 A 只需要在字典中查找所有实例的成员;另一方面,C 需要使用存储在每个实例中的字典。如果解释器非常聪明,理论上它可以注意到B的所有实例都必须包含成员名称和Hailstone_ending;因此,它可以等价于A。

A中,属性存储在A.__dict__中,即存储在类型上。在BC中,属性存储在self.__dict__中,即在实例上。两种字典在所有情况下都存在。没有更多的事情了。不,BC 之间没有区别。

Under the hood, does member lookup function in the same way for each class?

Unless you override __getattribute__, the attribute lookup first checks object attributes, then type attributes. It doesn't care how the class came to be.

It seems that A would only need on dictionary to lookup members for all instances; C, on the other hand, would need to use a dictionary stored within each of these instances. If the interpreter were very intelligent, it could theoretically notice that all instances of B must include members name and hailstone_ending; therefore, it could be equivalent to A.

In A, attributes are stored in A.__dict__, i.e. on the type. In B and C, attributes are stored in the self.__dict__, i.e. on the instance. Both dictionaries are present in all cases. There's nothing more to it. And no, there is no difference between B and C.

叶落知秋 2024-12-16 09:46:07

在Python中,每个类和每个实例都有一个字典。 A 使用类字典。类 BC 的示例使用实例字典。 B 不会等价于 A —— python 的目的并不是要快,要证明没有 B< 的实例,即使不是不可能,也会非常困难。 /code> 会发生变异。

证明:

>>> class D:
...   def __init__(self):
...     self.a = 3
... 
>>> d = D()
>>> d.a
3
>>> D.a
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: class D has no attribute 'a'
>>> dd = D()
>>> dd.a
3
>>> D.a
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: class D has no attribute 'a'

你的问题让我想到了 javascript 的原型。

另外:如果在实例字典中找不到成员,则成员查找可以依靠类字典,但写入将使用实例字典。

In python, each class and each instance gets a dictionary. A uses the class dictionary. The examples for classes B and C are using the instance dictionaries. B will not be equivalent to A -- python is not intended to be fast, it would be very hard if not impossible to prove that no instances of B would get mutated.

Proof:

>>> class D:
...   def __init__(self):
...     self.a = 3
... 
>>> d = D()
>>> d.a
3
>>> D.a
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: class D has no attribute 'a'
>>> dd = D()
>>> dd.a
3
>>> D.a
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: class D has no attribute 'a'

Your question makes me think of javascript's prototypes.

Also: member lookup can fall back on the class dictionary, if the member is not found in the instance dictionary, but writing will use the instance dictionary.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文