Python如何在运行时更改方法的功能

9

想知道在运行时是否可以更改方法的功能,例如

x = obj1 + obj2
return x+y

并且您想要添加

x = obj1 + obj2
x+= obj3
return x+y

http://mywiki.wooledge.org/XyProblem - Ignacio Vazquez-Abrams
1
y是什么?Y是什么?你说的return x=Y是什么意思? - Andrew Jaffe
无论x和y是什么,"return x=y"在Python中都是无效的表达式。 - Ant
抱歉,应该是 x+y。 - user537638
1
如果你想得到有意义的回复,我建议你退一步并解释一下你想要实现什么。 - NPE
显示剩余2条评论
5个回答

21
在Python中,类只是可以在运行时更改的对象。例如:
class Dog:
    def talk(self):
        print "bark"
dog1 = Dog()
dog1.talk()  # --> Bark

def cat_talk(self):
    print "Meow"

Dog.talk = cat_talk
dog1.talk()  # --> Meow

但是你不想做这样的事情,否则谁维护或调试这个程序肯定会想杀了你(而且这个人可能就是你自己)

注意:特殊的“dunder”方法的每个实例的定制不起作用(由于内部Python优化)。解决方法是使特殊方法调用常规方法,然后在常规方法上进行每个实例的定制。有关详细信息,请参见为什么动态添加`__call__`方法到实例不起作用?


2
哈哈哈,我喜欢它。真的很对。 - BaldDude
不一定总是可能的:https://dev59.com/RFMH5IYBdhLWcg3w92Mt - Charlie Parker
@CharlieParker:是的,我知道,这确实令人惊讶。添加了一个关于需要解决特殊方法的每个实例自定义的注意事项。 - 6502

5

一切皆有可能,您可以在运行时进行堆栈操作并插入字节码。参见类似byteplay的工具。

但是为什么??

这种修改方式不直观且难以阅读,最好的方法是一开始就将x += obj3留在那里,并将obj3设置为0; 当您需要该行执行某些操作时,使用obj3上的非零值即可...


刚刚在看byteplay,看起来是一个值得探究的领域。 - user537638
不一定总是可能的:https://dev59.com/RFMH5IYBdhLWcg3w92Mt - Charlie Parker

1
(据我所知) 有一些方法可以实现你想要的,但是方式受到限制...

主要用短语"Monkey Patching"(其他人也提到过)来描述,或者当通常谈论代码操作和/或运行时执行时,通常也用"dynamic/runtime code execution"这个短语来表示[...]

在Python中,您可以按照以下或以下简单的方式进行操作:

currentCode = '''
global x
x = objs[0] + objs[1]
'''

newCode = '''
global x
x = objs[0] + objs[1]
x += objs[2]
x += y
'''

class Ego:
   def doMethod(self, objs=None,y=1):
       exec(currentCode)
       return x

def main():
    I = Ego()
    
    obj1 = 8
    obj2 = 2
    obj3 = 1
    
    print('Before:', I.doMethod([obj1,obj2]))
    global currentCode
    currentCode = newCode #Swiching to new-Code
    print('After :', I.doMethod([obj1,obj2,obj3]))

if __name__ == "__main__":
    main()

输出结果为:

Before: 10
After : 12

⚠️ 免责声明:这不是一条建议(至少不适用于所有情况),这只是一种方法,一个概念证明,因为它确实是有效的(所以请不要因此讨厌我。)


1

程序经常在运行时更改方法的功能,这被称为“泛化”。

你所要做的就是编写一个更通用的算法。这并不难。

def run_time_change( y, *object_list ):
    x=sum( object_list )
    return x+y

example1 = run_time_change(y, obj1, obj2 )
example2 = run_time_change(y, obj1, obj2, obj3 )

没有“运行时”代码更改的地方。这是错误的。

正确的做法是编写更通用的算法。


好的,求和只是一个例子,我想知道如何泛化它! - user537638
@user537638: "求和仅仅是一个例子"。你不能在运行时修改代码。你需要编写更通用的算法。在这种情况下,我编写了一个更通用的算法。在所有情况下(所有),你都需要编写更通用的算法。 - S.Lott
那将是理想的情况,但有时我不知道用户想要改变什么!我的用户(科学家)有时想要更改语句、方法等以适应他们的“思维”- 感谢反馈! - user537638
2
@user537638: "我不知道用户想要改变什么!" 那不是“在运行时”。那是一次对话和设计更改。如果您想要一个允许灵活性的设计,那么您需要为灵活性进行设计。学习面向对象编程和函数式编程,以了解更灵活(和更通用)的设计。 - S.Lott
@user537638 但不要养成为未知的未来编写代码的习惯。解决手头的问题即可。 - progmatico

0

你想做什么并不完全清楚,但是在运行时更改方法和类被称为“ Monkey Patching”, 这在 Python 中不受欢迎(正如名称所示)。

原因是因为这让你的代码极难调试,因为通过阅读代码很难确定调用哪个版本的方法。或者更有可能的是,执行调试的人甚至没有意识到方法已经被更改了,所以他们看到的行为根本无法理解。

因此,虽然可以动态更改方法,但最好不要这样做。如果您提供有关您尝试解决的问题的更多详细信息,其他人将能够建议更“Pythonic”的解决方案。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接