是否可以在 Python 中覆盖命名元组中的方法?
Posted
技术标签:
【中文标题】是否可以在 Python 中覆盖命名元组中的方法?【英文标题】:Is it possible to override a method in a namedtuple in Python? 【发布时间】:2015-12-23 11:29:53 【问题描述】:假设我有这样的课程:
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
当然,我正在尝试打印“My f1”。我也希望 f1 是可选的。这里发生了什么?是否可以在命名元组中为方法定义默认实现,然后在 new 中覆盖它?
【问题讨论】:
在我看来,您想要一个具有默认值的字段命名元组。在这种情况下,默认值是可调用的,但没有太大区别:***.com/questions/11351032/… @AndreaCorbellini:这有很大的不同,因为处理属性的属性被方法破坏了。 @MartijnPieters:只有当你想在class Foo
中声明 f1
时才会有所不同。但这会使事情过于复杂(有关详细信息,请参阅您自己的答案:P)。在 class Foo
之外声明 f1
并将其设置为默认参数会使事情变得更容易。
@AndreaCorbellini:但是 OP 期望 foo.f1()
在创建实例时从 f1
参数中工作。 self[0]
是默认的 None
还是默认的外部函数都没有关系..
@MartijnPieters:我不确定我是否理解您的最后评论。顺便说一句,我发布了一个答案。
【参考方案1】:
您不能让方法和槽使用相同的名称。命名元组使用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
【讨论】:
【参考方案2】:避免在class Foo
中声明f1
。相反,在模块级别声明它,并将其用作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
【讨论】:
以上是关于是否可以在 Python 中覆盖命名元组中的方法?的主要内容,如果未能解决你的问题,请参考以下文章