2017-11-14 8 views
1

필자는 파이썬에서 메타 클래스에 대한 직감을 얻으려고했다. 나는 Python2.7과 Python3.5 둘 다 시도했다. 파이썬 3.5에서는 우리가 명시 적으로 상속했는지 여부에 관계없이 우리가 정의한 모든 클래스가 유형이 <class 'type'> 인 것을 발견했다. 그러나 유형에서 상속받지 않으면 해당 클래스를 다른 클래스의 메타 클래스로 사용할 수 없습니다.명시 적으로 'type'을 상속하여 python3.x에서 메타 클래스 구현하기

>>> class foo: 
    pass 

>>> class Metafoo(type): 
    pass 

>>> foo 
<class '__main__.foo'> 
>>> Metafoo 
<class '__main__.Metafoo'> 
>>> type(foo) 
<class 'type'> 
>>> type(Metafoo) 
<class 'type'> 
>>> 
>>> class foocls1(metaclass=foo): 
    pass 

나는 다음과 같은 오류 얻을 위의 일을 :

Traceback (most recent call last): 
    File "<pyshell#52>", line 1, in <module> 
    class foocls1(metaclass=foo): 
TypeError: object() takes no parameters 

을하지만

>>> class foocls3(metaclass=Metafoo): 
    pass 

>>> foocls3 
<class '__main__.foocls3'> 
>>> type(foocls3) 
<class '__main__.Metafoo'> 

사람이 이유를 설명 할 수있는 새로운 클래스의 메타 클래스로 Metafoo를 사용하는 동안 그런 경우가 아닌를 다른 클래스에서 클래스를 메타 클래스로 사용하려면 명시 적으로 상속해야합니다.

+2

모든 클래스는'type'의 * 인스턴스 *이지만'type'의 모든 하위 클래스 *는 아닙니다. – user2357112

답변

1

"type"은 Python 3 및 Python 2 게시 버전 2.2의 모든 클래스 개체에 대한 기본 클래스입니다. (파이썬 2에서는 파이썬 2에서 "객체"를 명시 적으로 상속받지 않는 클래스를 "이전 스타일 클래스"라고 부르며 이전 버전과의 호환성을 위해 보관했지만 거의 사용하지 않았습니다 .)

따라서 상속은 어떻게됩니까? 클래스의 수퍼 클래스는 무엇이고, "클래스는 객체 자체이기 때문에 클래스의 객체는 무엇입니까?"는 두 가지 다른 "메타 클래스"입니다. 소지품. 상속받은 클래스는 클래스 인스턴스에서 속성 (및 메소드) 조회 순서를 정의하므로 공통적 인 동작이 있습니다.

메타 클래스는 "클래스가 빌드 된 클래스"라기보다는 다른 용도로 사용할 수 있지만 클래스 자체의 구성 단계를 수정하는 데 가장 많이 사용됩니다. 주변을 검색하면 대부분 __new____init__ 개의 메소드를 구현하는 메타 클래스가 표시됩니다. (비록 다른 방법을 사용하는 것이 좋지만, 당신이 무엇을하고 있는지를 알고 있어야합니다.)

정상적인 개체를 만들 필요가없는 몇 가지 작업이 필요합니다. 이 작업은 네이티브 코드 레이어 (CPython의 C)에서 수행되며 클래스의 특수 메서드 슬롯 (예 : __add__, __eq__ 및 이러한 메서드를 구현하는 함수에 대한 포인터)을 채우는 것과 같이 순수 Python 코드에서 재생산되지 않습니다. CPython에서 그렇게하는 유일한 클래스는 "type"입니다. 따라서 클래스를 빌드하는 데 사용하려는 코드 (예 : 메타 클래스)는 언제든지 type.__new__ 메소드를 호출해야합니다. (당신이 파이썬에서 새로운 객체를 만들고자하는 것은 어떤 점에서 코드를 object.__new__으로 부를 것입니다.).

오류가 발생했습니다. type.__new__에 대한 직접 또는 간접 호출을 수행했는지 여부를 Python에서 확인하기 때문에 오류가 발생했습니다. 오류 : "TypeError : object()는 매개 변수를 사용하지 않습니다"는 object에서 동일한 메서드는 매개 변수없이 전달되는 반면에 __new__ 메타 클래스의 메서드는 3 개의 매개 변수 (이름,베이스, 네임 스페이스)를 전달한다는 사실 때문에 간단합니다. (둘 다 자기 자신과 동등한 여분의 "cls"를 얻지 만 이것은 계산되지 않습니다).

일반적인 함수 일지라도 모든 호출 가능 함수를 메타 클래스로 사용할 수 있습니다. 단지 3 개의 명시적인 매개 변수를 취해야 할 것입니다. 이 호출 가능 함수가 반환하는 값은 그 시점의 클래스로 사용되지만 어떤 경우에는 type.__new__ (심지어 간접적으로)을 호출하지 않으면 유효한 클래스가 반환되지 않습니다.

예를 들어, 하나는 사전 선언으로 클래스 몸을 사용할 수 있도록 단지 위해 간단한 방법을 만들 수 있습니다

def dictclass(name, bases, namespace): 
    return namespace 

class mydict(metaclass=dictclass): 
    a = 1 
    b = 2 
    c = 3 

mydict["a"] 

그래서, 모든 것을 하나의 흥미로운 사실은 type가 자신의 메타 클래스입니다. (파이썬 구현에서 하드 코딩 됨). 그러나 type 또한 자체 객체에서 상속

In [21]: type.__class__ 
Out[21]: type 

In [22]: type.__mro__ 
Out[22]: (type, object) 

을 그리고 그냥이 종료 :이 데이터로, 순수 파이썬 코드에서하지 일반적으로 object.__new__를 호출하지 않고 type.__new__와 개체를 호출하지 않고 클래스를 만드는 것입니다 만, C-API 레벨의 구조는 두 가지 동작 모두에 대해 채워 져야합니다. 하나는 함수의 원시 코드 구현을 수행하거나 ctypes로 해킹 할 수 있습니다.

+0

설명 주셔서 감사합니다. –