파이썬에서 클래스에 대한 클래스 메서드를 동적으로 만드는 방법
이 질문에 이미 답변이 있습니다.
- 기존 개체 인스턴스에 메서드 추가 16 답변
작은 파이썬 프로그램을 다음과 같이 정의하면
class a():
def _func(self):
return "asdf"
# Not sure what to resplace __init__ with so that a.func will return asdf
def __init__(self, *args, **kwargs):
setattr(self, 'func', classmethod(self._func))
if __name__ == "__main__":
a.func
역 추적 오류가 발생합니다.
Traceback (most recent call last):
File "setattr_static.py", line 9, in <module>
a.func
AttributeError: class a has no attribute 'func'
내가 알아 내려고하는 것은 객체를 인스턴스화하지 않고 클래스 메서드를 클래스에 동적으로 설정하는 방법입니다.
편집하다:
이 문제에 대한 답은
class a():
pass
def func(cls, some_other_argument):
return some_other_argument
setattr(a, 'func', classmethod(func))
if __name__ == "__main__":
print(a.func)
print(a.func("asdf"))
다음 출력을 반환합니다.
<bound method type.func of <class '__main__.a'>>
asdf
클래스 객체에 대한 간단한 할당이나 클래스 객체의 setattr에 의해 클래스에 클래스 메서드를 동적으로 추가 할 수 있습니다. 여기에서는 혼란을 줄이기 위해 클래스가 대문자로 시작하는 파이썬 규칙을 사용하고 있습니다.
# define a class object (your class may be more complicated than this...)
class A(object):
pass
# a class method takes the class object as its first variable
def func(cls):
print 'I am a class method'
# you can just add it to the class if you already know the name you want to use
A.func = classmethod(func)
# or you can auto-generate the name and set it this way
the_name = 'other_func'
setattr(A, the_name, classmethod(func))
여기에 몇 가지 문제가 있습니다.
__init__
인스턴스를 만들 때만 실행됩니다 (예 :obj = a()
. 이것은 당신이 할 때a.func
,setattr()
전화가 발생하지 않았 음을 의미합니다.- 당신은 그냥 사용하는 그래서 그 대신, 직접 그 클래스의 메서드 내에서 클래스의 속성에 액세스 할 수없는
_func
내부의__init__
사용해야합니다 당신self._func
또는self.__class__._func
self
인스턴스에a
속성을 설정하면 클래스가 아닌 해당 인스턴스에 대해서만 사용할 수 있습니다. 그래서 심지어 호출 한 후setattr(self, 'func', self._func)
,a.func
AttributeError를 제기합니다staticmethod
당신이하는 방식을 사용 하면 아무것도staticmethod
하지 않고 결과 함수를 반환하며 인수를 수정하지 않습니다. 따라서 대신 다음과 같은 것을 원할 것입니다setattr(self, 'func', staticmethod(self._func))
(그러나 위의 주석을 고려하면 여전히 작동하지 않습니다)
이제 문제는 실제로 무엇을하려고 하는가입니다. 인스턴스를 초기화 할 때 클래스에 속성을 실제로 추가하려면 다음과 같이 할 수 있습니다.
class a():
def _func(self):
return "asdf"
def __init__(self, *args, **kwargs):
setattr(self.__class__, 'func', staticmethod(self._func))
if __name__ == '__main__':
obj = a()
a.func
a.func()
그러나 이것은 여전히 이상합니다. 이제 a.func
문제없이 액세스 하고 호출 할 수 있지만의 self
인수 a.func
는 항상 가장 최근에 생성 된 a
. 인스턴스 메서드 _func()
를 정적 메서드 나 클래스의 클래스 메서드로 바꾸는 건전한 방법을 정말로 생각할 수 없습니다 .
클래스에 함수를 동적으로 추가하려고하므로 다음과 같은 것이 실제로 수행하려는 작업에 더 가깝습니까?
class a():
pass
def _func():
return "asdf"
a.func = staticmethod(_func) # or setattr(a, 'func', staticmethod(_func))
if __name__ == '__main__':
a.func
a.func()
이런 식으로 할 수 있습니다
class a():
def _func(self):
return "asdf"
setattr(a, 'func', staticmethod(a._func))
if __name__ == "__main__":
a.func()
1. 기본 아이디어 : 메서드를 보유하기 위해 추가 클래스 사용
작업을 수행하는 의미있는 방법을 찾았습니다.
먼저 다음과 같은 BaseClass를 정의합니다.
class MethodPatcher:
@classmethod
def patch(cls, target):
for k in cls.__dict__:
obj = getattr(cls, k)
if not k.startswith('_') and callable(obj):
setattr(target, k, obj)
이제 원래 클래스가 생겼습니다.
class MyClass(object):
def a(self):
print('a')
그런 다음 새 Patcher
클래스 에 추가하려는 새 메서드를 정의합니다 .
( _
이 경우 메서드 이름을로 시작하지 마십시오 )
class MyPatcher(MethodPatcher):
def b(self):
print('b')
그런 다음 전화 :
MyPatcher.patch(MyClass)
따라서 새 메서드 b(self)
가 원본에 추가 되었음을 알 수 있습니다 MyClass
.
obj = MyClass()
obj.a() # which prints an 'a'
obj.b() # which prints a 'b'
2. 구문을 덜 장황하게 만들고 클래스 데코레이터를 사용합니다.
이제 MethodPatcher
데칼 이 있으면 두 가지 작업을 수행해야합니다.
- 추가 할 추가 메서드를 포함 하는 자식 클래스
ChildClass
를 정의ModelPatcher
합니다. - 요구
ChildClass.patch(TargetClass)
그래서 우리는 곧 데코레이터를 사용하여 두 번째 단계를 단순화 할 수 있음을 발견했습니다.
데코레이터를 정의합니다.
def patch_methods(model_class):
def do_patch(cls):
cls.patch(model_class)
return do_patch
그리고 다음과 같이 사용할 수 있습니다.
@patch_methods(MyClass)
class MyClassPatcher(MethodPatcher):
def extra_method_a(self):
print('a', self)
@classmethod
def extra_class_method_b(cls):
print('c', cls)
# !!ATTENTION!! the effect on declaring staticmethod here may not work as expected:
# calling this method on an instance will take the self into the first argument.
# @staticmethod
# def extra_static_method_c():
# print('c')
3. 함께 포장
그래서 우리는 지금의 정의를 넣을 수 있습니다 MethodPatcher
그리고 patch_method
하나의 모듈로를 :
# method_patcher.py
class MethodPatcher:
@classmethod
def patch(cls, target):
for k in cls.__dict__:
obj = getattr(cls, k)
if not k.startswith('_') and callable(obj):
setattr(target, k, obj)
def patch_methods(model_class):
def do_patch(cls):
cls.patch(model_class)
return do_patch
따라서 자유롭게 사용할 수 있습니다.
from method_patcher import ModelPatcher, patch_model
4. 최종 솔루션 : 더 간단한 선언
Soon I found that the MethodPatcher
class is not nessesary, while the @patch_method
decorator can do the work, so FINALLY we only need a patch_method
:
def patch_methods(model_class):
def do_patch(cls):
for k in cls.__dict__:
obj = getattr(cls, k)
if not k.startswith('_') and callable(obj):
setattr(model_class, k, obj)
return do_patch
And the usage becomes:
@patch_methods(MyClass)
class MyClassPatcher:
def extra_method_a(self):
print('a', self)
@classmethod
def extra_class_method_b(cls):
print('c', cls)
# !!ATTENTION!! the effect on declaring staticmethod here may not work as expected:
# calling this method on an instance will take the self into the first argument.
# @staticmethod
# def extra_static_method_c():
# print('c')
You need to setattr(self, 'func', staticmethod(self._func))
You need to initialize class variable=a()
to call __init__
There is no init in static class
I'm using Python 2.7.5, and I wasn't able to get the above solutions working for me. This is what I ended up with:
# define a class object (your class may be more complicated than this...)
class A(object):
pass
def func(self):
print 'I am class {}'.format(self.name)
A.func = func
# using classmethod() here failed with:
# AttributeError: type object '...' has no attribute 'name'
'IT Share you' 카테고리의 다른 글
localStorage가 가득 차면 어떻게됩니까? (0) | 2020.12.12 |
---|---|
파이썬에서 subprocess.check_output ()을 어떻게 사용합니까? (0) | 2020.12.12 |
github에서 폴더 별 readme 파일을 만드는 방법이 있습니까? (0) | 2020.12.12 |
RestTemplate 스레드는 안전합니까? (0) | 2020.12.12 |
iPhone의 Core Data에서 Transformable 속성 유형으로 무엇을 할 수 있습니까? (0) | 2020.12.12 |