Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/283.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Python中,如何通过其他对象/函数/方法更改/插入方法的代码_Python_Methods - Fatal编程技术网

在Python中,如何通过其他对象/函数/方法更改/插入方法的代码

在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)

我对python并不陌生,但我远不是一个专家(或中间人)。现在,我在处理对象及其行为(如setattr、monkey patch等)。在这期间,我偶然发现了一个问题,我不知道这是如何工作的

想象一下下面的代码:

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))