programing

Python에서 인스턴스 변수의 기본값을 어떻게 선언해야 합니까?

minimums 2023. 10. 20. 13:32
반응형

Python에서 인스턴스 변수의 기본값을 어떻게 선언해야 합니까?

클래스 구성원에게 다음과 같이 기본값을 부여해야 합니까?

class Foo:
    num = 1

아니면 이렇게?

class Foo:
    def __init__(self):
        self.num = 1

이 질문에서 저는 두 사건 모두에서

bar = Foo()
bar.num += 1

는 잘 정의된 연산입니다.

첫 번째 방법은 클래스 변수가 주어지고 두 번째 방법은 주어지지 않는 것으로 알고 있습니다.그러나 클래스 변수를 필요로 하지 않고 인스턴스 변수의 기본값만 설정하면 되는 경우 두 방법 모두 동일하게 양호합니까?아니면 그들 중 한 명이 다른 한 명보다 더 '피톤적'인가요?

제가 주목한 것은 장고 튜토리얼에서 두 번째 방법을 사용하여 모델을 선언한다는 것입니다.개인적으로 두 번째 방법이 더 우아하다고 생각하지만, '표준' 방법이 무엇인지 알고 싶습니다.

bp의 답변을 확장해서, 나는 그가 의미하는 바를 당신에게 보여주고 싶었습니다.

첫째, 이것은 괜찮습니다.

>>> class TestB():
...     def __init__(self, attr=1):
...         self.attr = attr
...     
>>> a = TestB()
>>> b = TestB()
>>> a.attr = 2
>>> a.attr
2
>>> b.attr
1

그러나 이는 불변(변경 불가) 유형에만 적용됩니다.기본값이 변경 가능한 경우(교체할 수 있음을 의미함), 대신 다음과 같은 일이 발생합니다.

>>> class Test():
...     def __init__(self, attr=[]):
...         self.attr = attr
...     
>>> a = Test()
>>> b = Test()
>>> a.attr.append(1)
>>> a.attr
[1]
>>> b.attr
[1]
>>> 

둘 다 주의하십시오.a그리고.b공유 속성을 가지다이것은 종종 원하지 않습니다.

유형이 변이 가능한 경우 인스턴스 변수의 기본값을 정의하는 Pythonic 방식입니다.

>>> class TestC():
...     def __init__(self, attr=None):
...         if attr is None:
...             attr = []
...         self.attr = attr
...     
>>> a = TestC()
>>> b = TestC()
>>> a.attr.append(1)
>>> a.attr
[1]
>>> b.attr
[]

제 첫 번째 코드 조각이 작동하는 이유는 불변 유형의 경우 파이썬이 원하는 때마다 새로운 인스턴스를 만들기 때문입니다.1을 1에 추가해야 했다면, 이전 1은 변경할 수 없기 때문에 파이썬은 당신을 위해 새로운 2를 만듭니다.그 이유는 대부분 해시태그 때문인 것 같습니다.

두 토막글은 서로 다른 일을 하기 때문에 취향의 문제가 아니라 상황에 맞는 올바른 행동이 무엇인지에 대한 문제입니다.Python 문서에서는 이러한 차이점을 설명하고 있지만, 다음과 같은 몇 가지 예가 있습니다.

전시 A

class Foo:
  def __init__(self):
    self.num = 1

이것은 결속됩니다.numFoo의 사례를 들어보겠습니다.이 필드의 변경 내용은 다른 인스턴스로 전파되지 않습니다.

따라서:

>>> foo1 = Foo()
>>> foo2 = Foo()
>>> foo1.num = 2
>>> foo2.num
1

전시 B

class Bar:
  num = 1

이것은 결속됩니다.num바(Bar) 클래스로.변경사항이 전파됩니다!

>>> bar1 = Bar()
>>> bar2 = Bar()
>>> bar1.num = 2 #this creates an INSTANCE variable that HIDES the propagation
>>> bar2.num
1
>>> Bar.num = 3
>>> bar2.num
3
>>> bar1.num
2
>>> bar1.__class__.num
3

실답

클래스 변수를 필요로 하지 않고 인스턴스 변수의 기본값만 설정하면 되는 경우 두 방법 모두 동일하게 양호합니까?아니면 그들 중 한 명이 다른 한 명보다 더 '피톤적'인가요?

디스플레이 B의 코드는 이에 대해 완전히 잘못된 것입니다. 클래스 속성(인스턴스 생성 시 기본값)을 단일 인스턴스에 바인딩하려는 이유는 무엇입니까?

