파이썬 클래스에서 인스턴스 변수를 없음으로 선언하는 것이 좋은 습관입니까?


68

다음 클래스를 고려하십시오.

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

동료들은 다음과 같이 정의하는 경향이 있습니다.

class Person:
    name = None
    age = None

    def __init__(self, name, age):
        self.name = name
        self.age = age

주된 이유는 선택한 편집기가 자동 완성 속성을 표시하기 때문입니다.

개인적으로, 나는 후자가 싫어합니다 None.

어느 것이 더 나은 연습이 될 것이며 어떤 이유로?


62
IDE가 어떤 코드를 작성하도록 지시하지 않습니까?
Martijn Pieters

14
그건 그렇고 : 적절한 파이썬 IDE (예 : PyCharm)를 사용하여 __init__이미 속성을 설정하면 자동 완성 등이 제공됩니다. 또한 NoneIDE를 사용 하면 속성에 대해 더 나은 유형을 유추하는 것을 방지하므로 대신 적절한 기본값을 사용하는 것이 좋습니다 가능한).
Bakuriu

자동 완성을위한 것이라면 유형 힌트를 사용할 수 있으며 추가 docstring도 플러스입니다.
dashesy

3
"당신의 IDE가 어떤 코드를 작성하도록 지시하지 마십시오"는 논쟁의 여지가있는 문제입니다. 파이썬 3.6부터는 인라인 주석과 typing모듈이 있는데, IDE와 린터에 힌트를 제공 할 수 있습니다. 그런 종류의 것들이 당신의 공상을 간질이게한다면 ...
cz

1
수업 레벨에서의 이러한 과제는 나머지 코드에는 영향을 미치지 않습니다. 그들은 영향을 미치지 않습니다 self. 하더라도 self.name또는 self.age할당되지 않은 __init__인스턴스에 표시되지 것입니다 그들은 self, 그들은 단지 클래스에 표시 Person.
jolvi

답변:


70

나는 "이것은 당신이 생각하는 것을하지 않는다"라는 규칙에 따라 후자의 나쁜 관행이라고 부릅니다.

동료의 입장은 다음과 같이 재 작성할 수 있습니다. "접근 할 수 없었지만 다양한 클래스의 네임 스페이스 테이블 ( __dict__) 에서 공간을 차지하는 많은 클래스 정적 준 글로벌 변수 를 만들려고합니다. 어떤 것."


4
docstrings와 비슷하지만 ;-) 물론, 파이썬은 -OO필요한 사람들을 위해 그것들 을 제거하는 편리한 모드를 가지고 있습니다.
Steve Jessop

15
차지하는 공간은이 협약이 악취를 일으키는 가장 중요한 이유입니다. 이름 당 12 바이트 (프로세스 당)입니다. 나는 당신의 대답의 일부를 읽는 데 시간을 낭비한 것처럼 느낍니다 . 그것이 공간 비용이 얼마나 중요하지 않은지입니다.

8
@delnan 나는 항목의 메모리 크기가 무의미하다는 것에 동의합니다. 논리적 인 디버깅 공간을 만들고 더 많은 읽기와 정렬이 필요한 것으로 생각되는 논리 / 멘탈 공간을 더 많이 생각했습니다. I ~ LL
StarWeaver

3
실제로, 만약 당신이 우주에 대한이 편집증이라면, 이것은 공간을 절약하고 시간을 낭비한다는 것을 알 것입니다. 초기화되지 않은 멤버는 클래스 값을 사용하기 때문에 변수 이름의 사본이 없음 (각 인스턴스마다 하나씩)으로 매핑되지 않습니다. 따라서 비용은 클래스에서 몇 바이트이고 절약은 인스턴스 당 몇 바이트입니다. 그러나 각 실패한 변수 이름 검색에는 약간의 시간이 걸립니다.
Jon Jay Obermark

2
8 바이트가 걱정된다면 Python을 사용하지 않을 것입니다.
cz

26

1. 코드를 이해하기 쉽게 만들기

코드는 작성된 것보다 훨씬 자주 읽습니다. 코드 관리자의 작업을보다 쉽게 ​​만듭니다 (내년에도 나름대로있을 수 있습니다).

