6

我有一个扩展 a 的小类namedtuple,但__dict__其实例的属性始终返回空。

Point = namedtuple('Point', 'x y')
p1 = Point(20, 15)
print(p1, p1.__dict__)
# Point(x=20, y=15) OrderedDict([('x', 20), ('y', 15)]) <--- ok

class SubPoint(Point): pass
p2 = SubPoint(20, 15)
print(p2, p2.__dict__)
# SubPoint(x=20, y=15) {} <--- why is it empty?

p2有属性,但它__dict__是空的。但是,它们用 正确列出dir(),这很奇怪。请注意,在SubPoint扩展 vanilla 类时可以正常工作。

发生了什么,如何列出子类实例中的属性?

4

4 回答 4

4

问题是它__slots__仅限于定义它的类,因此基类将始终具有自己的__dict__属性,除非您__slots__也在那里定义。(还要注意,__dict__属性 ofnamedtuple不是普通的 dict 而是@property。)

来自文档

声明的作用__slots__仅限于定义它的类。因此,子类将有一个__dict__除非它们也定义__slots__(它必须只包含任何附加插槽的名称)。

因此,当您__slots__在子类中定义时,它无法__dict__在该类中查找属性,因此转到找到该__dict__属性的基类。

一个简单的演示:

class A:
    __slots__=  ('a', 'b')

    @property
    def __dict__(self):
        print ('inside A')
        return self.__slots__         

class B(A):
    pass

print(B().__dict__)

print ('-'*20)

class B(A):
    __slots__ = ()
print(B().__dict__)

输出:

{}
--------------------
inside A
()
于 2014-03-31T05:15:37.300 回答
1

要了解为什么__dict__不起作用,请查看Ashwini Chaudhary 的答案。这个答案涵盖了问题的第二部分(如何列出 namedtuple 属性)。

要列出 namedtuple 属性,有_fields_asdict

>>> import collections as c
>>> Point = c.namedtuple("Point", ["x", "y"])
>>> p1 = Point(20, 15)
>>> print(p1._fields)
('x', 'y')
>>> print(p1._asdict())
{'x': 20, 'y': 15}
>>> class SubPoint(Point): pass
...
>>> p2 = SubPoint(20, 15)
>>> print(p2._fields)
('x', 'y')
>>> print(p2._asdict())
{'x': 20, 'y': 15}

请注意,这_fields是在类上定义的,因此您还可以执行以下操作:

>>> print(SubPoint._fields)
('x', 'y')

显然,_asdict需要一个实例,以便它可以使用这些值。

我使用 Python 3.9.7 作为示例,我不确定何时添加了这些东西(也许知道的人可以发表评论)。

于 2021-10-05T06:58:49.413 回答
0

在子类中声明__slots__ = ()解决了这个问题,但原因尚不清楚。据我所知__slots__,不应该以如此微妙的方式改变代码的行为,所以这不是一个完整的答案。

Point = namedtuple('Point', 'x y')
p1 = Point(20, 15)
print(p1, p1.__dict__)
# Point(x=20, y=15) OrderedDict([('x', 20), ('y', 15)]) <--- ok

class SubPoint(Point):
    __slots__ = ()
p2 = SubPoint(20, 15)
print(p2, p2.__dict__)
# SubPoint(x=20, y=15) OrderedDict([('x', 20), ('y', 15)]) <--- fixed

欢迎提供解释的答案。

于 2014-03-31T04:43:13.090 回答
0
list(A.__annotations__.keys())
于 2019-08-14T22:28:17.960 回答