"self.x = x; self"를 피하려면 어떻게 해야 합니까?y = y; __init_의 self.z = z" 패턴?
다음과 같은 패턴이 보입니다.
def __init__(self, x, y, z):
...
self.x = x
self.y = y
self.z = z
...
상당히 자주, 종종 훨씬 더 많은 매개 변수를 사용합니다.이런 지루한 반복을 피할 수 있는 좋은 방법이 있습니까?가 클스가다상경우에서 ?namedtuple
대신에?
고지 사항:몇몇 사람들이 이 해결책을 제시하는 것에 대해 우려하고 있는 것 같으니, 저는 매우 명확한 면책 사항을 제시하겠습니다.이 솔루션을 사용하면 안 됩니다.저는 정보로만 제공하기 때문에 언어가 이것을 할 수 있다는 것을 알고 있습니다.나머지 답변은 언어 능력을 보여주는 것일 뿐이지 이런 방식으로 사용하는 것을 지지하는 것은 아닙니다.
매개 변수를 속성에 명시적으로 복사하는 것은 아무런 문제가 없습니다.cctor에 매개 변수가 너무 많으면 코드 냄새로 간주되기 때문에 이러한 매개 변수를 더 적은 개체로 그룹화해야 합니다.다른 때는, 그것이 필요하고 그것에 아무런 문제가 없습니다.어쨌든, 그것을 분명히 하는 것이 최선의 방법입니다.
그러나 이를 수행할 수 있는 방법을 묻는 경우(수행해야 하는지 여부가 아니라) 한 가지 해결 방법은 다음과 같습니다.
class A:
def __init__(self, **kwargs):
for key in kwargs:
setattr(self, key, kwargs[key])
a = A(l=1, d=2)
a.l # will return 1
a.d # will return 2
편집: 파이썬 3.7+가 있는 경우 데이터 클래스를 사용하십시오.
서명을 유지하는 데코레이터 솔루션:
import decorator
import inspect
import sys
@decorator.decorator
def simple_init(func, self, *args, **kws):
"""
@simple_init
def __init__(self,a,b,...,z)
dosomething()
behaves like
def __init__(self,a,b,...,z)
self.a = a
self.b = b
...
self.z = z
dosomething()
"""
#init_argumentnames_without_self = ['a','b',...,'z']
if sys.version_info.major == 2:
init_argumentnames_without_self = inspect.getargspec(func).args[1:]
else:
init_argumentnames_without_self = tuple(inspect.signature(func).parameters.keys())[1:]
positional_values = args
keyword_values_in_correct_order = tuple(kws[key] for key in init_argumentnames_without_self if key in kws)
attribute_values = positional_values + keyword_values_in_correct_order
for attribute_name,attribute_value in zip(init_argumentnames_without_self,attribute_values):
setattr(self,attribute_name,attribute_value)
# call the original __init__
func(self, *args, **kws)
class Test():
@simple_init
def __init__(self,a,b,c,d=4):
print(self.a,self.b,self.c,self.d)
#prints 1 3 2 4
t = Test(1,c=2,b=3)
#keeps signature
#prints ['self', 'a', 'b', 'c', 'd']
if sys.version_info.major == 2:
print(inspect.getargspec(Test.__init__).args)
else:
print(inspect.signature(Test.__init__))
다른 사람들이 언급했듯이 반복은 나쁘지 않지만 경우에 따라 명명된 튜플이 이러한 유형의 문제에 매우 적합할 수 있습니다.이렇게 하면 일반적으로 좋지 않은 방법인 로컬() 또는 콰그를 사용할 수 없습니다.
from collections import namedtuple
# declare a new object type with three properties; x y z
# the first arg of namedtuple is a typename
# the second arg is comma-separated or space-separated property names
XYZ = namedtuple("XYZ", "x, y, z")
# create an object of type XYZ. properties are in order
abc = XYZ("one", "two", 3)
print abc.x
print abc.y
print abc.z
제한적으로 사용할 수 있지만 다른 개체와 마찬가지로 명명된 튜플을 상속할 수 있습니다(계속 예)
class MySuperXYZ(XYZ):
""" I add a helper function which returns the original properties """
def properties(self):
return self.x, self.y, self.z
abc2 = MySuperXYZ(4, "five", "six")
print abc2.x
print abc2.y
print abc2.z
print abc2.properties()
명시적인 것이 암시적인 것보다 낫습니다... 그러니 더 간결하게 할 수 있습니다:
def __init__(self,a,b,c):
for k,v in locals().items():
if k != "self":
setattr(self,k,v)
더 나은 질문은: 그래야 하는가입니다.
이름이 붙은 튜플을 원한다면 이름이 붙은 튜플을 사용하는 것을 추천합니다. (튜플은 특정 조건이 붙어있다는 것을 기억하세요) ... 아마도 당신은 주문된 딕트나 그냥 딕트를 원할 것입니다.
에서 gruszczy
저는 다음과같은 했습니다.
class X:
x = None
y = None
z = None
def __init__(self, **kwargs):
for (k, v) in kwargs.items():
if hasattr(self, k):
setattr(self, k, v)
else:
raise TypeError('Unknown keyword argument: {:s}'.format(k))
이 방법은 다음과 같은 이유로 좋습니다.
- 반복을 방지합니다.
- 객체를 구성할 때 오타에 대한 내성이 있음
- 하위 분류와 잘 작동합니다(그냥 할 수 있음).
super().__init(...)
) - 에서가 아닌 클래스 수준(해당 클래스가 속한 위치)에서 속성을 문서화할 수 있습니다.
X.__init__
Python 3.6 이전 버전에서는 특성이 설정된 순서를 제어할 수 없습니다. 일부 특성이 다른 특성에 액세스하는 세터의 속성인 경우 문제가 될 수 있습니다.
아마 조금 더 개선될 수도 있겠지만, 저는 제 코드를 사용하는 유일한 사용자이기 때문에 어떤 형태의 입력 위생도 걱정하지 않습니다.아마도AttributeError
더 적절할 것 같습니다.
다음 작업도 수행할 수 있습니다.
locs = locals()
for arg in inspect.getargspec(self.__init__)[0][1:]:
setattr(self, arg, locs[arg])
물론, 당신은 그것을 수입해야 할 것입니다.inspect
모듈.
이것은 추가 수입이 없는 솔루션입니다.
도우미 기능
작은 도우미 기능을 통해 보다 편리하고 재사용 가능합니다.
def auto_init(local_name_space):
"""Set instance attributes from arguments.
"""
self = local_name_space.pop('self')
for name, value in local_name_space.items():
setattr(self, name, value)
어플
당신은 그것을 부를 필요가 있습니다.locals()
:
class A:
def __init__(self, x, y, z):
auto_init(locals())
시험
a = A(1, 2, 3)
print(a.__dict__)
출력:
{'y': 2, 'z': 3, 'x': 1}
변경하지 않음locals()
만약 당신이 바꾸고 싶지 않다면.locals()
다음 버전 사용:
def auto_init(local_name_space):
"""Set instance attributes from arguments.
"""
for name, value in local_name_space.items():
if name != 'self':
setattr(local_name_space['self'], name, value)
이를 처리하는(그리고 다른 많은 보일러 플레이트를 피하는) 흥미로운 라이브러리는 attrs입니다.예를 들어, 당신의 예는 이것으로 축소될 수 있습니다 (클래스가 호출된다고 가정합니다).MyClass
):
import attr
@attr.s
class MyClass:
x = attr.ib()
y = attr.ib()
z = attr.ib()
당신은 심지어 필요하지도 않습니다.__init__
다른 일을 하지 않는 한 더 이상 방법이 없습니다.여기 글립 레프코위츠의 멋진 소개가 있습니다.
Python 3.7 이상
Python 3.7에서는 Decorator를 사용할 수 있습니다.dataclasses
모듈.설명서에서 다음을 참조하십시오.
이 모듈은 데코레이터 및 다음과 같은 생성된 특수 메서드를 자동으로 추가하는 기능을 제공합니다.
__init__()
그리고.__repr__()
사용자 정의 클래스로 이동합니다.이것은 원래 PEP 557에 설명되어 있습니다.이러한 생성된 방법에 사용할 멤버 변수는 PEP 526 유형 주석을 사용하여 정의됩니다.예를 들어 이 코드는 다음과 같습니다.
@dataclass class InventoryItem: '''Class for keeping track of an item in inventory.''' name: str unit_price: float quantity_on_hand: int = 0 def total_cost(self) -> float: return self.unit_price * self.quantity_on_hand
무엇보다도, a를 추가할 것입니다.
__init__()
다음과 같이 보입니다.def __init__(self, name: str, unit_price: float, quantity_on_hand: int=0): self.name = name self.unit_price = unit_price self.quantity_on_hand = quantity_on_hand
이 메서드는 자동으로 클래스에 추가됩니다. 이 메서드는 인벤토리에 직접 지정되지 않습니다.위에 표시된 항목 정의입니다.
만약 당신의 수업이 크고 복잡하다면, 그것을 사용하는 것은 부적절할 수 있습니다.dataclass
파이썬 3.7.0 출시 당일에 작성하는 글이라 사용 패턴이 아직 잘 정립되지 않았습니다.
0.02달러입니다.이것은 조란 비즐리의 대답에 매우 가깝지만, 더 우아합니다.
def __init__(self, a, b, c, d, e, f):
vars(self).update((k, v) for k, v in locals().items() if v is not self)
추가적으로, 마이크 뮐러의 대답(내 취향에 가장 좋은 대답)은 이 기술로 줄일 수 있습니다.
def auto_init(ns):
self = ns.pop('self')
vars(self).update(ns)
그리고 정당한 결정은auto_init(locals())
당신의__init__
이것은 파이썬에서 일을 하는 자연스러운 방법입니다.더 영리한 것을 발명하려고 하지 마십시오. 팀의 아무도 이해하지 못할 정도로 영리한 코드를 만들 수 있습니다.만약 당신이 팀 플레이어가 되고 싶다면, 그리고 나서 계속 이런 식으로 적으세요.
언급URL : https://stackoverflow.com/questions/35190877/how-do-i-avoid-the-self-x-x-self-y-y-self-z-z-pattern-in-init
'programing' 카테고리의 다른 글
Spring-Boot 다중 모듈 프로젝트 로드 속성 파일 (0) | 2023.07.14 |
---|---|
예약된 Sql 키워드를 사용하여 명명된 테이블 열을 처리하는 방법 (0) | 2023.07.14 |
gitdiff를 사용하여 두 스프레드시트에서 읽을 수 있는 diff를 만들려면 어떻게 해야 합니까? (0) | 2023.07.14 |
sig_atomic_t는 실제로 어떻게 작동합니까? (0) | 2023.07.14 |
Firebase 데이터베이스에서 데이터를 검색하는 방법은 무엇입니까? (0) | 2023.07.14 |