파이썬에서 이전 스타일과 새로운 스타일 클래스의 차이점은 무엇입니까?


답변:


559

에서 새로운 스타일과 클래식 클래스 :

Python 2.1까지, 구식 클래스는 사용자가 사용할 수있는 유일한 특징이었습니다.

(구식) 클래스의 개념은 유형의 개념과 관련이 없습니다 x. 구식 클래스의 인스턴스 인 경우 클래스를 x.__class__ 지정 x하지만 type(x)항상 <type 'instance'>입니다.

이는 클래스와 관계없이 모든 이전 스타일 인스턴스가 인스턴스라는 단일 내장 유형으로 구현된다는 사실을 반영합니다.

새로운 스타일의 클래스가 Python 2.2에 도입되어 class와 type의 개념을 통합했습니다 . 새로운 스타일의 클래스는 단순히 사용자 정의 유형입니다.

x가 새 스타일 클래스의 인스턴스 인 경우 type(x)일반적으로 다음과 동일합니다 x.__class__(이는 보장되지 않지만 새 스타일 클래스 인스턴스는에 대해 반환 된 값을 재정의 할 수 있음 x.__class__).

새로운 스타일의 클래스를 도입하는 주요 동기는 완전한 메타 모델을 가진 통합 객체 모델을 제공하는 것 입니다.

또한 대부분의 내장 유형을 서브 클래 싱하는 기능이나 계산 된 속성을 가능하게하는 "설명자"의 도입과 같은 많은 즉각적인 이점이 있습니다.

호환성 때문에 클래스는 기본적으로 여전히 구식 입니다.

새 스타일 클래스는 다른 새 스타일 클래스 (예 : 유형)를 부모 클래스로 지정하거나 다른 부모가 필요하지 않은 경우 "최상위 유형"개체로 지정하여 만듭니다.

새 스타일 클래스의 동작은 반환되는 유형 외에 여러 가지 중요한 세부 사항에서 이전 스타일 클래스의 동작과 다릅니다.

이러한 변경 중 일부는 특수 메소드가 호출되는 방식과 같이 새 객체 모델의 기본입니다. 다른 것들은 다중 상속의 경우 메소드 해결 순서와 같이 호환성 문제로 이전에 구현할 수 없었던 "수정"입니다.

파이썬 3에는 새로운 스타일의 클래스 만 있습니다 .

서브 클래스의 유무에 관계없이 object클래스는 파이썬 3에서 새로운 스타일입니다.


41
이러한 차이점은 새로운 스타일의 클래스를 사용해야하는 매력적인 이유처럼 들리지 않지만, 항상 새로운 스타일을 사용해야한다고 모든 사람이 말합니다. 오리 타이핑을 사용해야하는 경우을 사용할 필요가 없습니다 type(x). 내장 유형을 서브 클래스 화하지 않으면 새로운 스타일 클래스에서 볼 수있는 이점이없는 것 같습니다. 의 추가 유형 인 단점이 있습니다 (object).
재귀

78
super()구식 수업에서는 작동하지 않는 것과 같은 특정 기능이 있습니다. 이 기사에서 언급했듯이 MRO와 같은 기본적인 수정 사항과 특수한 방법이 있습니다.이를 사용하는 것이 좋습니다.
John Doe

21
@User : 구식 클래스는 2.1에서와 2.7에서 동일하게 작동합니다. 그 이유는 기억에 남는 사람이 거의 없기 때문에 문서에서 더 이상 대부분의 내용을 다루지 않기 때문에 상황이 더 나쁩니다. 위의 문서 인용문은 다음과 같이 직접 말합니다 : 구식 클래스에서는 구현할 수없는 "수정"이 있습니다. 파이썬 2.1 이후로 아무도 다루지 않았고 설명서가 더 이상 설명조차하지 않는 기발한 문제를 겪고 싶지 않다면 구식 클래스를 사용하지 마십시오.
abarnert

10
다음은 2.7에서 구식 클래스를 사용하는 경우 발생할 수있는 기발한 예입니다
KT.

