我有以下名为tuple:
from collections import namedtuple
ReadElement = namedtuple('ReadElement', 'address value')
然后我想要以下内容:
LookupElement = namedtuple('LookupElement', 'address value lookups')
两个命名元组之间存在重复,我如何将ReadElement子类化为包含其他字段?
class LookupElement(ReadElement):
def __new__(self, address, value, lookups):
self = super(LookupElement, self).__new__(address, value)
l = list(self)
l.append(lookups)
return tuple(l)
然而,在 new 语句中创建了元组,如果我将self修改为列表,我将丢失类型信息,我该如何避免这种情况?
答案 0 :(得分:27)
您可以创建namedtuple
生成的类的子类,但是您需要更仔细地研究生成的类。您需要在额外字段中添加另一个__slots__
属性,更新_fields
属性,创建新的__repr__
和_replace
方法(他们对字段列表进行硬编码,类名)并为其他字段添加额外的property
个对象。请参阅example in the documentation。
这太过分了。我只是重用源类型的somenamedtuple._fields
attribute而不是子类:
LookupElement = namedtuple('LookupElement', ReadElement._fields + ('lookups',))
field_names
构造函数的namedtuple()
参数不必是字符串,它也可以是字符串序列。只需取_fields
并通过连接新元组添加更多元素。
演示:
>>> from collections import namedtuple
>>> ReadElement = namedtuple('ReadElement', 'address value')
>>> LookupElement = namedtuple('LookupElement', ReadElement._fields + ('lookups',))
>>> LookupElement._fields
('address', 'value', 'lookups')
>>> LookupElement('addr', 'val', 'lookup')
LookupElement(address='addr', value='val', lookups='lookup')
这确实意味着扩展类型不是基类型的子类。如果你必须有一个类层次结构,那么我不是试图使命名元组适合该模型,而是转而使用dataclasses。在大多数名为元组的用例中,数据类可以起到相同的作用,但很容易被子类化。
答案 1 :(得分:1)
将某些内容组合在一起非常容易,它允许您从其他命名元组合组成命名元组以及引入新字段。
def extended_namedtuple(name, source_fields):
assert isinstance(source_fields, list)
new_type_fields = []
for f in source_fields:
try:
new_type_fields.extend(f._fields)
except:
new_type_fields.append(f)
return namedtuple(name, new_type_fields)
# source types
Name = namedtuple('Name', ['first_name', 'last_name'])
Address = namedtuple('Address', ['address_line1', 'city'])
# new type uses source types and adds additional ID field
Customer = extended_namedtuple('Customer', ['ID', Name, Address])
# using the new type
cust1 = Customer(1, 'Banana', 'Man', '29 Acacia Road', 'Nuttytown')
print(cust1)
这输出以下内容:
Customer(ID=1, first_name='Banana', last_name='Man', address_line1='29 Acacia Road', city='Nuttytown')
答案 2 :(得分:1)
扩展Martijn Pieters' answer:有一种 方式,可以使新的namedtuple类成为另一个的子类,而无需进行修改。只需单独创建新的namedtuple
,然后使用其__new__
方法而不是使用super
:
from collections import namedtuple
class ReadElement(namedtuple('ReadElement', ('address', 'value'))):
def compute(self):
return self.value + 1
_LookupElement = namedtuple('_LookupElement', ReadElement._fields + ('lookups',))
class LookupElement(_LookupElement, ReadElement):
def __new__(self, address, value, lookups):
return _LookupElement.__new__(LookupElement, address, value, lookups)
assert issubclass(LookupElement, ReadElement)
l = LookupElement('ad', 1, dict())
assert isinstance(l, ReadElement)
assert l.compute() == 2
这似乎也可以在不覆盖__new__
的情况下起作用!
from collections import namedtuple
class ReadElement(namedtuple('ReadElement', ('address', 'value'))):
def compute(self):
return self.value + 1
class LookupElement(namedtuple('LookupElement', ReadElement._fields + ('lookups',)),
ReadElement):
"""nothing special to do"""
pass