왜 파이썬 코드가 길이 메소드 대신 len () 함수를 사용합니까?


204

파이썬에는 len()문자열의 크기를 결정하는 데 사용되는 함수 가 있다는 것을 알고 있지만 왜 문자열 객체의 메소드가 아닌지 궁금합니다.

최신 정보

좋아, 나는 내가 당혹스럽게 착각했다는 것을 깨달았다. __len__()실제로는 문자열 객체의 메서드입니다. 문자열 객체에서 len 함수를 사용하여 파이썬에서 객체 지향 코드를 보는 것이 이상하게 보입니다. 또한 __len__len 대신 이름 으로 보는 것도 이상합니다 .

답변:


180

문자열에는 길이 방법이 있습니다. __len__()

파이썬에서의 프로토콜은 길이와 사용 목적에이 방법을 구현하는 것입니다 내장 len()당신이 구현하는 방법과 유사 당신을 위해 그것을 호출 기능, __iter__()그리고 사용하는 내장 iter()기능 (또는 뒤에라는 방법을 반복 가능한 객체에 대한 장면).

자세한 내용은 컨테이너 유형 에뮬레이션 을 참조하십시오.

다음은 파이썬에서 프로토콜의 주제에 대해 잘 읽은 것입니다 : 파이썬과 최소한의 놀라움의 원리


124
사용 이유가 얼마나 모 론적인지는 놀랍습니다 len. 그들은 사람들이 강제로 구현하는 .__len__것보다 사람들이 강제로 구현하는 것이 더 쉽다고 생각합니다 .len(). 그것은 똑같으며, 훨씬 깨끗해 보입니다 . 만약 언어가 OOP를 가지게된다면, __len__세상에서 무엇을해야 하는가len(..)
대안

38
len, str 등은 메쏘드를 호출하기 위해 함수 나 람다를 정의 할 필요없이 map, reduce 및 filter와 같은 고차 함수와 함께 사용할 수 있습니다. 파이썬에서도 모든 것이 OOP를 중심으로하는 것은 아닙니다.
Evicatos

11
또한 프로토콜을 사용하여 구현하는 다른 방법을 제공 할 수 있습니다. 예를 들어, 당신은으로 반복 가능한 만들 수 있습니다 __iter__, 또는에서만을 __getitem__하고, iter(x)어느 쪽이든 작동합니다. 당신은 함께 사용할 수 -에 - 부울 컨텍스트 개체를 만들 수 있습니다 __bool__또는 __len__, 그리고 bool(x)어느 쪽이든 작동합니다. 등등. Armin은 링크 된 게시물에서 이것을 합리적으로 잘 설명하고 있다고 생각합니다. 그러나 비록 그렇지 않더라도, 핵심 개발자와 공개적으로 대립하는 사람에 의해 외부 설명으로 인해 Python moronic을 호출한다고해서 정확히 공평하지 않을 것입니다…
abarnert

8
@Evicatos : "OOP의 주위에있는 모든 것을의 공전"에 대한 +1,하지만 난 "로 끝나는 것 , 특히 파이썬에서"이 아니라 . Python (Java, Ruby 또는 Smalltalk와 달리)은 "순수한 OOP"언어가되지 않습니다. "다중 패러다임"언어가되도록 명시 적으로 설계되었습니다. 리스트 이해는 반복 가능한 방법이 아닙니다. 메소드가 zip아닌 최상위 함수 zip_with입니다. 등등. 모든 것이 객체이기 때문에 객체라는 것이 각 것에서 가장 중요한 것을 의미하지는 않습니다.
abarnert

7
그 기사는 너무 나쁘게 쓰여져 서 읽은 후에 혼란스럽고 화를냅니다. "Python 2.x에서 예를 들어 Tuple 유형은 특수하지 않은 메소드를 노출하지 않지만이를 사용하여 문자열을 만들 수 있습니다."모든 것은 거의 해독 할 수없는 문장의 결합입니다.
MirroredFate

