인스턴스 변수와 Python의 클래스 변수


120

런타임에 인스턴스가 하나만 필요한 Python 클래스가 있으므로 인스턴스가 아닌 클래스 당 한 번만 속성을 갖는 것으로 충분합니다. 둘 이상의 인스턴스가있는 경우 (발생하지 않음) 모든 인스턴스는 동일한 구성을 가져야합니다. 다음 옵션 중 어느 것이 더 낫거나 더 "유용한"Python이 될지 궁금합니다.

클래스 변수 :

class MyController(Controller):

  path = "something/"
  children = [AController, BController]

  def action(self, request):
    pass

인스턴스 변수 :

class MyController(Controller):

  def __init__(self):
    self.path = "something/"
    self.children = [AController, BController]

  def action(self, request):
    pass

4
이 질문을 읽고 답을 본 후 첫 번째 질문 중 하나는 "그래서 클래스 변수에 액세스하려면 어떻게해야합니까?"였습니다. -지금까지는 인스턴스 변수 만 사용했기 때문입니다. 내 질문에 대한 대답으로 클래스 이름 자체를 통해 수행하지만 기술적으로는 인스턴스를 통해서도 수행 할 수 있습니다. 여기에 같은 질문에 다른 사람을 위해 읽을 수있는 링크입니다 : stackoverflow.com/a/3434596/4561887은
가브리엘 스테이 플스

답변:


158

어쨌든 인스턴스가 하나만있는 경우 모든 변수를 인스턴스별로 만드는 것이 가장 좋습니다. 단순히 액세스 (조금) 속도가 빨라지기 때문입니다 (클래스에서 인스턴스로의 "상속"으로 인해 "조회"수준이 하나 적음). 그리고이 작은 이점에 대해 평가할 단점이 없습니다.


7
Borg 패턴에 대해 들어 본 적이 없습니까? 처음에 인스턴스를 하나만 갖는 것은 잘못된 방법이었습니다.
Devin Jeanpierre

434
@Devin, 네, Borg 패턴에 대해 들어 봤습니다 . 2001 년에 도입 한 사람이기 때문입니다 (cfr code.activestate.com/recipes/… ;-). 그러나 단순한 경우에는 시행없이 단일 인스턴스 만 있으면 잘못된 것은 없습니다.
Alex Martelli

2
@ user1767754, 쉽게 직접 만들 수 python -mtimeit있지만 python3.4에서 방금 수행 한 후에는 int클래스 변수에 액세스하는 것이 실제로 이전 워크 스테이션의 인스턴스 변수와 동일한 보다 약 5 ~ 11 나노초 더 빠르다 는 점에 유의합니다. codepath는 그렇게 만듭니다.
Alex Martelli

45

MikeAlex의 충고를 더 반영 하고 나만의 색상을 추가합니다.

인스턴스 속성을 사용하는 것이 일반적입니다 ... 더 관용적 인 Python입니다. 클래스 속성은 사용 사례가 구체적이기 때문에 많이 사용되지 않습니다. 정적 및 클래스 메서드와 "일반"메서드의 경우에도 마찬가지입니다. 그것들은 특정한 사용 사례를 다루는 특별한 구조이고, 그렇지 않으면 파이썬 프로그래밍의 모호한 부분을 알고 있음을 보여주고 싶어하는 비정상적인 프로그래머가 만든 코드입니다.

Alex는 자신의 답변에서 조회 수준이 한 단계 줄어들 기 때문에 액세스가 (조금) 더 빨라질 것이라고 언급했습니다. 아직 이것이 어떻게 작동하는지 모르는 사람들을 위해 더 자세히 설명하겠습니다. 변수 액세스와 매우 유사하며 검색 순서는 다음과 같습니다.

  1. 지역 주민
  2. 비 현지인
  3. 글로벌
  4. 내장

속성 액세스의 경우 순서는 다음과 같습니다.

  1. 수업
  2. MRO에 의해 결정된 기본 클래스 (메소드 확인 순서)

두 기술 모두 "인사이드 아웃 (inside-out)"방식으로 작동합니다. 즉, 대부분의 로컬 객체가 먼저 확인 된 다음 외부 레이어가 연속적으로 확인됩니다.

위의 예에서 path속성을 찾고 있다고 가정 해 보겠습니다 . " self.path" 와 같은 참조를 발견하면 Python은 먼저 인스턴스 속성에서 일치 항목을 찾습니다. 실패하면 개체가 인스턴스화 된 클래스를 확인합니다. 마지막으로 기본 클래스를 검색합니다. Alex가 말했듯이 인스턴스에서 속성이 발견되면 다른 곳을 볼 필요가 없으므로 약간의 시간이 절약됩니다.

