代码之家  ›  专栏  ›  技术社区  ›  Timmy

Python动态添加到函数

  •  16
  • Timmy  · 技术社区  · 16 年前

    如何在函数之前或之后向现有函数添加代码?

    例如,我有一门课:

     class A(object):
         def test(self):
             print "here"
    

    我如何用元编程来编辑类以便我这样做

     class A(object):
         def test(self):
             print "here"
    
             print "and here"
    

    也许是附加另一个函数来测试的方法?

    添加另一个函数,例如

     def test2(self):
          print "and here"
    

    把原来的改成

     class A(object):
         def test(self):
             print "here"
             self.test2()
    

    7 回复  |  直到 16 年前
        1
  •  27
  •   Daniel DiPaolo    16 年前

    如果需要,可以使用装饰器修改函数。但是,由于它不是在函数的初始定义时应用的装饰器,因此您将无法使用 @ 我想用它。

    >>> class A(object):
    ...     def test(self):
    ...         print "orig"
    ...
    >>> first_a = A()
    >>> first_a.test()
    orig
    >>> def decorated_test(fn):
    ...     def new_test(*args, **kwargs):
    ...         fn(*args, **kwargs)
    ...         print "new"
    ...     return new_test
    ...
    >>> A.test = decorated_test(A.test)
    >>> new_a = A()
    >>> new_a.test()
    orig
    new
    >>> first_a.test()
    orig
    new
    

    :将decorator的参数列表修改为 更好的 版本使用 args kwargs

        2
  •  10
  •   Community Mohan Dere    9 年前

    decorator (使用 the wraps function ):

    from functools import wraps
    
    def add_message(func):
        @wraps
        def with_additional_message(*args, **kwargs)
            try:
                return func(*args, **kwargs)
            finally:
                print "and here"
        return with_additional_message
    
    class A:
        @add_message
        def test(self):
            print "here"
    

    当然,这真的取决于你想要完成什么。我经常使用decorators,但如果我只想打印额外的消息,我可能会这样做

    class A:
        def __init__(self):
            self.messages = ["here"]
    
        def test(self):
            for message in self.messages:
                print message
    
    a = A()
    a.test()    # prints "here"
    
    a.messages.append("and here")
    a.test()    # prints "here" then "and here"
    

    这不需要元编程,但是您的示例可能已经大大简化了实际需要执行的操作。也许如果你发布更多关于你的具体需求的细节,我们可以更好地建议什么是Pythonic方法。

    编辑:因为您似乎想调用函数,所以可以使用函数列表而不是消息列表。例如:

    class A:
        def __init__(self):
            self.funcs = []
    
        def test(self):
            print "here"
            for func in self.funcs:
                func()
    
    def test2():
        print "and here"
    
    a = A()
    a.funcs.append(test2)
    a.test()    # prints "here" then "and here"
    

    A ,那么你应该 funcs 类字段而不是实例字段,例如。

    class A:
        funcs = []
        def test(self):
            print "here"
            for func in self.funcs:
                func()
    
    def test2():
        print "and here"
    
    A.funcs.append(test2)
    
    a = A()
    a.test()    # print "here" then "and here"
    
        3
  •  5
  •   D A MaxNoe    5 年前

    types.FunctionType
    

    以及

    types.CodeType
    

    import inspect
    import copy
    import types
    import dill
    import dill.source
    
    
    #Define a function we want to modify:
    def test():
        print "Here"
    
    #Run the function to check output
    print '\n\nRunning Function...'
    test()
    #>>> Here
    
    #Get the source code for the test function:
    testSource = dill.source.getsource(test)
    print '\n\ntestSource:'
    print testSource
    
    
    #Take the inner part of the source code and modify it how we want:
    newtestinnersource = ''
    testSourceLines = testSource.split('\n')
    linenumber = 0 
    for line in testSourceLines:
        if (linenumber > 0):
            if (len(line[4:]) > 0):
                newtestinnersource += line[4:] + '\n'
        linenumber += 1
    newtestinnersource += 'print "Here2"'
    print '\n\nnewtestinnersource'
    print newtestinnersource
    
    
    #Re-assign the function's code to be a compiled version of the `innersource`
    code_obj = compile(newtestinnersource, '<string>', 'exec')
    test.__code__ = copy.deepcopy(code_obj)
    print '\n\nRunning Modified Function...'
    test() #<- NOW HAS MODIFIED SOURCE CODE, AND PERFORMS NEW TASK
    #>>>Here
    #>>>Here2
    

    待办事项: 把这个答案改成 dill.source.getsource

        4
  •  3
  •   Jack M.    16 年前

    上面有很多非常好的建议,但是有一个我没有看到的是在调用中传递函数。可能看起来像这样:

    class A(object):
        def test(self, deep=lambda self: self):
            print "here"
            deep(self)
    def test2(self):
        print "and here"
    

    使用此项:

    >>> a = A()
    >>> a.test()
    here
    >>> a.test(test2)
    here
    and here
    
        5
  •  2
  •   Samir Talwar PruthviRaj Reddy    16 年前

    为什么不使用继承?

    class B(A):
        def test(self):
            super(B, self).test()
            print "and here"
    
        6
  •  1
  •   Delta    15 年前

    复制粘贴,尽情享受!!!!!

    #!/usr/bin/env python 
    
    def say(host, msg): 
       print '%s says %s' % (host.name, msg) 
    
    def funcToMethod(func, clas, method_name=None): 
       setattr(clas, method_name or func.__name__, func) 
    
    class transplant: 
       def __init__(self, method, host, method_name=None): 
          self.host = host 
          self.method = method 
          setattr(host, method_name or method.__name__, self) 
    
       def __call__(self, *args, **kwargs): 
          nargs = [self.host] 
          nargs.extend(args) 
          return apply(self.method, nargs, kwargs) 
    
    class Patient: 
       def __init__(self, name): 
          self.name = name 
    
    if __name__ == '__main__': 
       jimmy = Patient('Jimmy') 
       transplant(say, jimmy, 'say1') 
       funcToMethod(say, jimmy, 'say2') 
    
       jimmy.say1('Hello') 
       jimmy.say2(jimmy, 'Good Bye!') 
    
        7
  •  0
  •   dzen    16 年前

    如果类A继承自对象,则可以执行以下操作:

    def test2():
        print "test"
    
    class A(object):
        def test(self):
            setattr(self, "test2", test2)
            print self.test2
            self.test2()
    
    def main():
        a = A()
        a.test()
    
    if __name__ == '__main__':
        main()
    

    这是最快的方法,更容易理解。