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

Jan*_*cka 12 python methods python-3.x

问:有没有办法在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!
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,人的反应取决于他们通过该方法计算的当前情绪HasGoodMood().默认情况下,只要他们有10美元以上的现金,他们就会心情愉快.

我可以很容易地创造一个不关心金钱并且一直很开心的人:

>>> joe.HasGoodMood = lambda: True
>>> joe.SayHi()
Hello!
>>> joe.Cash = 0
>>> joe.SayHi()
Hello!
Run Code Online (Sandbox Code Playgroud)

凉.请注意Python如何知道在使用原始实现时HasGoodMood,它会以静默方式self作为第一个参数传递,但如果我将其更改为lambda: True,则会调用不带参数的函数.问题是:如果我想更改HasGoodMood另一个也接受self作为参数的函数的默认值,该怎么办?

让我们继续我们的例子:如果我想创造一个Person只有超过100美元的贪婪的人呢?我想做的事情如下:

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

不幸的是,这不起作用.有没有其他方法来改变方法?


免责声明:以上示例仅用于演示目的.我知道我可以使用继承或保留现金门槛作为财产Person.但这不是问题的关键.

khe*_*ood 11

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

通过HasGoodMood在您的实例中分配,您没有在那里放置新方法,而是将函数放入属性中.您可以读取该属性以获取该函数,并调用它,虽然这看起来像一个方法调用,但它只是调用恰好存储在属性中的函数.您不会self自动获得参数.

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

greedy_jack.HasGoodMood = (lambda self=greedy_jack: self.Cash > 100)
Run Code Online (Sandbox Code Playgroud)

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

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

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

greedy_jack.HasGoodMood = greedy_jack_HasGoodMood
Run Code Online (Sandbox Code Playgroud)

对于一个不太讨厌的解决方案,请参阅Andrew McDowell的回答.

  • 如果你说一些关于描述符和方法绑定的东西,解释OP的实际问题是很好的.然而,虽然我不是你的创可贴解决方案的忠实粉丝,但我认为它不值得投票. (2认同)

And*_*ell 10

使用以下提示:

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

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

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!
Run Code Online (Sandbox Code Playgroud)