인수에 대한 python __init__ setattr?
-
07-07-2019 - |
문제
자주 보입니다 __init__
방법은 이것과 유사합니다.
def __init__(self, ivar1, ivar2, ivar3):
self.ivar1 = ivar1
self.ivar2 = ivar2
self.ivar3 = ivar3
인수를 목록으로 바꿀 수있는 곳이 있습니까 (의지하지 않고 *args
또는 **kwargs
) 그런 다음 사용합니다 setattr
매개 변수 이름과 인수가 통과 된 인스턴스 변수를 설정하려면? 그리고 아마도 목록을 자울 수도 있습니다. 예를 들어 적어도 슬라이스해야 할 것입니다. [1:]
당신은 원하지 않기 때문에 self.self
.
(실제로 이름과 가치를 유지하려면 사전이어야 할 것 같아요)
이와 같이:
def __init__(self, ivar1, ivar2, ivar3, optional=False):
for k, v in makedict(self.__class__.__init__.__args__): # made up __args__
setattr(self, k, v)
감사!
미지의 답변에 응답하면서, 나는 이것이 효과가 있음을 알았습니다.
Class A(object):
def __init__(self, length, width, x):
self.__dict__.update(dict([(k, v) for k, v in locals().iteritems() if k != 'self']))
또는
Class A(object):
def __init__(self, length, width, x):
self.__dict__.update(locals())
del self.__dict__['self']
나쁘지 않아..
해결책
당신은 간다. 예, 이것은 못생긴 사악한 해킹입니다. 예 객체에는 __dict__ 변수가 필요합니다. 하지만 이봐, 그 깔끔한 작은 하나의 라이너!
def __init__(self):
self.__dict__.update(locals())
생성자는 모든 유형의 인수를 취할 수 있습니다.
class test(object):
def __init__(self, a, b, foo, bar=5)...
a = test(1,2,3)
dir(a)
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'a', 'b', 'foo', 'bar', 'self']
또한 자아가 포함되지만 쉽게 삭제하거나 자기를 무시하는 자신의 업데이트 기능을 만들 수 있습니다.
다른 팁
expect.getargspec을 사용하여 데코레이터로 캡슐화 할 수 있습니다. 선택 사항 및 키워드 인수 조회는 약간 까다 롭지 만 그렇게해야합니다.
def inits_args(func):
"""Initializes object attributes by the initializer signature"""
argspec = inspect.getargspec(func)
argnames = argspec.args[1:]
defaults = dict(zip(argnames[-len(argspec.defaults):], argspec.defaults))
@functools.wraps(func)
def __init__(self, *args, **kwargs):
args_it = iter(args)
for key in argnames:
if key in kwargs:
value = kwargs[key]
else:
try:
value = args_it.next()
except StopIteration:
value = defaults[key]
setattr(self, key, value)
func(self, *args, **kwargs)
return __init__
그런 다음 다음과 같이 사용할 수 있습니다.
class Foo(object):
@inits_args
def __init__(self, spam, eggs=4, ham=5):
print "Foo(%r, %r, %r)" % (self.spam, self.eggs, self.ham)
기능 서명에 개별적으로 지정된 경우 인수를 목록으로 얻는 좋은 방법은 없습니다. 당신은 아마도 검사 나 프레임 해킹으로 무언가를 할 수 있지만, 당신이했던 것처럼 철자를 철자하는 것보다 추악 할 것입니다.
노력하다 검사 .getArgSpec:
In [31]: inspect.getargspec(C.__init__)
Out[31]: ArgSpec(args=['self', 'ivar1', 'ivar2', 'ivar3', 'optional'],
varargs=None, keywords=None, defaults=(False,))
컬렉션 모듈의 새로운 지명 (Python 2.6의 새로운)이 귀하에게 효과적 일 수 있는지 확인하십시오.
인수의 내성을 사용하여 수행 할 수 있지만 코드는 대체하려는 코드보다 길어집니다. 특히 KW를 처리하는 경우해야합니다.
이 짧은 코드는 대부분의 경우 작동합니다 (미지의 예에서 개선) :
>>> class Foo:
... def __init__(self, labamba, **kw):
... params = locals().copy()
... del params['self']
... if 'kw' in params:
... params.update(params['kw'])
... del params['kw']
... self.__dict__.update(params)
그러나 그것은 추악한 해킹으로, 게으름을 제외하고는 특별한 이유없이 코드를 읽기 쉽게 만들 수 있으므로 그렇게하지 마십시오. 또한 얼마나 자주 당신을합니까? 진짜 5-6 이상의 init 매개 변수가있는 클래스가 있습니까?
나는 그 형태가 너무 길고 너무 길지 않고 복사 가능하고 하위 클래식을 좋아합니다.
class DynamicInitClass(object):
__init_defargs=('x',)
def __init__(self,*args,**attrs):
for idx,val in enumerate(args): attrs[self.__init_defargs[idx]]=val
for key,val in attrs.iteritems(): setattr(self,key,val)
특별 수업에서 파생하는 것은 어떻습니까? 나는 그것이 생각합니다 더 명시적이고 유연합니다 이 방법:
class InitMe:
def __init__(self, data):
if 'self' in data:
data = data.copy()
del data['self']
self.__dict__.update(data)
class MyClassA(InitMe):
def __init__(self, ivar1, ivar2, ivar3 = 'default value'):
super().__init__(locals())
class MyClassB(InitMe):
def __init__(self, foo):
super().__init__({'xxx': foo, 'yyy': foo, 'zzz': None})
# or super().__init__(dict(xxx=foo, yyy=foo, zzz=None))
class MyClassC(InitMe):
def __init__(self, foo, **keywords):
super().__init__(keywords)