5
궁금한 사람은 누구나 Python 3에서 객체를 명시 적으로 상속해야하는 좋은 이유는 여러 버전의 Python을 더 쉽게 지원할 수 있기 때문입니다.
jpmc26

308

선언 현명한 :

새 스타일 클래스는 object 또는 다른 새 스타일 클래스에서 상속됩니다 .

class NewStyleClass(object):
    pass

class AnotherNewStyleClass(NewStyleClass):
    pass

구식 수업은 그렇지 않습니다.

class OldStyleClass():
    pass

파이썬 3 참고 :

Python 3은 이전 스타일 클래스를 지원하지 않으므로 위에서 언급 한 형식 중 하나가 새로운 스타일 클래스가됩니다.


24
새 스타일 클래스가 다른 새 스타일 클래스에서 상속되면 확장에 의해에서 상속됩니다 object.
aaronasterling

2
이것은 오래된 스타일의 파이썬 클래스의 잘못된 예입니까? class AnotherOldStyleClass: pass
Ankur Agarwal

11
@abc 나는 그렇게 생각 class A: pass하고 class A(): pass엄격하게 동일합니다. 첫 번째는 "A는 부모 클래스를 상속받지 않음" 을 의미하고 두 번째는 "A는 부모 클래스를 상속받지 않음"을 의미 합니다. 즉 아주 비슷 not is하고is not
eyquem

5
참고로, 3.X의 경우 "object"의 상속이 자동으로 가정됩니다 (3.X에서 "object"를 상속 할 방법이 없음을 의미 함). 이전 버전과의 호환성을 위해 "(개체)"를 유지하는 것은 나쁘지 않습니다.
Yo Hsiao

