我们说我有一个这样的课程:
class Foo(namedtuple('Foo', ['f1'])):
def f1(self):
print('Default f1')
def __new__(cls, f1=f1):
return super().__new__(cls, f1)
让我们说我稍后会创建一个Foo对象并选择覆盖f1的方法定义,如下所示:
def my_f1():
print("My f1")
foo = Foo(f1=my_f1)
如果我再尝试:
foo.f1()
我明白了:
Default f1
我试图获得"我的f1"当然要打印。我也希望f1是可选的。这里发生了什么?是否可以为namedtuple中的方法定义默认实现,然后在 new 中覆盖它?
答案 0 :(得分:5)
您不能同时使用相同名称的方法和插槽。命名元组使用slots,并且这些元素在与方法相同的命名空间中实现为property
个对象。通过定义方法f1
,您破坏了f1
属性:
>>> from collections import namedtuple
>>> namedtuple('Foo', ['f1']).f1
<property object at 0x1069764c8>
>>> class Foo(namedtuple('Foo', ['f1'])):
... def f1(self):
... print('Default f1')
...
>>> Foo.f1
<unbound method Foo.f1>
property
对象只返回self[0]
。因此,要么按位置访问f1
值:
class Foo(namedtuple('Foo', ['f1'])):
def f1(self):
if self[0]:
return self[0]()
print('Default f1')
或为您的属性指定一个不同的名称,并将f1
方法委托给该名称:
class Foo(namedtuple('Foo', ['f1_callable'])):
def f1(self):
if self.f1_callable:
return self.f1_callable()
print('Default f1')
演示:
>>> def my_f1():
... print("My f1")
...
>>> class Foo(namedtuple('Foo', ['f1'])):
... def f1(self):
... if self[0]:
... return self[0]()
... print('Default f1')
...
>>> foo = Foo(my_f1)
>>> foo.f1()
My f1
>>> foo = Foo(None)
>>> foo.f1()
Default f1
答案 1 :(得分:0)
避免在f1
内声明class Foo
。相反,在模块级别声明它,并将其用作default argument for your namedtuple:
def f1():
print('Default f1')
Foo = namedtuple('Foo', 'f1')
Foo.__new__.__defaults__ = (f1,)
用法:
>>> foo = Foo()
>>> foo.f1()
Default f1
>>> def other_f1():
... print('Another f1')
>>> foo = Foo(f1=other_f1)
>>> foo.f1()
Another f1