python에서 변수 인수(kwargs)에서 클래스 속성을 설정하는 방법
변수 개수의 인수를 사용한 다음 조건부로 클래스 속성으로 설정하는 생성자(또는 다른 함수)가 있는 클래스가 있다고 가정합니다.
수동으로 설정할 수는 있지만, python에서는 변수 매개 변수가 충분히 일반적이어서 이를 위한 공통 관용구가 있어야 하는 것 같습니다.하지만 저는 이것을 어떻게 역동적으로 하는지 잘 모르겠습니다.
저는 eval을 사용한 예가 있지만, 그것은 거의 안전하지 않습니다.저는 이것을 하는 적절한 방법을 알고 싶습니다. 아마도 람다로?
class Foo:
def setAllManually(self, a=None, b=None, c=None):
if a!=None:
self.a = a
if b!=None:
self.b = b
if c!=None:
self.c = c
def setAllWithEval(self, **kwargs):
for key in **kwargs:
if kwargs[param] != None
eval("self." + key + "=" + kwargs[param])
할 수 .__dict__
키워드 인수를 사용한 속성(사전 형식의 인스턴스 속성을 나타냄):
class Bar(object):
def __init__(self, **kwargs):
self.__dict__.update(kwargs)
그러면 다음을 수행할 수 있습니다.
>>> bar = Bar(a=1, b=2)
>>> bar.a
1
그리고 다음과 같은 것으로:
allowed_keys = {'a', 'b', 'c'}
self.__dict__.update((k, v) for k, v in kwargs.items() if k in allowed_keys)
사전에 키를 필터링할 수 있습니다(사용).iteritems
에 items
여전히 Python 2.x를 사용하는 경우).
다음 방법을 사용할 수 있습니다.
class Foo:
def setAllWithKwArgs(self, **kwargs):
for key, value in kwargs.items():
setattr(self, key, value)
속성을 검색하는 유사한 방법이 있습니다.
여기서 대부분의 답변은 허용된 모든 특성을 하나의 기본값으로 초기화하는 좋은 방법을 다루지 않습니다.따라서 @fqxp 및 @mmj가 제공한 답변에 추가하려면 다음과 같이 하십시오.
class Myclass:
def __init__(self, **kwargs):
# all those keys will be initialized as class attributes
allowed_keys = set(['attr1','attr2','attr3'])
# initialize all allowed keys to false
self.__dict__.update((key, False) for key in allowed_keys)
# and update the given keys by their given values
self.__dict__.update((key, value) for key, value in kwargs.items() if key in allowed_keys)
허용된 속성 외에 속성에 대한 기본값을 설정할 수 있는 fqxp의 답변의 변형을 제안합니다.
class Foo():
def __init__(self, **kwargs):
# define default attributes
default_attr = dict(a=0, b=None, c=True)
# define (additional) allowed attributes with no default value
more_allowed_attr = ['d','e','f']
allowed_attr = list(default_attr.keys()) + more_allowed_attr
default_attr.update(kwargs)
self.__dict__.update((k,v) for k,v in default_attr.items() if k in allowed_attr)
3이며, 2의 경우 조정이 합니다. Python 2.x의 경우 적어도 하나의 조정이 필요합니다.iteritems()
신에를 items()
.
매우 늦은 후속 조치
저는 최근에 위의 코드를 클래스 데코레이터로 다시 작성하여 속성의 하드 코딩이 최소화되도록 했습니다.어떤 면에서는 장식가의 일부 기능과 유사하며, 대신 사용할 수도 있습니다.
# class decorator definition
def classattributes(default_attr,more_allowed_attr):
def class_decorator(cls):
def new_init(self,*args,**kwargs):
allowed_attr = list(default_attr.keys()) + more_allowed_attr
default_attr.update(kwargs)
self.__dict__.update((k,v) for k,v in default_attr.items() if k in allowed_attr)
cls.__init__ = new_init
return cls
return class_decorator
# usage:
# 1st arg is a dict of attributes with default values
# 2nd arg is a list of additional allowed attributes which may be instantiated or not
@classattributes( dict(a=0, b=None, c=True) , ['d','e','f'] )
class Foo():
pass # add here class body except __init__
@classattributes( dict(g=0, h=None, j=True) , ['k','m','n'] )
class Bar():
pass # add here class body except __init__
obj1 = Foo(d=999,c=False)
obj2 = Bar(h=-999,k="Hello")
obj1.__dict__ # {'a': 0, 'b': None, 'c': False, 'd': 999}
obj2.__dict__ # {'g': 0, 'h': -999, 'j': True, 'k': 'Hello'}
그러나 mmj와 fqxp의 훌륭한 답변을 기반으로 한 또 다른 변형입니다.우리가 원한다면요?
- 허용된 특성 목록의 하드 코딩 방지
- 생성자의 각 속성에 대한 기본값을 직접 및 명시적으로 설정합니다.
- 다음 중 하나를 사용하여 kwarg를 미리 정의된 특성으로 제한
- 잘못된 인수를 묵묵히 거부하거나, 또는,
- 오류를 제기
인 "직적으라로말는"를 피한다는 입니다.default_attributes
사전.
class Bar(object):
def __init__(self, **kwargs):
# Predefine attributes with default values
self.a = 0
self.b = 0
self.A = True
self.B = True
# get a list of all predefined values directly from __dict__
allowed_keys = list(self.__dict__.keys())
# Update __dict__ but only for keys that have been predefined
# (silently ignore others)
self.__dict__.update((key, value) for key, value in kwargs.items()
if key in allowed_keys)
# To NOT silently ignore rejected keys
rejected_keys = set(kwargs.keys()) - set(allowed_keys)
if rejected_keys:
raise ValueError("Invalid arguments in constructor:{}".format(rejected_keys))
중요한 돌파구는 아니지만 누군가에게 유용할 수도 있습니다
편집: 우리 반이 사용하는 경우@property
는 "세터로 의 생성자와 이러한 수, 는 데레보터는세 "고호된하화로", ▁the▁decor▁wantators▁to▁expand"▁to▁wetiesprotected▁encaps▁mayutes▁with있▁attrib수▁we싶▁with습▁these▁properulate▁set▁get니다을고or는하리▁"장allowed_keys
목된록의 을 사용된 dir(self)
다음과 같이:
allowed_keys = [i for i in dir(self) if "__" not in i and any([j.endswith(i) for j in self.__dict__.keys()])]
위의 코드는 다음을 제외합니다.
- 의 숨겨진
dir()
와 "__"의으로 함) 및 - 어떤 방법을 써서라도
dir()
속성 이름의 끝에서 이름을 찾을 수 없는 경우(보호되거나 그렇지 않은 경우)__dict__.keys()
따라서 @particle 장식된 방법만 유지할 가능성이 높습니다.
이 편집은 Python 3 이상에서만 유효합니다.
솔루션은 다음과 같습니다.vars(self).update(kwargs)
또는self.__dict__.update(**kwargs)
사용자가 오류 메시지 없이 사전을 입력할 수 있기 때문에 강력하지 않습니다.사용자가 다음 서명('a1', 'a2', 'a3', 'a4', 'a5')을 삽입하는지 확인해야 하는 경우 해결책이 작동하지 않습니다.또한 사용자는 "위치 매개변수" 또는 "케이-값 쌍 매개변수"를 전달하여 개체를 사용할 수 있어야 합니다.
그래서 저는 메타클래스를 이용하여 다음과 같은 해결책을 제안합니다.
from inspect import Parameter, Signature
class StructMeta(type):
def __new__(cls, name, bases, dict):
clsobj = super().__new__(cls, name, bases, dict)
sig = cls.make_signature(clsobj._fields)
setattr(clsobj, '__signature__', sig)
return clsobj
def make_signature(names):
return Signature(
Parameter(v, Parameter.POSITIONAL_OR_KEYWORD) for v in names
)
class Structure(metaclass = StructMeta):
_fields = []
def __init__(self, *args, **kwargs):
bond = self.__signature__.bind(*args, **kwargs)
for name, val in bond.arguments.items():
setattr(self, name, val)
if __name__ == 'main':
class A(Structure):
_fields = ['a1', 'a2']
if __name__ == '__main__':
a = A(a1 = 1, a2 = 2)
print(vars(a))
a = A(**{a1: 1, a2: 2})
print(vars(a))
이것은 라스크를 통해 가장 쉽습니다.
class Foo:
def setAllWithKwArgs(self, **kwargs):
for key, value in kwargs.items():
setattr(self, key, value)
예:
class Foo:
def __init__(self, **kwargs):
for key, value in kwargs.items():
setattr(self, key, value)
door = Foo(size='180x70', color='red chestnut', material='oak')
print(door.size) #180x70
제가 주로 하는 일은 다음과 같습니다.
class Foo():
def __init__(self, **kwrgs):
allowed_args = ('a', 'b', 'c')
default_values = {'a':None, 'b':None}
self.__dict__.update(default_values)
if set(kwrgs.keys()).issubset(allowed_args):
self.__dict__.update(kwrgs)
else:
unallowed_args = set(kwrgs.keys()).difference(allowed_args)
raise Exception (f'The following unsupported argument(s) is passed to Foo:\n{unallowed_args}')
대부분의 경우 이 짧은 코드로 충분하다고 생각합니다.
메모
루프에 setattr을 사용하면 특히 이 클래스를 많이 만드는 경우 코드 성능에 부정적인 영향을 미칠 수 있습니다.내 테스트에서, 교체하는 것.__update__
와 함께setattr(self, key, value)
위의 Foo 클래스에 대한 for 루프에서, 클래스를 인스턴스화하는 데 1.4배의 시간이 소요되었습니다.설정할 인수가 더 많은 경우 최악의 상황이 발생합니다.for 루프는 파이썬에서 느리기 때문에 놀랄 일이 아닙니다.
class SymbolDict(object):
def __init__(self, **kwargs):
for key in kwargs:
setattr(self, key, kwargs[key])
x = SymbolDict(foo=1, bar='3')
assert x.foo == 1
는 그 을 나는수업불렀다니습라고 불렀습니다.SymbolDict
기본적으로 문자열 대신 기호를 사용하여 작동하는 사전이기 때문입니다. 다말해서, 은신당을 합니다.x.foo
에 x['foo']
하지만 이불 속에서는 정말 똑같은 일이 벌어지고 있습니다.
다 둘다setattr()
그리고.__dict__.update()
: 무시 : 무시@setter
기능들.이걸 작동시키는 유일한 방법은exec()
.
exec
보안 위험으로 간주되지만 이전 사용자 입력과 함께 사용하지 않기 때문에 왜 그런지 알 수 없습니다.동의하지 않으시면 그 이유를 꼭 알고 싶으니 댓글을 남겨주세요.저는 안전하지 않은 코드를 옹호하거나 저지르고 싶지 않습니다.
제 예는 대부분 완성도를 위해 이전 답변에서 차용한 것이지만, 주요 차이점은 선입니다.exec(f"self.{key} = '{value}'")
class Foo:
def __init__(self, **kwargs):
# Predefine attributes with default values
self.a = 0
self.b = 0
self.name = " "
# get a list of all predefined attributes
allowed_keys = [attr for attr in dir(self) if not attr.startswith("_")]
for key, value in kwargs.items():
# Update properties, but only for keys that have been predefined
# (silently ignore others)
if key in allowed_keys:
exec(f"self.{key} = '{value}'")
@property
def name(self):
return f"{self.firstname} {self.lastname}"
@name.setter
def name(self, name):
self.firstname, self.lastname = name.split(" ", 2)
그들이 더 나은 해결책이 될 수도 있지만, 제가 생각하는 것은 다음과 같습니다.
class Test:
def __init__(self, *args, **kwargs):
self.args=dict(**kwargs)
def getkwargs(self):
print(self.args)
t=Test(a=1, b=2, c="cats")
t.getkwargs()
python Test.py
{'a': 1, 'c': 'cats', 'b': 2}
대부분의 경우 명명된 args(자체 문서화 코드를 더 잘 만들기 위해)를 사용하는 것이 더 나을 수 있다고 생각합니다.
class Foo:
def setAll(a=None, b=None, c=None):
for key, value in (a, b, c):
if (value != None):
settattr(self, key, value)
저는 이 페이지에 미묘하게 다른 질문을 던졌지만, 여기 제가 필요로 하는 대답이 있습니다.
ㅠㅠnamedtuple
클래스(이 답변 참조), 또는@dataclass
장식가(이 문제)
이러한 기능은 특히 이러한 종류의 기능을 염두에 두고 제작되었지만 여기에 있는 다른 답변보다 유연성이 떨어질 수 있습니다.
언급URL : https://stackoverflow.com/questions/8187082/how-can-you-set-class-attributes-from-variable-arguments-kwargs-in-python
'programing' 카테고리의 다른 글
실제 존재하는 파일을 제거할 수 없습니다. fatal: pathspec ...이(가) 일치하지 않습니다. (0) | 2023.06.27 |
---|---|
문자열을 8자리 숫자로 해시하는 방법은 무엇입니까? (0) | 2023.06.27 |
아티팩트 com.oracle:ojdbc6:jar:11.2.0.3 누락 (0) | 2023.06.27 |
MongoDB에서 각 문서의 마지막 업데이트 시간을 검색하는 방법은 무엇입니까? (0) | 2023.06.27 |
iOS에서 카메라 권한 탐지 (0) | 2023.06.27 |