클래스의 __init__
메소드에 매개 변수가 무엇인지 물어볼 수 있기를 원합니다. 직접적인 접근 방식은 다음과 같습니다.Python에서 함수의 매개 변수 찾기
cls.__init__.__func__.__code__.co_varnames[:code.co_argcount]
그러나 클래스에 데코레이터가있는 경우에는 작동하지 않습니다. 데코레이터에 의해 반환 된 함수에 대한 매개 변수 목록을 제공합니다. 나는 원래의 __init__
메쏘드로 내려가 원래의 매개 변수를 얻고 싶습니다. 실내 장식의 경우, 장식 기능은 장식에 의해 반환 된 함수의 폐쇄에서 찾을 수 것입니다 : 어떤 장식 폐쇄, 다른 일이있는 경우
cls.__init__.__func__.__closure__[0]
, 그것은 더 복잡하다 수시로 할 수 있습니다 :
def Something(test):
def decorator(func):
def newfunc(self):
stuff = test
return func(self)
return newfunc
return decorator
def test():
class Test(object):
@Something(4)
def something(self):
print Test
return Test
test().something.__func__.__closure__
(<cell at 0xb7ce7584: int object at 0x81b208c>, <cell at 0xb7ce7614: function object at 0xb7ce6994>)
그리고 난 원래의 기능에서 매개 변수 또는 데코레이터에서 매개 변수를 원하는지 결정해야합니다. 데코레이터에서 반환하는 함수의 매개 변수는 *args
및 **kwargs
일 수 있습니다. 여러 개의 데코레이터가 있고 어떤 것이 내가 신경 써야하는지 결정해야한다면 어떨까요?
그래서 함수를 장식 할 수있는 경우에도 함수의 매개 변수를 찾을 수있는 가장 좋은 방법은 무엇입니까? 또한 데코레이터의 체인을 내려 장식 된 기능으로 되돌아가는 가장 좋은 방법은 무엇입니까?
업데이트 : 값을 재미없는이 시점 자료 보고서에서
import abc
import collections
IGNORED_PARAMS = ("self",)
DEFAULT_PARAM_MAPPING = {}
DEFAULT_DEFAULT_PARAMS = {}
class DICT_MAPPING_Placeholder(object):
def __get__(self, obj, type):
DICT_MAPPING = {}
for key in type.PARAMS:
DICT_MAPPING[key] = None
for cls in type.mro():
if "__init__" in cls.__dict__:
cls.DICT_MAPPING = DICT_MAPPING
break
return DICT_MAPPING
class PARAM_MAPPING_Placeholder(object):
def __get__(self, obj, type):
for cls in type.mro():
if "__init__" in cls.__dict__:
cls.PARAM_MAPPING = DEFAULT_PARAM_MAPPING
break
return DEFAULT_PARAM_MAPPING
class DEFAULT_PARAMS_Placeholder(object):
def __get__(self, obj, type):
for cls in type.mro():
if "__init__" in cls.__dict__:
cls.DEFAULT_PARAMS = DEFAULT_DEFAULT_PARAMS
break
return DEFAULT_DEFAULT_PARAMS
class PARAMS_Placeholder(object):
def __get__(self, obj, type):
func = type.__init__.__func__
# unwrap decorators here
code = func.__code__
keys = list(code.co_varnames[:code.co_argcount])
for name in IGNORED_PARAMS:
try: keys.remove(name)
except ValueError: pass
for cls in type.mro():
if "__init__" in cls.__dict__:
cls.PARAMS = tuple(keys)
break
return tuple(keys)
class BaseMeta(abc.ABCMeta):
def __init__(self, name, bases, dict):
super(BaseMeta, self).__init__(name, bases, dict)
if "__init__" not in dict:
return
if "PARAMS" not in dict:
self.PARAMS = PARAMS_Placeholder()
if "DEFAULT_PARAMS" not in dict:
self.DEFAULT_PARAMS = DEFAULT_PARAMS_Placeholder()
if "PARAM_MAPPING" not in dict:
self.PARAM_MAPPING = PARAM_MAPPING_Placeholder()
if "DICT_MAPPING" not in dict:
self.DICT_MAPPING = DICT_MAPPING_Placeholder()
class Base(collections.Mapping):
__metaclass__ = BaseMeta
"""
Dict-like class that uses its __init__ params for default keys.
Override PARAMS, DEFAULT_PARAMS, PARAM_MAPPING, and DICT_MAPPING
in the subclass definition to give non-default behavior.
"""
def __init__(self):
pass
def __nonzero__(self):
"""Handle bool casting instead of __len__."""
return True
def __getitem__(self, key):
action = self.DICT_MAPPING[key]
if action is None:
return getattr(self, key)
try:
return action(self)
except AttributeError:
return getattr(self, action)
def __iter__(self):
return iter(self.DICT_MAPPING)
def __len__(self):
return len(self.DICT_MAPPING)
print Base.PARAMS
#()
print dict(Base())
# {}
:
여기내가 지금이 권리를하고있는 중이 야 (이름은 피고인의 신원을 보호하기 위해 변경되었습니다) 얼마나 효과적으로이다 인스턴스의 네 가지 상수 및 사전 버전은 비어 있습니다.
class Sub1(Base):
def __init__(self, one, two):
super(Sub1, self).__init__()
self.one = one
self.two = two
Sub1.PARAMS
# ("one", "two")
dict(Sub1(1,2))
# {"one": 1, "two": 2}
class Sub2(Base):
PARAMS = ("first", "second")
def __init__(self, one, two):
super(Sub2, self).__init__()
self.first = one
self.second = two
Sub2.PARAMS
# ("first", "second")
dict(Sub2(1,2))
# {"first": 1, "second": 2}
도대체 왜 그걸 원할거야? – delnan
이것이 어렵다는 사실은 당신에게 옳은 일이 아니라는 것을 알려 주어야합니다. – katrielalex
클래스의 객체를 dicts로 사용할 수 있고 '__getitem__' 및'__iter__'을 통해 공개되는 키를 명시 적으로 제어 할 수 있기를 원합니다. '__init__'의 매개 변수는 위대한 기본 키를 만듭니다. 그래서 프로그래밍 방식으로 이들을 가져옵니다. 나는 단지 디스크립터가 관련 될 때와 같이 코너 케이스를 처리하려고하고있다. –