1
상속 된 클래스에 대한 기술을 얻으려면이 대답은 이전 스타일 클래스에서 상속하여 다른 이전 스타일 클래스를 만듭니다. (작성한
대로이

224

이전 스타일 클래스와 새로운 스타일 클래스 사이의 중요한 동작 변경

  • 감독자 추가
  • MRO 변경 (아래에 설명)
  • 서술자 추가
  • 새로운 스타일 클래스 객체는 Exception(아래 예) 에서 파생되지 않으면 올릴 수 없습니다
  • __slots__ 추가

MRO (Method Resolution Order)가 변경되었습니다.

다른 답변에서 언급되었지만 고전 MRO와 C3 MRO (새로운 스타일 클래스에서 사용)의 차이점에 대한 구체적인 예가 있습니다.

문제는 속성 (메소드 및 멤버 변수 포함)이 다중 상속에서 검색되는 순서입니다.

클래식 수업 은 왼쪽에서 오른쪽으로 깊이 우선 검색을 수행합니다. 첫 경기에서 멈춰라. __mro__속성 이 없습니다 .

class C: i = 0
class C1(C): pass
class C2(C): i = 2
class C12(C1, C2): pass
class C21(C2, C1): pass

assert C12().i == 0
assert C21().i == 2

try:
    C12.__mro__
except AttributeError:
    pass
else:
    assert False

새로운 스타일의 수업 MRO는 단일 영어 문장으로 합성하기가 더 복잡합니다. 여기 에 자세히 설명되어 있습니다 . 그 속성 중 하나는 기본 클래스가 모든 파생 클래스가 검색된 후에 만 ​​검색된다는 것입니다. __mro__검색 순서를 표시 하는 속성이 있습니다.

class C(object): i = 0
class C1(C): pass
class C2(C): i = 2
class C12(C1, C2): pass
class C21(C2, C1): pass

assert C12().i == 2
assert C21().i == 2

assert C12.__mro__ == (C12, C1, C2, C, object)
assert C21.__mro__ == (C21, C2, C1, C, object)

새로운 스타일 클래스 객체는 Exception

파이썬 2.5 주변에서 많은 클래스가 생길 수 있었고 파이썬 2.6 주변에서는이 클래스가 제거되었습니다. 파이썬 2.7.3에서 :

# OK, old:
class Old: pass
try:
    raise Old()
except Old:
    pass
else:
    assert False

# TypeError, new not derived from `Exception`.
class New(object): pass
try:
    raise New()
except TypeError:
    pass
else:
    assert False

# OK, derived from `Exception`.
class New(Exception): pass
try:
    raise New()
except New:
    pass
else:
    assert False

# `'str'` is a new style object, so you can't raise it:
try:
    raise 'str'
except TypeError:
    pass
else:
    assert False

8
좋은 요약 감사합니다. "영어로 설명하기 어렵다"라고 말하면 사전 주문 심도 우선 검색을 사용하는 이전 스타일 클래스와는 반대로 주문 후 심도 우선 검색을 설명하는 것 같습니다. (주문은 우리가 첫 자녀보다 먼저 자신을 검색하는 것을 의미하며, 우편 주문은 마지막 자녀 이후에 자신을 검색하는 것을 의미합니다).
Steve Carter

40

이전 스타일 클래스는 여전히 속성 조회 속도가 약간 빠릅니다. 이것은 일반적으로 중요하지 않지만 성능에 민감한 Python 2.x 코드에서 유용 할 수 있습니다.

[3]에서 : 클래스 A :
   ... : 데프 __init __ (자체) :
   ... : self.a = '안녕하세요'
   ... :

[4]에서 : 클래스 B (객체) :
   ... : 데프 __init __ (자체) :
   ... : self.a = '안녕하세요'
   ... :

[6]에서 : aobj = A ()
[7]에서 : bobj = B ()

[8]에서 : % timeit aobj.a
10000000 루프, 루프 당 3 : 78.7ns

[10]에서 : % timeit bobj.a
10000000 루프, 루프 당 3 : 86.9ns

5
실습에서 알게 된 사실에 따르면, 인스턴스 dict에서 속성을 찾은 새로운 스타일의 클래스가 설명인지 여부를 확인하기 위해 추가 조회를 수행해야하기 때문입니다. 반환되는 값을 얻기 위해 호출해야하는 get 메소드. 이전 스타일 클래스는 추가 계산없이 찾은 객체를 간단하게 반환하지만 디스크립터는 지원하지 않습니다. Guido python-history.blogspot.co.uk/2010/06/…에 의해이 훌륭한 게시물에서 더 많은 내용을 읽을 수 있습니다 . 특히 슬롯
xuloChavez

1
CPython 2.7.2에서는 사실이 아닌 것 같습니다 :%timeit aobj.a 10000000 loops, best of 3: 66.1 ns per loop %timeit bobj.a 10000000 loops, best of 3: 53.9 ns per loop
Benedikt Waldvogel at 24:12

1
x86-64 Linux에서 CPython 2.7.2의 aobj는 여전히 더 빠릅니다.
xioxox

41
성능에 민감한 응용 프로그램에 순수한 Python 코드를 사용하는 것은 좋지 않습니다. "빠른 코드가 필요하므로 구식 Python 클래스를 사용하겠습니다." Numpy는 순수한 Python으로 간주되지 않습니다.
Phillip Cloud

IPython 2.7.6에서도 마찬가지입니다. '' ''
477ns

37

귀도는 파이썬의 새로운 스타일과 구식 클래스에 대한 훌륭한 기사 인 New-Style Classes에 대한 The Inside Story를 작성 했습니다.

파이썬 3에는 새로운 스타일의 클래스 만 있습니다. '구식 클래스'를 작성하더라도 묵시적으로 파생됩니다 object.

새로운 스타일 클래스에는 super새로운 C3 mro , 일부 마법적인 방법 등과 같은 구식 클래스에서 부족한 몇 가지 고급 기능이 있습니다 .


24

여기에는 매우 실용적이고 참 / 거짓의 차이가 있습니다. 다음 코드의 두 버전 간의 유일한 차이점은 두 번째 버전에서 Personobject 로부터 상속 한다는 것입니다 . 그 외에 두 버전은 동일하지만 결과가 다릅니다.

  1. 구식 수업

    class Person():
        _names_cache = {}
        def __init__(self,name):
            self.name = name
        def __new__(cls,name):
            return cls._names_cache.setdefault(name,object.__new__(cls,name))
    
    ahmed1 = Person("Ahmed")
    ahmed2 = Person("Ahmed")
    print ahmed1 is ahmed2
    print ahmed1
    print ahmed2
    
    
    >>> False
    <__main__.Person instance at 0xb74acf8c>
    <__main__.Person instance at 0xb74ac6cc>
    >>>
    
  2. 새로운 스타일의 수업

    class Person(object):
        _names_cache = {}
        def __init__(self,name):
            self.name = name
        def __new__(cls,name):
            return cls._names_cache.setdefault(name,object.__new__(cls,name))
    
    ahmed1 = Person("Ahmed")
    ahmed2 = Person("Ahmed")
    print ahmed2 is ahmed1
    print ahmed1
    print ahmed2
    
    >>> True
    <__main__.Person object at 0xb74ac66c>
    <__main__.Person object at 0xb74ac66c>
    >>>

2
'_names_cache'는 무엇을합니까? 당신은 참조를 공유 할 수 있습니까?
Muatik

4
_names_cache는 전달하는 모든 이름을 캐시 (향후 검색을 위해 저장)하는 사전입니다 Person.__new__. 사전에 정의 된 setdefault 메소드는 키와 값의 두 가지 인수를 사용합니다. 키가 dict에 있으면 값을 반환합니다. dict에 없으면 먼저 두 번째 인수로 전달 된 값으로 설정 한 다음 반환합니다.
ychaouche

4
사용법이 잘못되었습니다. 아이디어는 이미 존재하는 경우 새 객체를 생성하는 것이 아니라 사용자의 경우 __new__()항상 호출되며 항상 새로운 객체를 생성 한 다음 던집니다. 이 경우에는 a if보다 바람직합니다 .setdefault().
Amit Upadhyay

그러나 출력의 차이, 즉 이전 스타일 클래스의 두 인스턴스가 다르므로 False가 반환 된 이유를 얻지 못했지만 새 스타일 클래스의 경우 두 인스턴스가 동일합니다. 어떻게 ? 이전 스타일 클래스가 아닌 두 인스턴스를 동일하게 만든 새로운 스타일 클래스의 변경 사항은 무엇입니까?
Pabitra Pati

1
@PabitraPati : 여기는 싸구려 데모입니다. __new__실제로 구식 클래스에는 문제가 아니며 인스턴스 생성에 사용되지 않습니다 (정의처럼 특별한 것처럼 보이는 임의의 이름 일뿐입니다 __spam__). 따라서 구식 클래스를 구성하면을 호출 __init__하는 반면, 새 스타일 구성은 __new__이름을 기준으로 싱글 톤 인스턴스에 통합하여 구성하고 __init__초기화합니다.
ShadowRanger 2016 년

10

새로운 스타일의 클래스 object는 파이썬 2.2부터 (예를 들어 class Classname(object):대신 class Classname:) 상속 받아야합니다 . 핵심 변경 사항은 형식과 클래스를 통합하는 것이며, 이로 인한 부작용은 기본 제공 형식에서 상속 할 수 있다는 것입니다.

자세한 내용은 descrintro 를 읽으십시오 .


8

새로운 스타일의 클래스는 super(Foo, self)어디 Foo에서 클래스이고 self인스턴스입니다.

super(type[, object-or-type])

메서드 호출을 부모 또는 형제 유형의 클래스에 위임하는 프록시 객체를 반환합니다. 클래스에서 재정의 된 상속 된 메서드에 액세스하는 데 유용합니다. 검색 순서는 유형 자체를 건너 뛰는 것을 제외하고 getattr ()에서 사용 된 것과 동일합니다.

그리고 Python 3.x super()에서는 매개 변수없이 클래스 내부에서 간단하게 사용할 수 있습니다 .

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