我可以替换 Python 中对象的现有方法吗?

新手上路,请多包涵

问: 有没有办法改变 Python (3.6) 中现有对象的方法? (“方法”是指作为参数传递的函数 self 。)


例子

假设我有一个类 Person 有一些非常有用的方法 SayHi()

 class Person(object):
    Cash = 100
    def HasGoodMood(self):
        return self.Cash > 10

    def SayHi(self):
        if self.HasGoodMood():
            print('Hello!')
        else:
            print('Hmpf.')

>>> joe = Person()
>>> joe.SayHi()
Hello!

如您所见,此人的反应取决于他们当前的情绪,该情绪由方法 HasGoodMood() 计算得出。违约者只要身上有超过 10 美元的现金,就会心情愉快。

我可以很容易地创造一个不在乎钱并且一直快乐的人:

 >>> joe.HasGoodMood = lambda: True
>>> joe.SayHi()
Hello!
>>> joe.Cash = 0
>>> joe.SayHi()
Hello!

凉爽的。请注意 Python 如何知道在使用 HasGoodMood 的原始实现时,它会默默地传递 self 作为第一个参数,但是如果我将它更改为 lambda: True 没有参数的函数。问题是:如果我想为另一个也接受 self 作为参数的函数更改默认值 HasGoodMood 怎么办?

让我们继续我们的例子:如果我想创建一个贪婪的 Person 谁只有超过 100 美元才会快乐?我想做类似的事情:

 >>> greedy_jack = Person()
>>> greedy_jack.HasGoodMood = lambda self: self.Cash > 100
TypeError: <lambda>() missing 1 required positional argument: 'self'

不幸的是,这不起作用。还有其他方法可以改变方法吗?


免责声明: 以上示例仅用于演示目的。我知道我可以使用继承或保留现金阈值作为 Person 的属性。但这不是问题的重点。

原文由 Jan Kukacka 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 553
2 个回答

使用一些提示:

是否可以在不更改同一类的所有其他实例的情况下更改实例的方法实现?

您可以执行以下操作,方法是使用类型模块将方法分配给创建的对象而不影响类。您需要这样做,因为函数不会自动接收 self 对象作为第一个变量,但方法会。

 import types

joe = Person()
bob = Person()

joe.SayHi()
>>> Hello!

def greedy_has_good_mood(self):
    return self.Cash > 100

joe.HasGoodMood = types.MethodType(greedy_has_good_mood, joe)

joe.SayHi()
>>> Hmpf.
bob.SayHi()

>>> Hello!

原文由 Andrew McDowell 发布,翻译遵循 CC BY-SA 4.0 许可协议

当你在一个类中编写一个 def ,然后在一个实例上调用它时,这是一个方法,方法调用的机制将在你调用它时填充 self 参数.

通过在您的实例中分配给 HasGoodMood ,您并不是在其中放置一个新方法,而是在属性中放置一个函数。您可以读取属性以获取函数并调用它,尽管这看起来像方法调用,但它只是调用恰好存储在属性中的函数。您不会获得自动提供的 self 参数。

但是您已经知道 self 将会是什么,因为您将此函数分配给一个特定的对象。

 greedy_jack.HasGoodMood = (lambda self=greedy_jack: self.Cash > 100)

这将函数参数 self 与变量的当前值 greedy_jack 相关联。

Python 中的 Lambda 只能是一行。如果您需要更长的功能,您可以使用 def 代替。

 def greedy_jack_HasGoodMood(self=greedy_jack):
    return self.Cash > 100

greedy_jack.HasGoodMood = greedy_jack_HasGoodMood

对于不太复杂的解决方案,请参阅 Andrew McDowell 的回答

原文由 khelwood 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
logo
Stack Overflow 翻译
子站问答
访问
宣传栏