在Python中,如何通过其他对象/函数/方法更改/插入方法的代码
我对python并不陌生,但我远不是一个专家(或中间人)。现在,我在处理对象及其行为(如setattr、monkey patch等)。在这期间,我偶然发现了一个问题,我不知道这是如何工作的 想象一下下面的代码:在Python中,如何通过其他对象/函数/方法更改/插入方法的代码,python,methods,Python,Methods,我对python并不陌生,但我远不是一个专家(或中间人)。现在,我在处理对象及其行为(如setattr、monkey patch等)。在这期间,我偶然发现了一个问题,我不知道这是如何工作的 想象一下下面的代码: class MyCalculator(): def __init__(self): pass def addition(self, a, b): return a + b def substraction(self, a, b)
class MyCalculator():
def __init__(self):
pass
def addition(self, a, b):
return a + b
def substraction(self, a, b):
return a - b
import inspect
class Changing():
def __init__(self):
pass
def listUserMethods(self, myObject):
object_names = [object_name for object_name in inspect.getmembers(myObject) if (inspect.ismethod(object_name[1]))]
return object_names
def setMethodAttribute(self, myMethod):
pass
if __name__=="__main__":
myCalc = MyCalculator()
change = Changing()
现在,我希望setMethodAttribute()将更改我自己提供的方法的代码。例如,在执行原始方法的其余部分之前插入print()语句。例如,在执行加法之前打印输入参数等。
在我的例子中,这不需要在运行时进行(即使知道这一点非常有趣)。我可以想象,使用继承或类似的东西可能是一种方式。也许有人有个好主意
谢谢你的帮助 答案真的取决于你在追求什么 包装类的方法(运行时之前) 这是装饰器的典型用例(函数定义上方的
@something
)
def带_打印(func):
def包装(*args,**kwargs):
打印(“在调用方法之前”)
ret=func(*args,**kwargs)
打印(“调用方法后”)
回程网
返回包装器
类别MyCalculator:
@印刷
def添加(自身、a、b):
打印(“呼叫添加”)
返回a+b
如果要保留原始方法的docstring,可以使用
示例输出
mycalc=MyCalculator()
打印(mycalc.添加(2,3))
将打印
Before calling method
calling addition
After calling method
5
包装对象实例的方法(运行时)
下面是一个更改对象方法的实现。请注意,这会更改实例的方法,而不是该类的每个实例
类MyCalculator:
def添加(自身、a、b):
打印(“呼叫添加”)
返回a+b
换班:
定义设置方法属性(自身、对象、方法名称):
方法=getattr(对象,方法名称)
def包装(*args,**kwargs):
打印(“在调用方法之前”)
ret=方法(*args,**kwargs)
打印(“调用方法后”)
回程网
setattr(对象、方法名称、包装器)
示例用法
#创建两个用于测试的计算器对象
mycalc=MyCalculator()
mycalc2=MyCalculator()
change=Changing()
#变动前
打印(mycalc.添加(2,3))
打印(“---”)
#变动后
更改.设置方法属性(mycalc,“添加”)
打印(mycalc.添加(2,3))
打印(“---”)
#另一个计算器对象保持不变
打印(mycalc2.添加(2,3))
将打印
calling addition
5
----
Before calling method
calling addition
After calling method
5
----
calling addition
5
我以一种新的方式重新创建了一些代码。你介意看一下,告诉我这是不是一种“好”的方式吗 基本思想是,每个继承“InBetween”的类都可以通过super()向每个方法添加包装器。而不是在脚本中手动执行此操作。我的下一个想法是,通过记录等方式替换打印语句。最后,如果我调用父项“init”,信息将很容易被记录下来,否则,“什么也不会发生” 我很想听听其他的意见
谢谢大家! 你希望它如何工作?类似于
change.setMethodAttribute(myCalc.addition)
?是否要在Changing.setMethodAttribute
中编写“打印”的代码?谢谢!这很有道理。很久以前,我看了一些教程(来自Corey Schafer)。完全忘记了装饰师背后的想法。我利用了你的输入,得到了不同的东西和星座,正如我所期望的那样。我可能还没有完全理解,但它正在变得越来越近。
import inspect
class InBetween():
def __init__(self):
object_names = [object_name for object_name in inspect.getmembers(self) if (inspect.ismethod(object_name[1]) and (object_name[0] != 'with_print'))]
for name in object_names:
method = getattr(self, name[0])
wrapper = self.with_print(method)
setattr(self, name[0], wrapper)
def with_print(self, method):
def wrapper(*args, **kwargs):
print("before")
ret = method(*args, **kwargs)
print("after")
return ret
return wrapper
class MyCalculator(InBetween):
def __init__(self):
super().__init__()
def addition(self, a, b):
return a + b
def substraction(self, a, b):
return a - b
def multiply(self, a, b):
return a * b
if __name__=="__main__":
myCalc = MyCalculator()
print(myCalc.addition(2,5))
print(myCalc.multiply(2,5))