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

2024-10-01 11:32:23 发布

您现在位置:Python中文网/ 问答频道 /正文

Q:在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美元的现金时,他们的心情就会很好。在

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

^{pr2}$

很酷。请注意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'

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


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


Tags: 方法lambda函数self示例hello参数def
3条回答

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

通过在实例中赋值给HasGoodMood,您并不是在那里放置一个新方法,而是将一个函数放入属性中。您可以读取属性来获取函数,然后调用它,尽管这看起来像是一个方法调用,但它只是调用一个碰巧存储在属性中的函数。不会自动提供self参数。在

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

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

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

Python中的Lambdas只能是一行。如果需要更长的函数,可以使用def。在

^{2}$

有关不那么老套的解决方案,请参见Andrew McDowell's answer。在

使用以下方面的提示:

Is it possible to change an instance's method implementation without changing all other instances of the same class?

通过使用types模块将方法分配给创建的对象而不影响类,可以执行以下操作。您需要这样做,因为函数不会自动接收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!

继承是必由之路。在

它可以简单到:

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

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


class newPersonObject(Person):
    def HasGoodMood(self):
        return self.Cash > 100

>>> greedy = newClassPerson()
>>> greedy.SayHi()
hmpf

当你做^{时,你在做同样的事情。您只覆盖了greedy_jacks属性。用上面提到的方法,你可以创造贪婪的人,快乐的人,永远不快乐的人,嬉皮士等等

在我看来,一个更好的选择是在定义对象时接受cash作为参数。因此,你可以动态地让人们变得贪婪或正常。(未测试)

^{2}$

相关问题 更多 >