A 전시장의 코드는 괜찮습니다.

생성자의 인스턴스(instance) 변수에 대해 기본값을 부여하려면 다음과 같이 수행합니다.

class Foo:
  def __init__(self, num = None):
    self.num = num if num is not None else 1

...아니면:

class Foo:
  DEFAULT_NUM = 1
  def __init__(self, num = None):
    self.num = num if num is not None else DEFAULT_NUM

...또는 심지어: (pref 오류가 있지만 불변 유형을 처리하는 경우에만 해당됩니다!)

class Foo:
  def __init__(self, num = 1):
    self.num = num

이렇게 하면 다음을 수행할 수 있습니다.

foo1 = Foo(4)
foo2 = Foo() #use default

클래스 구성원을 사용하여 기본값을 부여하는 것은 불변의 값으로만 주의를 기울이는 한 매우 효과적입니다.만약 당신이 목록이나 구술로 그것을 하려고 한다면 꽤 치명적일 것입니다.또한 인스턴스 특성이 클래스에 대한 참조인 기본값이 없음인 경우에도 작동합니다.

저는 이 기술이 Zope 위에서 실행되는 프레임워크인 repoze에서 매우 성공적으로 사용되는 것을 보았습니다.여기서의 장점은 클래스가 데이터베이스에 지속될 때 기본값이 아닌 속성만 저장하면 되는 것뿐만 아니라 스키마에 새 필드를 추가해야 할 때도 저장된 데이터를 실제로 변경할 필요 없이 모든 기존 개체가 기본값으로 새 필드를 볼 수 있다는 것입니다.

좀 더 일반적인 코딩에서도 잘 작동한다고 생각하지만, 스타일적인 부분입니다.당신이 가장 행복한 것은 무엇이든지 사용하세요.

Python 3.7에 추가된 기능인 데이터 클래스를 사용하면 클래스 인스턴스에서 기본값을 설정할 수 있는 또 다른(아주 편리한) 방법이 있습니다.데코레이터.dataclass생성자와 같은 몇 가지 메서드를 클래스에 자동으로 생성합니다.위에 링크된 문서에서 언급한 바와 같이, "이러한 생성된 방법에서 사용할 멤버 변수는 PEP 526 유형의 주석을 사용하여 정의됩니다."

OP의 예를 고려하면 다음과 같이 구현할 수 있습니다.

from dataclasses import dataclass

@dataclass
class Foo:
    num: int = 0

이 클래스 유형의 개체를 구성할 때 값을 덮어쓸 수도 있습니다.

print('Default val: {}'.format(Foo()))
# Default val: Foo(num=0)
print('Custom val: {}'.format(Foo(num=5)))
# Custom val: Foo(num=5)

인스턴스 변수의 기본값에 클래스 멤버를 사용하는 것은 좋은 생각이 아니며, 이 아이디어가 언급된 것은 처음입니다.예제에서는 효과가 있지만 많은 경우 실패할 수도 있습니다.예를 들어 값이 변경 가능한 경우 수정되지 않은 인스턴스에서 값을 변경하면 기본값이 변경됩니다.

>>> class c:
...     l = []
... 
>>> x = c()
>>> y = c()
>>> x.l
[]
>>> y.l
[]
>>> x.l.append(10)
>>> y.l
[10]
>>> c.l
[10]

클래스 변수를 None으로 선언하여 전파를 방지할 수도 있습니다.이것은 잘 정의된 클래스가 필요하고 AttributeErrors를 방지하려는 경우에 유용합니다.예를 들어,

>>> class TestClass(object):
...     t = None
... 
>>> test = TestClass()
>>> test.t
>>> test2 = TestClass()
>>> test.t = 'test'
>>> test.t
'test'
>>> test2.t
>>>

또한 기본값이 필요한 경우:

>>> class TestClassDefaults(object):
...    t = None
...    def __init__(self, t=None):
...       self.t = t
... 
>>> test = TestClassDefaults()
>>> test.t
>>> test2 = TestClassDefaults([])
>>> test2.t
[]
>>> test.t
>>>

물론 여전히 다른 답변의 정보를 따르며, 가변형 대 불변형을 기본값으로 사용합니다.__init__.

언급URL : https://stackoverflow.com/questions/2681243/how-should-i-declare-default-values-for-instance-variables-in-python

반응형