93

이 질문에 대한 Jim의 답변 도움 될 수 있습니다. 여기에 복사합니다. Quoing Guido van Rossum :

우선, HCI 이유로 x.len () 대신 len (x)를 선택했습니다 (def __len __ ()이 훨씬 늦음). 실제로 HCI에는 두 가지 이유가 있습니다.

(a) 일부 연산의 경우 접두사 표기법은 접두사보다 더 잘 읽습니다. 접두사 (및 접두사!) 연산은 수학에서 시각이 수학자가 문제에 대해 생각하는 데 도움이되는 표기법을 좋아하는 오랜 전통을 가지고 있습니다. x * (a + b)와 같은 공식을 x a + x 로 쉽게 재 작성하는 것과 비교 b로 원시 OO 표기법을 사용하여 같은 일을하는 어색함을 비교하십시오.

(b) len (x)라는 코드를 읽을 때 무언가 길이를 요구한다는 것을 알고 있습니다. 이것은 두 가지를 말해줍니다. 결과는 정수이고 인수는 일종의 컨테이너입니다. 반대로 x.len ()을 읽을 때 x는 인터페이스를 구현하거나 표준 len ()이있는 클래스에서 상속되는 일종의 컨테이너라는 것을 이미 알고 있어야합니다. 맵핑을 구현하지 않는 클래스에 get () 또는 keys () 메소드가 있거나 파일이 아닌 클래스에 write () 메소드가있는 경우 때때로 혼란을 목격하십시오.

다른 방법으로 같은 것을 말하면 'len'이 내장 된 작업으로 간주됩니다. 나는 그것을 잃는 것을 싫어한다. /… /


37

이있다 len 방법은 :

>>> a = 'a string of some length'
>>> a.__len__()
23
>>> a.__len__
<method-wrapper '__len__' of str object at 0x02005650>

34

파이썬은 실용적인 프로그래밍 언어이며, 그 이유 len()기능이 아닌 방법 인 str, list,dict 등 는 실용적입니다.

len()내장 기능 상품의 직접와 내장 유형 :의 CPython의 구현 len()실제로는의 값 반환 ob_size필드 PyVarObjectC 구조체 나타내고있는 가변 크기의 내장 메모리에 객체입니다. 이것은 메서드를 호출하는 것보다 훨씬 빠릅니다. 속성 조회가 필요하지 않습니다. 컬렉션의 항목 수를 얻기 일반적인 작업입니다 및 기본 및 다양한 유형으로 효율적으로 일해야한다 str, list,array.array

그러나 일관성을 높이기 위해 len(o)사용자 정의 형식에 적용 할 때 Python o.__len__()은 폴백으로 호출 합니다. __len__, __abs__에 설명 된 모든 다른 특별한 방법 파이썬 데이터 모델은 쉽게 그 내장 기능처럼 작동, 우리가 "파이썬"이라고 부르는 표현과 매우 일관된 API를 가능 객체를 생성 할 수 있습니다.

특수 메소드를 구현하면 객체가 반복을 지원하고, 삽입 연산자를 오버로드하고, with블록 에서 컨텍스트를 관리 할 수 있습니다. Python 모델 자체를 생성 한 객체를 완벽하게 통합 할 수있는 프레임 워크로 사용하는 방법으로 데이터 모델을 생각할 수 있습니다.

같은 귀도 반 로섬 (Guido van Rossum)에서 따옴표가 지원하는 두 번째 이유는, 이 하나 , 읽기 및 쓰기 쉽다 것입니다 len(s)보다 s.len().

이 표기법 len(s)은 다음과 같이 접두사 표기법이있는 단항 연산자와 일치 abs(n)합니다. len()보다 자주 abs()사용되며 작성하기 쉬워야합니다.

역사적인 이유가있을 수도 있습니다. 파이썬에 앞서 ABC 언어에 (그리고 디자인에 매우 영향력이있는), 단항 연산자가 #s의미하는 대로 작성되었습니다 len(s).


