다음과 같은 파이썬 클래스가 있습니다.
class Process:
def __init__(self, PID, PPID, cmd, FDs, reachable, user):
뒤에 :
self.PID=PID
self.PPID=PPID
self.cmd=cmd
...
C ++의 초기화 목록과 같이 이러한 인스턴스 변수를 자동 초기화하는 방법이 있습니까? 많은 중복 코드를 절약 할 수 있습니다.
답변
데코레이터를 사용할 수 있습니다.
from functools import wraps
import inspect
def initializer(func):
"""
Automatically assigns the parameters.
>>> class process:
... @initializer
... def __init__(self, cmd, reachable=False, user='root'):
... pass
>>> p = process('halt', True)
>>> p.cmd, p.reachable, p.user
('halt', True, 'root')
"""
names, varargs, keywords, defaults = inspect.getargspec(func)
@wraps(func)
def wrapper(self, *args, **kargs):
for name, arg in list(zip(names[1:], args)) + list(kargs.items()):
setattr(self, name, arg)
for name, default in zip(reversed(names), reversed(defaults)):
if not hasattr(self, name):
setattr(self, name, default)
func(self, *args, **kargs)
return wrapper
그것을 사용하여 __init__
방법 을 장식하십시오 .
class process:
@initializer
def __init__(self, PID, PPID, cmd, FDs, reachable, user):
pass
산출:
>>> c = process(1, 2, 3, 4, 5, 6)
>>> c.PID
1
>>> dir(c)
['FDs', 'PID', 'PPID', '__doc__', '__init__', '__module__', 'cmd', 'reachable', 'user'
답변
Python 2.6 이상을 사용하는 경우 collections.namedtuple 을 사용할 수 있습니다 .
>>> from collections import namedtuple
>>> Process = namedtuple('Process', 'PID PPID cmd')
>>> proc = Process(1, 2, 3)
>>> proc.PID
1
>>> proc.PPID
2
이것은 특히 당신의 수업이 정말로 큰 가치의 가방 일 때 적절합니다.
답변
Python 3.7+의 경우 원하는 작업을 수행하는 매우 비단뱀적이고 유지 관리 가능한 방법 인 Data Class를 사용할 수 있습니다 .
자동으로 초기화되는 인스턴스 변수 인 클래스에 대한 필드 를 정의 할 수 있습니다 .
다음과 같이 보일 것입니다.
@dataclass
class Process:
PID: int
PPID: int
cmd: str
...
__init__
방법은 이미 클래스에있을 것입니다.
여기에 있습니다 힌트를 입력이 필요합니다 내가 사용하는 이유입니다, int
그리고 str
예에서. 필드 유형을 모르는 경우 typing
모듈 에서 Any를 사용할 수 있습니다 .
데이터 클래스는 제안 된 솔루션에 비해 많은 장점이 있습니다.
- 그것은는 명시 적으로 모든 필드는 파이썬의 선을 존중하고 읽기 쉽고 유지 보수하게하는, 볼 수 있습니다. 그것을 사용하는
**kwargs
. - 메서드 를 가질 수 있습니다 . 다른 클래스와 마찬가지로.
- 그것은 방법을
__init__
사용하여 자동으로 넘어갈 수 있습니다__post_init__
.
편집 : NamedTuples 사용을 피하는 이유
일부는 namedtuple
이 경우에 의 사용을 제안 하지만 namedtuple에는 Python 클래스와 다른 동작이 있습니다. 처음에는 분명하지 않으며 잘 알려져 있어야합니다.
1. NamedTuples는 불변입니다.
불변성은 유용 할 수 있지만 인스턴스에 원하는 것이 아닐 수도 있습니다. 당신이 인수를 사용하는 경우 DataClasses도 어떻게 든 불변 수 있습니다 frozen=True
온 @dataclass
장식을.
2. NamedTuples __eq__
는 Tuple처럼 동작합니다.
파이썬에서, SomeNamedTuple(a=1, b=2) == AnotherNamedTuple(c=1, d=2)
입니다 True
! __eq__
비교에 사용되는 NamedTuple 의 함수는 해당 클래스 또는 필드의 이름이 아닌 비교 된 인스턴스에서 해당 값의 값과 위치 만 고려합니다.
답변
Zen of Python 인용 ,
명시적인 것이 암시적인 것보다 낫습니다.
답변
당신이 할 수있는 또 다른 일 :
class X(object):
def __init__(self, a,b,c,d):
vars = locals() # dict of local names
self.__dict__.update(vars) # __dict__ holds and object's attributes
del self.__dict__["self"] # don't need `self`
하지만 내가 추천하는 유일한 해결책은 철자를 쓰는 것 외에 “편집기에서 매크로를 만드는 것”입니다. ;-p
답변
다음과 같이 키워드 인자로 쉽게 할 수 있습니다.
>>> class D:
def __init__(self, **kwargs):
for k, v in kwargs.items():
setattr(self, k, v)
>>> D(test='d').test
'd'
위치 인수에 대한 유사한 구현은 다음과 같습니다.
>> class C:
def __init__(self, *args):
self.t, self.d = args
>>> C('abc', 'def').t
'abc'
>>> C('abc', 'def').d
'def'
나에게 당신의 문제를 해결하지 못하는 것 같습니다.
답변
Nadia의 솔루션이 더 좋고 강력하지만 이것도 흥미 롭다고 생각합니다.
def constructor(*arg_names):
def __init__(self, *args):
for name, val in zip(arg_names, args):
self.__setattr__(name, val)
return __init__
class MyClass(object):
__init__ = constructor("var1", "var2", "var3")
>>> c = MyClass("fish", "cheese", "beans")
>>> c.var2
"cheese"