그러나 클래스 속성을 고집하는 경우 추가 조회가 필요합니다. 또는 , 다른 대안은, 예를 들어, 클래스 대신 인스턴스를 통해 객체를 참조하는 MyController.path대신 self.path. 이것은 지연된 조회를 우회하는 직접 조회이지만 alex가 아래에서 언급했듯이 전역 변수이므로 저장할 것이라고 생각했던 비트를 잃게됩니다 ([global] 클래스 이름에 대한 로컬 참조를 생성하지 않는 한 ).

결론은 대부분의 경우 인스턴스 속성을 사용해야한다는 것입니다. 그러나 클래스 속성이 작업에 적합한 도구 인 경우가 있습니다. 두 가지를 동시에 사용하는 코드는 가장 많은 노력이 필요합니다 .을 사용하면 동일한 이름의 클래스 속성에 대한 self인스턴스 속성 개체와 섀도우 액세스 만 얻을 수 있기 때문 입니다. 이 경우 속성을 참조하려면 클래스 이름으로 속성 액세스 를 사용해야 합니다.


@wescpy하지만, MyController총 비용이보다 높은 있도록 전역에서 룩업되는 self.pathpath(이후 인스턴스 변수 self로컬 있어서 == 초고속 룩업)이다.
Alex Martelli

아, 사실. 좋은 캐치. 유일한 해결 방법은 로컬 참조를 만드는 것입니다.이 시점에서는 그만한 가치가 없습니다.
wescpy

24

확실하지 않은 경우 인스턴스 속성이 필요할 수 있습니다.

클래스 속성은 의미가있는 특수한 경우에 가장 적합합니다. 매우 일반적인 사용 사례는 방법뿐입니다. 아니다 드문 클래스 인스턴스 (당신은 또한에서 액세스하려면이 유일한 이점은 비록 알 필요가 읽기 전용 상수 속성을 사용하여 외부 클래스),하지만 당신은 확실히 그들에게 어떤 상태를 저장에 대해 신중해야 , 그것은 당신이 원하는 것은 거의 없습니다. 인스턴스가 하나만 있더라도 다른 클래스처럼 클래스를 작성해야합니다. 이는 일반적으로 인스턴스 속성을 사용하는 것을 의미합니다.


1
클래스 변수는 일종의 읽기 전용 상수입니다. 파이썬이 상수를 정의하도록했다면 상수로 작성했을 것입니다.
deamon

1
@deamon, 내 상수를 클래스 정의 외부에 완전히 배치하고 모두 대문자로 이름을 지정할 가능성이 약간 더 높습니다. 수업에 넣는 것도 괜찮습니다. 인스턴스 속성을 만드는 것은 아무것도 해치지 않지만 약간 이상 할 수 있습니다. 나는 이것이 커뮤니티가 옵션 중 하나를 너무 많이 늦추는 문제라고 생각하지 않습니다.
Mike Graham

@MikeGraham FWIW, Google의 Python 스타일 가이드 는 클래스 변수를 선호하는 전역 변수를 피할 것을 제안합니다. 하지만 예외가 있습니다.
Dennis

다음은 Google의 Python 스타일 가이드에 대한 새 링크 입니다. 이제 간단히 작성되었습니다. avoid global variables정의는 전역 변수가 클래스 속성으로 선언 된 변수라는 것입니다. 그러나 Python의 자체 스타일 가이드 ( PEP-8 )는 이런 종류의 질문에 가장 먼저 가야합니다. 그렇다면 자신의 마음이 선택의 도구가되어야합니다 (물론 Google에서 아이디어를 얻을 수도 있습니다).
colidyre

4

Python에서 클래스 변수에 액세스하는 성능에 대한 동일한 질문 -@Edward Loper에서 수정 한 코드

로컬 변수는 가장 빠르게 액세스 할 수 있으며 모듈 변수, 클래스 변수, 인스턴스 변수 순으로 연결됩니다.

다음에서 변수에 액세스 할 수있는 4 가지 범위가 있습니다.

  1. 인스턴스 변수 (self.varname)
  2. 클래스 변수 (Classname.varname)
  3. 모듈 변수 (VARNAME)
  4. 지역 변수 (varname)

시험:

import timeit

setup='''
XGLOBAL= 5
class A:
    xclass = 5
    def __init__(self):
        self.xinstance = 5
    def f1(self):
        xlocal = 5
        x = self.xinstance
    def f2(self):
        xlocal = 5
        x = A.xclass
    def f3(self):
        xlocal = 5
        x = XGLOBAL
    def f4(self):
        xlocal = 5
        x = xlocal
a = A()
'''
print('access via instance variable: %.3f' % timeit.timeit('a.f1()', setup=setup, number=300000000) )
print('access via class variable: %.3f' % timeit.timeit('a.f2()', setup=setup, number=300000000) )
print('access via module variable: %.3f' % timeit.timeit('a.f3()', setup=setup, number=300000000) )
print('access via local variable: %.3f' % timeit.timeit('a.f4()', setup=setup, number=300000000) )

결과:

access via instance variable: 93.456
access via class variable: 82.169
access via module variable: 72.634
access via local variable: 72.199
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.