2017-04-23 48 views
7

파이썬은 마술 방법으로 많은 일을합니다. 그리고 이들 대부분은 일부 프로토콜의 일부입니다. 나는 "iterator protocol"과 "number protocol"에 익숙하지만 최근에는 "sequence protocol"이라는 용어를 우연히 발견했다. 그러나 일부 연구를 한 후에도 "시퀀스 프로토콜"이 무엇인지 정확히 알지 못합니다.파이썬의 시퀀스 프로토콜이란 무엇입니까?

예를 들어 C API 함수 PySequence_Check은 "개체에"시퀀스 프로토콜 "이 구현되는지 확인합니다 (문서에 따라). source code이는 딕셔너리 아니다 클래스가 있음을 나타냅니다하지만 iter에 대한 설명서도 나와 무엇을 으로 동일한 __getitem__ 방법을 구현

[...] 시퀀스 프로토콜을 지원해야합니다 (__getitem__() 0에서 시작하는 정수 인자)와 방법. [...]

그러나 0로 시작하는 요구 사항은 PySequence_Check에서 "구현"뭔가 아니다.

은 다음 또한 기본적으로 인스턴스가 __reversed__, __contains__, __iter____len__를 구현해야 말한다 collections.abc.Sequence 유형이있다.

그러나이 정의에 따르면 "시퀀스 프로토콜"을 구현하는 클래스는 반드시 시퀀스 일 필요는 없습니다 (예 : "data model"). 시퀀스에는 길이가있는 추상 클래스가 있습니다. 그러나 __getitem__ (PySequence_Check 전달)을 구현하는 클래스는 len(an_instance_of_that_class)을 사용할 때 예외를 throw합니다.

누군가가 시퀀스와 시퀀스 프로토콜 (소스 코드를 읽는 것 외에도 프로토콜에 대한 정의가있는 경우)과 어떤 정의를 사용할 지의 차이점을 명확히 해 주실 수 있습니까?

+0

'collections.abc.Sequence'에는'__getitem__'과'__len__'이 (가) 필요합니다. 그 외 모든 것에 믹스 인 방법이 있습니다. 반복에 대해서'__iter__'없이 '__getitem__' 만 정의되면, 내장 iter는 인덱스 0에서 시작하는 간단한 반복자를 인스턴스화합니다.'reversed'가 작동하려면'__len__'도 정의되어야합니다. 마지막 색인에서 시작할 수 있습니다. – eryksun

+0

@eryksun 그러나 클래스는 ('PySequence_Check'에 관한 한) 시퀀스 프로토콜을 구현하기 위해'__len__'을 필요로하지 않습니다. 그리고'__len__'과'__getitem__'을 구현하지만'collections.abc.Sequence'를 상속받지 않는 클래스는 isinstance (an_instance, Sequence)를 전달하지 않습니다. 그것이 내 질문을 유발 한 것입니다. :) – MSeifert

답변

5

정말 일관성이 없습니다.

여기 PySequence_Check 같습니다

int 
PySequence_Check(PyObject *s) 
{ 
    if (PyDict_Check(s)) 
     return 0; 
    return s != NULL && s->ob_type->tp_as_sequence && 
     s->ob_type->tp_as_sequence->sq_item != NULL; 
} 

PySequence_Check 검사 대상 오브젝트의 종류를 나타내는 PyTypeObject에서 tp_as_sequence 부재를 통해 구현 된 시퀀스 C 프로토콜을 제공하는 경우. 이 tp_as_sequence 구성원은 숫자 인덱스로 항목을 검색하는 경우 sq_item, 항목을 할당 할 때 sq_ass_item과 같이 시퀀스 동작을위한 함수 모음을 포함하는 구조체에 대한 포인터입니다.

특히 PySequence_Check은 인수가 사전이 아니며 sq_item을 제공해야합니다. 파이썬으로 작성된 __getitem__

종류가 너무 dict에서 상속하지 않습니다 파이썬으로 작성된 매핑은 PySequence_Check를 전달합니다, 관계없이 개념적 시퀀스 또는 매핑을하든의 sq_item을 제공 할 것입니다. 한편


, collections.abc.Sequence은 객체 구체적 동급 (또는 수퍼) collections.abc.Sequence 또는 상속 여부를 명시 적으로 collections.abc.Sequence register 혼성 여부를 체크한다.이러한 일을하지 않고 직접 시퀀스를 구현하면 isinstance(your_sequence, Sequence)이 전달되지 않습니다. 또한 collections.abc.Sequence으로 등록 된 대부분의 클래스는 collections.abc.Sequence의 메소드 중 일부를 지원하지 않습니다. 전반적으로 collections.abc.Sequence은 사람들이 일반적으로 기대하는 것보다 훨씬 덜 신뢰할 만합니다. 실제로 시퀀스로 계산 무엇인지에 관해서는


는 보통 0에서 시작하는 정수 인덱스 __len____getitem__을 지원하고 매핑가 아닌 것은입니다. 함수에 대한 문서가 어떤 시퀀스를 취한다고 말하면 거의 모든 것이 필요합니다. 불행히도 "매핑이 아님"은 "시퀀스"가 핀 고정하기 어렵다는 것과 유사한 이유로 테스트하기가 어렵습니다.

+0

하위 클래스가'__getitem__'을 구현할 수 있기 때문에 'PySequence_Check'가'dict'을 제외한다고 생각합니다. 사용자 정의 클래스는'__getitem__'을 구현할 때'True'를 리턴합니다. https://gist.github.com/MSeifert04/ e39d91f9d262618a32f7db14aaab15f4. 답해 주셔서 감사합니다 (특히'collections.abc.Sequence'에는 새로운 __subclasshook__가 없다는 것을 지적 해주었습니다), 다른 누군가가 대답을 제공하기를 원한다면 다른 날을 용인하지 않을 것입니다. . – MSeifert

+1

@MSeifert : 네, 사용자 정의 클래스와'sq_item'에 대해서 틀렸어요. 나는'__getitem__'을 래핑하여'sq_item'을 제공하도록 처리하지 않았다고 맹세 할 수 있었지만 분명히있을 수 있으며 새로운 것이 아닙니다. – user2357112

+1

'issubclass'의 한계를 "one-trick 조랑말"이 아닌 ABC와 관련하여 [issue 23864] (http://bugs.python.org/issue23864)를보십시오. 그것은 항상 나에게만 불필요하게 보였습니다. – eryksun