나는 어려운 규칙을 모르지만 미래의 인스턴스 상태를 명확하게 선언 하는 것을 선호 합니다. 과 충돌하면 AttributeError충분하지 않습니다. 인스턴스 속성의 수명주기를 명확하게 보지 못하는 것이 더 나쁩니다. 할당 된 속성으로 이어지는 가능한 호출 시퀀스를 복원하는 데 필요한 정신 체조의 양은 간단하지 않아 오류가 발생할 수 있습니다.

그래서 나는 보통 생성자의 모든 것을 정의 할뿐만 아니라 변경 가능한 속성의 수를 최소로 유지하려고 노력합니다.

2. 클래스 수준 멤버와 인스턴스 수준 멤버를 혼합하지 마십시오

class선언에서 바로 정의한 것은 클래스에 속하며 클래스의 모든 인스턴스가 공유합니다. 예를 들어 클래스 내부에서 함수를 정의하면 모든 인스턴스에서 동일한 메소드가됩니다. 데이터 멤버에도 동일하게 적용됩니다. 이것은 일반적으로에서 정의한 인스턴스 속성과는 완전히 다릅니다 __init__.

클래스 수준 데이터 멤버는 상수로 가장 유용합니다.

class Missile(object):
  MAX_SPEED = 100  # all missiles accelerate up to this speed
  ACCELERATION = 5  # rate of acceleration per game frame

  def move(self):
    self.speed += self.ACCELERATION
    if self.speed > self.MAX_SPEED:
      self.speed = self.MAX_SPEED
    # ...

2
예, 그러나 클래스 수준과 인스턴스 수준 멤버를 혼합하는 것은 def 가하는 일과 거의 같습니다 . 객체의 속성으로 생각하지만 실제로 클래스의 멤버 인 함수를 만듭니다. 재산 과 그 일에 대해서도 마찬가지입니다 . 수업에서 실제로 중재 될 때 일에 대한 환상을주는 것은 시간이 걸리지 않는 방법입니다. 파이썬 자체가 괜찮다면 어떻게 그렇게 나쁠 수 있습니까?
Jon Jay Obermark 18

글쎄, 파이썬의 메소드 분석 순서 (데이터 멤버에도 적용 가능)는 그리 간단하지 않습니다. 인스턴스 레벨에서 찾을 수없는 것은 클래스 레벨에서 검색된 후 기본 클래스 등에서 검색됩니다. 실제로 동일한 이름의 인스턴스 레벨 멤버를 지정하여 클래스 레벨 멤버 (데이터 또는 메소드)를 섀도 잉 할 수 있습니다. 그러나 인스턴스 수준의 메서드는 인스턴스 에 바인딩 되어 전달 될 self필요가 없지만 self클래스 수준의 메서드는 바인딩되지 않은 상태 에서 일반 함수로서 def인스턴스를 첫 번째 인수로 받아들입니다. 그래서 이것들은 다릅니다.
9000

나는 AttributeError버그가있는 것보다 좋은 신호 라고 생각합니다 . 그렇지 않으면 None을 삼키고 의미없는 결과를 얻습니다. 속성이에 정의되어있는 경우에 특히 중요 __init__하므로 누락 된 속성 (하지만 클래스 수준에 존재)은 버그 상속만으로 발생할 수 있습니다.
Davidmh

@Davidmh : 감지 된 오류는 항상 감지되지 않은 오류보다 낫습니다! 속성을 만들어야 하고 인스턴스 생성 시점 None에서이 값 이 의미가없는 경우 아키텍처에 문제가 있으며 속성 값 또는 초기 값의 수명주기를 다시 생각해야 한다고 말하고 싶습니다 . 속성을 일찍 정의하면 코드를 실행하지 않고 나머지 클래스를 작성하기 전에도 이러한 문제를 감지 할 수 있습니다.
9000

장난! 미사일! 어쨌든 클래스 레벨에 기본값 등이 포함되어 있다면 클래스 레벨 변수를 만들어서 섞어도
괜찮습니다

18

개인적으로 __ init __ () 메소드에서 멤버를 정의합니다. 나는 클래스 부분에서 그것들을 정의하는 것에 대해 생각하지 않았다. 그러나 내가 항상하는 일 : __ init__ 메소드의 모든 멤버를 초기화합니다. 심지어 __ init__ 메소드에 필요하지 않은 멤버도 포함합니다.

예:

class Person:
    def __init__(self, name, age):
        self._name = name
        self._age = age
        self._selected = None

   def setSelected(self, value):
        self._selected = value