12
met% python -c 'import this' | grep 'only one'
There should be one-- and preferably only one --obvious way to do it.

34
물론 객체로 작업 할 때 확실한 것은 방법입니다.
피터 쿠퍼

4
@ 피터 : 나는 귀도의 뒷면에 당신의 의견을 녹화했다는 사진 증거가있는 사람에게 20 달러를 지불 할 것입니다. 그의 이마에 있으면 $ 50.
bug

1
예, 파이썬 디자이너는 교리를 고수하지만 스스로 교리를 존중하지 않습니다.
bitek

2
$ python -c '가져 오기'| grep 명백한
Ed Randall

4

여기에 큰 대답이 있습니다. 그래서 내가 직접하기 전에 여기에서 읽은 몇 가지 보석 (루비 찌르지 않음)을 강조하고 싶습니다.

  • 파이썬은 순수한 OOP 언어가 아닙니다. 프로그래머가 가장 편한 패러다임 및 / 또는 자신의 솔루션에 가장 적합한 패러다임을 사용할 수 있도록하는 범용 멀티 패러다임 언어입니다.
  • 파이썬은 일급 함수를 가지고 있으므로 len실제로 객체입니다. 반면에 루비에는 퍼스트 클래스 기능이 없습니다. 따라서 len함수 객체에는를 실행하여 검사 할 수있는 자체 메소드가 있습니다 dir(len).

자신의 코드에서 이것이 작동하는 방식이 마음에 들지 않으면 원하는 방법을 사용하여 컨테이너를 다시 구현하는 것이 간단합니다 (아래 예 참조).

>>> class List(list):
...     def len(self):
...         return len(self)
...
>>> class Dict(dict):
...     def len(self):
...         return len(self)
...
>>> class Tuple(tuple):
...     def len(self):
...         return len(self)
...
>>> class Set(set):
...     def len(self):
...         return len(self)
...
>>> my_list = List([1,2,3,4,5,6,7,8,9,'A','B','C','D','E','F'])
>>> my_dict = Dict({'key': 'value', 'site': 'stackoverflow'})
>>> my_set = Set({1,2,3,4,5,6,7,8,9,'A','B','C','D','E','F'})
>>> my_tuple = Tuple((1,2,3,4,5,6,7,8,9,'A','B','C','D','E','F'))
>>> my_containers = Tuple((my_list, my_dict, my_set, my_tuple))
>>>
>>> for container in my_containers:
...     print container.len()
...
15
2
15
15

0

당신은 또한 말할 수 있습니다

>> x = 'test'
>> len(x)
4

파이썬 사용하기 2.7.3.


9
len함수는 이미 이전 답변에서 언급되었습니다. 그렇다면이 "답변"의 요점은 무엇입니까?
Piotr Dobrogost

0

나머지 답변에서 누락 된 부분 : len함수는 __len__메소드가 음이 아닌 것을 반환 하는지 확인합니다 int. len함수 라는 사실 은 클래스가 검사를 피하기 위해이 동작을 무시할 수 없음을 의미합니다. 따라서 불가능한 len(obj)수준의 안전을 제공합니다 obj.len().

예:

>>> class A:
...     def __len__(self):
...         return 'foo'
...
>>> len(A())
Traceback (most recent call last):
  File "<pyshell#8>", line 1, in <module>
    len(A())
TypeError: 'str' object cannot be interpreted as an integer
>>> class B:
...     def __len__(self):
...         return -1
... 
>>> len(B())
Traceback (most recent call last):
  File "<pyshell#13>", line 1, in <module>
    len(B())
ValueError: __len__() should return >= 0

물론 len함수를 전역 변수로 다시 할당 하여 함수 를 "재정의"할 수는 있지만이를 수행하는 코드는 클래스의 메서드를 재정의하는 코드보다 훨씬 더 의심됩니다.


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