列出命名元组子类的属性
我有一个小类,它是从 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
从普通类扩展时,这个问题就不存在了。
这是怎么回事,我该如何在我的子类实例中列出属性呢?
3 个回答
在编程中,有时候我们会遇到一些问题,特别是在使用某些工具或库的时候。比如,有人可能在使用一个叫做“库”的东西时,发现它的某些功能没有按照预期工作。这种情况可能会让人感到困惑,因为我们不知道问题出在哪里。
通常,解决这些问题的第一步是仔细检查代码,看看有没有写错的地方。接着,可以查阅相关的文档,看看这个库的使用方法是否正确。有时候,文档里会有示例代码,帮助我们理解如何正确使用这个库。
如果自己解决不了,也可以去一些技术论坛,比如StackOverflow,向其他人请教。在提问的时候,最好把自己的代码和遇到的问题详细描述清楚,这样别人才能更好地帮助你。
总之,遇到问题时,不要急于放弃,耐心寻找解决方案,通常都能找到答案。
list(A.__annotations__.keys())
问题在于,__slots__
只对定义它的类有效,所以基类总是会有自己的 __dict__
属性,除非你在基类中也定义 __slots__
。另外,namedtuple
的 __dict__
属性并不是一个普通的字典,而是一个 @property。
根据 文档:
一个
__slots__
声明的作用仅限于定义它的类。因此,子类会有一个__dict__
,除非它们也定义了__slots__
(而且这个__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
()
要了解为什么 __dict__
不起作用,可以查看 Ashwini Chaudhary 的回答。这个回答讲解了问题的第二部分(如何列出命名元组的属性)。
要列出命名元组的属性,可以使用 _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 来做示例,我不太确定这些内容是什么时候添加的(也许知道的人可以评论一下)。