한 곳에서 모든 멤버를 정의하는 것이 중요하다고 생각합니다. 코드를 더 읽기 쉽게 만듭니다. __ init __ () 내부인지 외부인지는 중요하지 않습니다. 그러나 팀이 거의 동일한 코딩 스타일을 사용하는 것이 중요합니다.

아, 멤버 변수에 접두사 "_"를 추가 한 것을 알 수 있습니다.


13
생성자에서 모든 값을 설정해야합니다. 클래스 자체에서 값을 설정 한 경우 인스턴스간에 공유되며 None (없음)에는 적합하지만 대부분의 값에는 적합하지 않습니다. 따라서 그것에 대해 아무것도 변경하지 마십시오. ;)
Remco Haszing

4
매개 변수의 기본값과 임의의 위치 및 키워드 인수를 사용하면 예상보다 훨씬 덜 고통 스럽습니다. (그리고 다른 방법으로 건축을 위임 또는 독립형 기능을 실제로 할 수있다, 그래서 당신이 경우 정말 여러 파견이 필요 당신도 그렇게 할 수 있습니다).
Sean Vieira

6
@Benedict Python에는 액세스 제어가 없습니다. 주요한 밑줄은 구현 세부 사항에 대해 승인 된 규칙입니다. PEP 8을 참조하십시오 .
Doval

3
@Doval 속성 이름 앞에 접두사를 붙일 특별한 이유 _가 있습니다. (왜이 스레드의 많은 사람들이 파이썬을 다른 언어와 혼동하거나 반 혼동합니까?)

1
아, 그래서 당신은 모든 노출 된 사람들을위한 그런 속성들 중 하나입니다 ... 오해해서 죄송합니다. 그 스타일은 항상 나에게 과도한 것처럼 보이지만 다음과 같은 특징이 있습니다.
Jon Jay Obermark 14

11

이것은 나쁜 습관입니다. 이러한 값이 필요하지 않고 코드가 복잡해져 오류가 발생할 수 있습니다.

치다:

>>> class WithNone:
...   x = None
...   y = None
...   def __init__(self, x, y):
...     self.x = x
...     self.y = y
... 
>>> class InitOnly:
...   def __init__(self, x, y):
...     self.x = x
...     self.y = y
... 
>>> wn = WithNone(1,2)
>>> wn.x
1
>>> WithNone.x #Note that it returns none, no error
>>> io = InitOnly(1,2)
>>> InitOnly.x
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: class InitOnly has no attribute 'x'

나는 '오류를 일으킨다'고 부르기 힘들다. 여기에 'x'를 요청하면 의미가 모호하지만 가장 초기 값을 원할 수도 있습니다.
Jon Jay Obermark 18

잘못 사용하면 오류가 발생할 수 있다고 설명 했어야합니다.
데니스

더 높은 위험은 여전히 ​​개체를 초기화하는 것입니다. 정말 안전한 것은 없습니다. 그것이 발생할 유일한 오류는 실제로 절름발이 예외를 삼키는 것입니다.
Jon Jay Obermark

1
오류로 인해 더 심각한 문제가 발생하지 않으면 오류가 발생하지 않는 것이 문제입니다.
Erik Aronesty

0

나는 "docstrings와 같은 비트"로 가서 항상None 또는 변하지 않는 좁은 범위의 다른 값 이라면 무해하다고 선언합니다 .

그것은 atavism과 정적 타입 언어에 대한 과도한 애착이있다. 그리고 코드만큼 좋지 않습니다. 그러나 문서에 남아있는 사소한 목적이 있습니다.

예상되는 이름이 무엇인지 문서화하므로 누군가와 코드를 결합하고 우리 중 하나가 'username'과 다른 user_name을 가지고 있다면 인간에게 우리가 길을 나 and 고 동일한 변수를 사용하지 않는다는 단서가 있습니다.

정책으로 전체 초기화를 강요하면보다 파이썬적인 방식으로 동일한 일을 달성 할 수 있지만에 실제 코드가있는 __init__경우 사용중인 변수를 문서화 할 수있는 더 명확한 위치를 제공합니다.

분명히 여기서 큰 문제는 사람들이 아닌 다른 값으로 초기화하도록 유혹한다는 것입니다 None.

class X:
    v = {}
x = X()
x.v[1] = 2

전역 추적을 남기고 x에 대한 인스턴스를 만들지 않습니다.

그러나 이것은 실제 연습보다 파이썬 전체의 단점입니다. 우리는 이미 그것에 대해 편집증이 있어야합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.