len ()과 .__ len __ ()의 차이점은 무엇입니까?


답변:


102

len컬렉션의 길이를 구하는 함수입니다. 개체의 __len__메서드 를 호출하여 작동합니다 . __something__속성은 특별하고 일반적으로 눈에 보이는 것 이상이며 일반적으로 직접 호출해서는 안됩니다.

오래 전 어느 시점에서 무언가의 길이를 얻는 것은 메소드 코드가 아닌 함수 여야하며, 그 len(a)의미는 초보자에게는 분명하지만 a.len()그다지 명확 하지는 않을 것이라고 추론 하기 로 결정되었습니다. 파이썬이 시작되었을 때 __len__존재하지도 않았고 len몇 가지 유형의 객체로 작동하는 특별한 것이 었습니다. 이것이 우리를 떠나는 상황이 타당하든 그렇지 않든간에, 여기에 머물러 있습니다.


66

내장 또는 연산자의 "전형적인"동작은 __whatever__관련된 객체에 대해 적합한 매직 메서드 (예 :와 같은 이름)를 호출하는 (다르고 더 멋진 구문으로) 경우가 많습니다 . 종종 내장 또는 연산자에는 "부가가치"가 있습니다 (관련된 객체에 따라 다른 경로를 취할 수 있음). lenvs 의 경우 __len__에는 내장에서 누락 된 내장에 대한 약간의 온 전성 검사일뿐입니다. 마법의 방법 :

>>> class bah(object):
...   def __len__(self): return "an inch"
... 
>>> bah().__len__()
'an inch'
>>> len(bah())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'str' object cannot be interpreted as an integer

len내장에 대한 호출을 보면 예외가 발생하지 않고 그 후에도 프로그램이 계속되면 호출이 정수, 음이 아닌 2 ** 31 미만을 반환했음을 확신 합니다. 에 대한 호출을 xxx.__len__()보면 확실하지 않습니다 (코드 작성자가 Python에 익숙하지 않거나 좋지 않은 경우를 제외하고는 ;-).

다른 내장 기능은 단순한 온 전성 검사 및 가독성 이상의 부가 가치를 제공합니다. 모든 Python이 내장 호출과 연산자 사용을 통해 작동하도록 일관되게 설계함으로써 프로그래머는 어떤 경우인지 기억해야하는 부담에서 벗어날 수 있습니다. 2.5 때까지 전화를했다 : (때때로 오류가에서 미끄러 져 foo.next()그 이전 버전과의 호환성을 위해 계속 작동하는 동안, 당신은 전화해야, 2.6 - next(foo)과에서 3.*, 마법의 방법이 제대로 이름 __next__대신 "죄송합니다 - 도망"의 next-! ).

따라서 일반적인 규칙은 매직 메서드를 직접 호출하지 않는 것입니다 (하지만 항상 내장을 통해 간접적으로 호출해야 함). 그 이유를 정확히 알지 못하는 경우 (예 : 하위 클래스에서 이러한 메서드를 재정의 할 때) 하위 클래스는 매직 메서드에 대한 명시 적 호출을 통해 수행해야하는 수퍼 클래스를 연기해야합니다.


저는 파이썬 초보 사용자입니다 (초보 프로그래머 생각이 아님). "len 내장에 대한 호출을 볼 때 프로그램이 예외를 발생시키는 것이 아니라 그 후에도 계속되면"에 대해 확신 할 수 없습니다. 나는 이것을 시도했고 두 번 def len(x): return "I am a string." print(len(42)) print(len([1,2,3]))인쇄 I am string되었습니다. 더 설명해 주시겠습니까?
Darek Nędza 2014 년

4
@ DarekNędza 이것은 내장 len에 관한 위와 아무 관련이 없습니다. 방금 len 함수를 정의했습니다. 물론 원하는 것을 반환 할 수 있습니다. OP는 고려중인 객체에 대한 __len__특수 메서드 (함수 아님) 를 호출하는 내장 len에 대해 이야기했습니다 .
Veky

@Veky 어떻게 내가 전화하고 있는지 확인 할 수 있습니다 내장 된 기능이 len없는 같은 이름을 가진 우연히 (내 예처럼) 다른 기능 - len. "내장 함수 len을 재정의하고 있습니다"와 같은 경고는 없습니다. 제 생각에는 Alex가 그의 대답에서 말한 것에 대해 확신 할 수 없습니다.
Darek Nędza 2014

3
알렉스는 명시 적으로 말했다 경우 는 내장을 호출하고, 다음 당신은 ..._ 확신합니다. 그는 당신이 빌트인이라고 부르는 것에 대해 아무 말도하지 않았습니다. 그러나이를 알고 싶다면 다음을 수행 할 수 있습니다 len in vars(__builtins__).values()..
Veky

1
슬프게도, 파이썬에서 객체에 대한 공통 기본 클래스가 없다는 또 다른 예입니다. 구문 적 문맥 전환은 항상 열매를 맺었습니다. 어떤 경우에는 밑줄 방법을 사용하는 것이 일반적인 관용구이고 다른 경우에는 많은 객체에 공통적 인 작업을 수행하는 함수와 같은 것을 사용해야합니다. 많은 객체가 len에 의미 론적 사용이 없기 때문에 이상합니다. 때때로 객체 모델은 같은 더 C ++, 주방 sinky ..입니다
uchuugaka

28

len ()은 대략 다음과 같다고 생각할 수 있습니다.

def len(x):
    return x.__len__()

한 가지 장점은 다음과 같은 내용을 작성할 수 있다는 것입니다.

somelist = [[1], [2, 3], [4, 5, 6]]
map(len, somelist) 

대신에

map(list.__len__, somelist)

또는

map(operator.methodcaller('__len__'), somelist)

하지만 약간 다른 동작이 있습니다. 예를 들어 int의 경우

>>> (1).__len__()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'int' object has no attribute '__len__'
>>> len(1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: object of type 'int' has no len()

2
operator.methodcaller대신 을 의미한다고 가정합니다 operator.attrgetter.
Elazar

5

Pythond 문서 를 확인할 수 있습니다 .

>>> class Meta(type):
...    def __getattribute__(*args):
...       print "Metaclass getattribute invoked"
...       return type.__getattribute__(*args)
...
>>> class C(object):
...     __metaclass__ = Meta
...     def __len__(self):
...         return 10
...     def __getattribute__(*args):
...         print "Class getattribute invoked"
...         return object.__getattribute__(*args)
...
>>> c = C()
>>> c.__len__()                 # Explicit lookup via instance
Class getattribute invoked
10
>>> type(c).__len__(c)          # Explicit lookup via type
Metaclass getattribute invoked
10
>>> len(c)                      # Implicit lookup
10
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.