복붙노트

[PYTHON] 파이썬 함수에 동적으로 추가

PYTHON

파이썬 함수에 동적으로 추가

이전 또는 이후에 기존 함수에 코드를 추가하려면 어떻게합니까?

예를 들어, 나는 수업을 가지고 :

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

내가 어떻게 그렇게 클래스 위트 metaprogramming 편집합니까

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

이것을 할 수있는 방법이 있습니까?

해결법

  1. ==============================

    1.원하는 경우 데코레이터를 사용하여 함수를 수정할 수 있습니다. 그러나 함수의 초기 정의시 적용된 데코레이터가 아니므로 @ 통사론 설탕을 사용하여 적용 할 수는 없습니다.

    원하는 경우 데코레이터를 사용하여 함수를 수정할 수 있습니다. 그러나 함수의 초기 정의시 적용된 데코레이터가 아니므로 @ 통사론 설탕을 사용하여 적용 할 수는 없습니다.

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

    기존 인스턴스에 대한 메소드도 수정한다는 점에 유의하십시오.

    수정 : args 및 kwargs 사용하여 더 나은 버전으로 데코레이터에 대한 args 목록 수정

  2. ==============================

    2.함수에 함수를 추가하는 일반적인 방법은 데코레이터를 사용하는 것입니다 (wraps 함수 사용).

    함수에 함수를 추가하는 일반적인 방법은 데코레이터를 사용하는 것입니다 (wraps 함수 사용).

    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"
    

    물론, 그것은 정말로 당신이 성취하고자하는 것에 달려 있습니다. 나는 데코레이터를 많이 사용하지만, 내가하고 싶었던 것은 여분의 메시지를 출력하는 것이 었으면 좋겠다.

    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의 모든 인스턴스에서 호출 할 함수를 추가하려면 함수 필드를 인스턴스 필드가 아닌 클래스 필드로 만들어야합니다.

    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. ==============================

    3.위의 정말 좋은 제안이 많이 있지만, 내가 보지 못한 것은 호출이있는 함수를 전달하는 것입니다. 다음과 같이 보일 수 있습니다.

    위의 정말 좋은 제안이 많이 있지만, 내가 보지 못한 것은 호출이있는 함수를 전달하는 것입니다. 다음과 같이 보일 수 있습니다.

    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
    
  4. ==============================

    4.이 대답을 사용하면 래퍼를 만들지 않고 원래 함수를 수정할 수 있습니다. 귀하의 질문에 대답하는 데 유용한 다음 두 가지 원시 파이썬 형식을 발견했습니다 :

    이 대답을 사용하면 래퍼를 만들지 않고 원래 함수를 수정할 수 있습니다. 귀하의 질문에 대답하는 데 유용한 다음 두 가지 원시 파이썬 형식을 발견했습니다 :

    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
    
  5. ==============================

    5.왜 상속을 사용하지 않습니까?

    왜 상속을 사용하지 않습니까?

    class B(A):
        def test(self):
            super(B, self).test()
            print "and here"
    
  6. ==============================

    6.복사하여 붙여 넣기를 즐기십시오 !!!!!

    복사하여 붙여 넣기를 즐기십시오 !!!!!

    #!/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. ==============================

    7.클래스 A가 객체에서 상속받는 경우 다음과 같이 할 수 있습니다.

    클래스 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()
    

    이 코드에는 관심이 없으며 추가 한 새 메소드에서 self를 사용할 수 없습니다. 방금이 코드를 재미있게 보았지만 결코 사용하지 않을 것입니다. 역동적으로 객체 자체를 변경하는 것을 싫어합니다.

    가장 빠르며 이해하기 쉽습니다.

  8. from https://stackoverflow.com/questions/2789460/python-add-to-a-function-dynamically by cc-by-sa and MIT license