[PYTHON] 파이썬 : 런타임시 메소드와 속성 변경하기
PYTHON파이썬 : 런타임시 메소드와 속성 변경하기
파이썬에서 속성과 메소드를 추가하고 제거 할 수있는 클래스를 만들고 싶습니다. 어떻게 그것을 성취 할 수 있습니까?
왜 그런지 물어 보지 마세요.
해결법
-
==============================
1.
import types class SpecialClass(object): @classmethod def removeVariable(cls, name): return delattr(cls, name) @classmethod def addMethod(cls, func): return setattr(cls, func.__name__, types.MethodType(func, cls)) def hello(self, n): print n instance = SpecialClass() SpecialClass.addMethod(hello) >>> SpecialClass.hello(5) 5 >>> instance.hello(6) 6 >>> SpecialClass.removeVariable("hello") >>> instance.hello(7) Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'SpecialClass' object has no attribute 'hello' >>> SpecialClass.hello(8) Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: type object 'SpecialClass' has no attribute 'hello'
-
==============================
2.이 예제는 클래스에 메소드를 추가하는 것과 인스턴스에 메소드를 추가하는 것의 차이점을 보여줍니다.
이 예제는 클래스에 메소드를 추가하는 것과 인스턴스에 메소드를 추가하는 것의 차이점을 보여줍니다.
>>> class Dog(): ... def __init__(self, name): ... self.name = name ... >>> skip = Dog('Skip') >>> spot = Dog('Spot') >>> def talk(self): ... print 'Hi, my name is ' + self.name ... >>> Dog.talk = talk # add method to class >>> skip.talk() Hi, my name is Skip >>> spot.talk() Hi, my name is Spot >>> del Dog.talk # remove method from class >>> skip.talk() # won't work anymore Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: Dog instance has no attribute 'talk' >>> import types >>> f = types.MethodType(talk, skip, Dog) >>> skip.talk = f # add method to specific instance >>> skip.talk() Hi, my name is Skip >>> spot.talk() # won't work, since we only modified skip Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: Dog instance has no attribute 'talk'
-
==============================
3.types.MethodType을 다음에서 사용할 때 흥미로운 대안 :
types.MethodType을 다음에서 사용할 때 흥미로운 대안 :
>>> f = types.MethodType(talk, puppy, Dog) >>> puppy.talk = f # add method to specific instance
함수가 기술자라는 사실을 악용하는 것입니다 :
>>> puppy.talk = talk.__get__(puppy, Dog)
-
==============================
4.속성 및 메소드를 모든 클래스에 추가 및 제거 할 수 있으며 클래스의 모든 인스턴스에서 속성 및 메소드를 사용할 수 있습니다.
속성 및 메소드를 모든 클래스에 추가 및 제거 할 수 있으며 클래스의 모든 인스턴스에서 속성 및 메소드를 사용할 수 있습니다.
>>> def method1(self): pass >>> def method1(self): print "method1" >>> def method2(self): print "method2" >>> class C(): pass >>> c = C() >>> c.method() Traceback (most recent call last): File "<pyshell#62>", line 1, in <module> c.method() AttributeError: C instance has no attribute 'method' >>> C.method = method1 >>> c.method() method1 >>> C.method = method2 >>> c.method() method2 >>> del C.method >>> c.method() Traceback (most recent call last): File "<pyshell#68>", line 1, in <module> c.method() AttributeError: C instance has no attribute 'method' >>> C.attribute = "foo" >>> c.attribute 'foo' >>> c.attribute = "bar" >>> c.attribute 'bar'
-
==============================
5.원래 클래스 이름에 액세스하거나 __class__를 통해 클래스에 직접 할당 할 수 있습니다.
원래 클래스 이름에 액세스하거나 __class__를 통해 클래스에 직접 할당 할 수 있습니다.
class a : pass ob=a() ob.__class__.blah=lambda self,k: (3, self,k) ob.blah(5) ob2=a() ob2.blah(7)
인쇄 할 것이다.
(3, <__main__.a instance at 0x7f18e3c345f0>, 5) (3, <__main__.a instance at 0x7f18e3c344d0>, 7)
-
==============================
6.또 다른 대안은, 당신이 수업을 대체하는 것이 필요한 경우 class 속성을 수정하는 것입니다 :
또 다른 대안은, 당신이 수업을 대체하는 것이 필요한 경우 class 속성을 수정하는 것입니다 :
>>> class A(object): ... def foo(self): ... print 'A' ... >>> class B(object): ... def foo(self): ... print 'Bar' ... >>> a = A() >>> a.foo() A >>> a.__class__ = B >>> a.foo() Bar
-
==============================
7.간단히:
간단히:
f1 = lambda:0 #method for instances f2 = lambda _:0 #method for class class C: pass #class c1,c2 = C(),C() #instances print dir(c1),dir(c2) #add to the Instances c1.func = f1 c1.any = 1.23 print dir(c1),dir(c2) print c1.func(),c1.any del c1.func,c1.any #add to the Class C.func = f2 C.any = 1.23 print dir(c1),dir(c2) print c1.func(),c1.any print c2.func(),c2.any
결과는 다음과 같습니다.
['__doc__', '__module__'] ['__doc__', '__module__'] ['__doc__', '__module__', 'any', 'func'] ['__doc__', '__module__'] 0 1.23 ['__doc__', '__module__', 'any', 'func'] ['__doc__', '__module__', 'any', 'func'] 0 1.23 0 1.23
-
==============================
8.클래스 자체를 반드시 수정해야합니까? 아니면 단순히 런타임에 특정 지점에서 object.method ()를 대체하는 것이 목표입니까?
클래스 자체를 반드시 수정해야합니까? 아니면 단순히 런타임에 특정 지점에서 object.method ()를 대체하는 것이 목표입니까?
내 기본 상속 개체에 getattribute 및 런타임 데코레이터를 사용하여 내 프레임 워크에서 원숭이 패치 특정 메서드를 호출하도록 클래스를 실제로 수정하는 문제를 회피했기 때문에 묻습니다.
getattribute에서 Base 객체에 의해 검색된 메소드는 데코레이터 / 원숭이 패치 적용을위한 메소드 호출 키워드 인수를 파싱하는 Runtime_Decorator에 래핑됩니다.
따라서 object.method (monkey_patch = "mypatch"), object.method (decorator = "mydecorator") 및 object.method (decorators = my_decorator_list) 구문을 사용할 수 있습니다.
이 방법은 어떤 개별 메소드 호출 (마법 메서드를 사용하지 않음)에서 작동하며, 클래스 / 인스턴스 속성을 실제로 수정하지 않고 임의의 심지어 외래 메소드를 패치 할 수 있으며 Base에서 상속받은 하위 클래스에서 투명하게 작동합니다 (제공 한 경우 물론 getattribute를 재정의).
import trace def monkey_patched(self, *args, **kwargs): print self, "Tried to call a method, but it was monkey patched instead" return "and now for something completely different" class Base(object): def __init__(self): super(Base, self).__init__() def testmethod(self): print "%s test method" % self def __getattribute__(self, attribute): value = super(Base, self).__getattribute__(attribute) if "__" not in attribute and callable(value): value = Runtime_Decorator(value) return value class Runtime_Decorator(object): def __init__(self, function): self.function = function def __call__(self, *args, **kwargs): if kwargs.has_key("monkey_patch"): module_name, patch_name = self._resolve_string(kwargs.pop("monkey_patch")) module = self._get_module(module_name) monkey_patch = getattr(module, patch_name) return monkey_patch(self.function.im_self, *args, **kwargs) if kwargs.has_key('decorator'): decorator_type = str(kwargs['decorator']) module_name, decorator_name = self._resolve_string(decorator_type) decorator = self._get_decorator(decorator_name, module_name) wrapped_function = decorator(self.function) del kwargs['decorator'] return wrapped_function(*args, **kwargs) elif kwargs.has_key('decorators'): decorators = [] for item in kwargs['decorators']: module_name, decorator_name = self._resolve_string(item) decorator = self._get_decorator(decorator_name, module_name) decorators.append(decorator) wrapped_function = self.function for item in reversed(decorators): wrapped_function = item(wrapped_function) del kwargs['decorators'] return wrapped_function(*args, **kwargs) else: return self.function(*args, **kwargs) def _resolve_string(self, string): try: # attempt to split the string into a module and attribute module_name, decorator_name = string.split(".") except ValueError: # there was no ".", it's just a single attribute module_name = "__main__" decorator_name = string finally: return module_name, decorator_name def _get_module(self, module_name): try: # attempt to load the module if it exists already module = modules[module_name] except KeyError: # import it if it doesn't module = __import__(module_name) finally: return module def _get_decorator(self, decorator_name, module_name): module = self._get_module(module_name) try: # attempt to procure the decorator class decorator_wrap = getattr(module, decorator_name) except AttributeError: # decorator not found in module print("failed to locate decorators %s for function %s." %\ (kwargs["decorator"], self.function)) else: return decorator_wrap # instantiate the class with self.function class Tracer(object): def __init__(self, function): self.function = function def __call__(self, *args, **kwargs): tracer = trace.Trace(trace=1) tracer.runfunc(self.function, *args, **kwargs) b = Base() b.testmethod(monkey_patch="monkey_patched") b.testmethod(decorator="Tracer") #b.testmethod(monkey_patch="external_module.my_patch")
이 접근 방식의 단점은 getattribute가 속성에 대한 모든 액세스를 후크하기 때문에 메소드가 아닌 속성의 경우에도 점검 및 잠재적 인 래핑이 발생하여 + 특정 호출에 대해 기능을 활용하지 않을 것입니다. 그리고 getattribute를 사용하는 것은 본질적으로 다소 복잡합니다.
내 경험 / 목적에 대한이 오버 헤드의 실제 영향은 무시할만큼 낮았고, 내 컴퓨터는 듀얼 코어 셀러론을 실행합니다. 이전 구현에서는 객체 초기화시 introspected 메소드를 사용하고 Runtime_Decorator를 메소드에 바인딩했습니다. 그런 식으로 물건을 활용할 필요성을 없애고 이전에 언급 한 오버 헤드를 줄였습니다 ... 그러나 피클을 깨기도하고 (아마도 딜링이 아닐 수도 있습니다)이 방법은 덜 동적입니다.
내가 실제로이 기술로 "야생에서"만난 유일한 유스 케이스는 타이밍 및 데코레이터와 관련이있었습니다. 그러나 그것이 열리는 가능성은 매우 광범위합니다.
다른 기본 클래스에서 상속 할 수없는 기존 클래스가 있거나 자체 클래스 정의 또는 기본 클래스에있는 기술을 활용하면 모든 것이 단순히 불행히도 해당 문제에 적용되지 않습니다.
나는 런타임에 클래스에서 호출 불가능한 속성을 설정 / 제거하는 것이 반드시 어렵다고 생각하지 않습니까? 수정 된 클래스에서 상속받은 클래스가 자동으로 변경 사항을 자동으로 반영하지 못하게하려는 경우가 아니라면 ... '소리를 들으면 전체적으로'할 수 있습니다.
from https://stackoverflow.com/questions/962962/python-changing-methods-and-attributes-at-runtime by cc-by-sa and MIT license
'PYTHON' 카테고리의 다른 글
[PYTHON] NumPy 배열 전치시키기 (0) | 2018.10.06 |
---|---|
[PYTHON] 파이썬에서 OpenSSL AES 암호화 파일을 해독하는 방법은 무엇입니까? (0) | 2018.10.06 |
[PYTHON] 파이썬에서 콘솔 로깅을 비활성화하고 다시 활성화하는 방법은 무엇입니까? (0) | 2018.10.06 |
[PYTHON] 파이썬으로 mp3 메타 데이터에 접근하기 (0) | 2018.10.06 |
[PYTHON] Django : 이미지 URL에서 ImageField에 이미지 추가 (0) | 2018.10.06 |