我知道SO社区是多么激烈,所以我会尽力保留问题minimal, complete and verifiable。
我只想知道是否可以使用猴子补丁替换现有函数的定义?
例如:
class A():
def foo():
print '2'
def foo():
print '5'
A.foo = foo
这种方式似乎也不起作用为什么我不添加新函数而不是替换现有函数,我在其他类中调用这些函数,我理解猴子修补在运行时添加这些函数,我需要我的python代码在Apache spark服务器上运行,该服务器抛出错误,认为对该函数的调用未引用。
所以请你好好帮助我或建议一个解决方案。 谢谢。
编辑:代码的目标是在调用A.foo时打印5。
答案 0 :(得分:2)
我希望我明白你在这里想做什么。这适用于 Python 3 :
class A():
def foo():
print('2')
def foo():
A.foo = lambda: print('5')
A.foo() # Print '2'
foo() # Assign the new method
A.foo() # Prints '5'
在 Python 2 中,但有几点需要注意。
print
不是Python 3中的方法(参见此处:Why doesn't print work in a lambda?)
您无法调用未绑定的邮件(请参阅此处:In Python, can you call an instance method of class A, but pass in an instance of class B?)
所以你必须这样做:
from __future__ import print_function
class A():
def foo():
print('2')
def foo():
A.foo = lambda: print('5')
A.foo.__func__() # Print '2'
foo() # Assign the new method
A.foo.__func__() # Prints '5'
修改强> 在评论中看到你的问题后,我认为你真的想要一些不同的东西。这是:
class A():
def foo(self):
print '2'
def foo(self):
print '5'
a = A()
a.foo() # Print '2'
A.foo = foo # Assign the new method
a.foo() # Prints '5'
这在 Python 2 中运行良好。
self
是对方法绑定的当前实例的引用。当您只调用print
之类的内容来访问附加到该实例的任何属性或方法时,不会使用它。但是对于不同的情况,请看下面的例子:
class A():
msg = "Some message"
def foo(self):
print self.msg
def bar(self):
self.msg = "Some other message"
a = A()
a.foo() # Print old msg
A.bar = bar # Assign the new method
a.bar() # Assigns new message
a.foo() # Prints new message
此外,正如chepner在其帖子中的评论中指出的那样:
自我这个名字并不特别;它只是一个惯例。你可以用 这个如果你真的想要,它不需要是同一个名字 在这里定义的两个函数中。重要的是第一个 用作实例方法的函数的参数将是一个参考 到调用对象。 a.foo()几乎与A.foo(a)
完全相同
答案 1 :(得分:2)
您唯一的问题是您没有正确定义foo
。它需要为调用它的实例采用显式参数。
class A(object):
def __init__(self)
self.x = 2
def foo(self):
print(self.x)
def foo(this):
print(this.x + 3)
A.foo = foo
a = A()
a.foo() # outputs 5 in Python 2 and Python 3
在一个非常真实的意义上,猴子修补是首先创建类的方式。 class
语句几乎只是以下代码的语法糖:
def foo(self):
print(self.x)
A = type('A', (object,), {'foo': foo})
del foo
对type
的定义进行成像并不是一个简单的简化
def type(name, bases, d):
new_class = magic_function_to_make_a_class()
new_class.name = name
new_class.bases = bases
for k, v in d.items():
setattr(new_class, k, v)
return new_class