Por que o uso de código Python len function () em vez de um método de comprimento?
-
04-07-2019 - |
Pergunta
Eu sei que python tem uma função len()
que é usado para determinar o tamanho de uma string, mas eu queria saber por que ele não é um método do objeto string.
Atualizar
Ok, eu percebi que estava vergonhosamente enganados. __len__()
é realmente um método de um objeto string. Parece apenas estranho ver código orientado objeto em Python utilizando a função Len em objetos string. Além disso, também é estranho ver __len__
como o nome em vez de apenas len.
Solução
Strings têm um método de comprimento: __len__()
O protocolo em Python é implementar este método sobre objectos que têm um comprimento e usam o built-in len()
função noreferrer, que chama-lo para você, semelhante à maneira como você poderia implementar __iter__()
e usar o built-in função iter()
(ou ter o método chamado nos bastidores para você) em objetos que são iterable.
tipos de contêineres Veja Emulando para mais informações.
Aqui está uma boa leitura sobre o assunto de protocolos em Python: Python e o princípio da menor Astonishment
Outras dicas
A resposta de Jim para esta pergunta pode ajudar; Eu copiá-lo aqui. Citando Guido van Rossum:
Em primeiro lugar, eu escolhi len (x) sobre x.len () por razões de IHC (def __len __ () veio muito mais tarde). Há duas razões interligadas, na verdade, tanto HCI:
(a) Para algumas operações, prefixo notação apenas lê melhor do que postfix - (! E infix) prefixo operações têm uma longa tradição na matemática que gosta de anotações onde os visuais ajudam o pensamento matemático sobre um problema. Compare o fácil com que reescrever uma fórmula como x * (a + b) em x a + x b para a falta de jeito de fazer a mesma coisa usando uma notação OO matéria.
(b) Quando li o código que diz len (x) Eu sei que ele está pedindo para o comprimento de algo. Isto diz-me duas coisas: o resultado é um número inteiro, eo argumento é algum tipo de recipiente. Ao contrário, quando li x.len (), eu tenho que já sabe que x é algum tipo de recipiente implementação de uma interface ou herdar de uma classe que tem um len () padrão. Testemunha a confusão que ocasionalmente têm quando uma classe que não está a implementar um mapeamento tem um método get () ou as teclas (), ou algo que não é um arquivo tem um método write ().
dizendo a mesma coisa de outra maneira, eu vejo ‘len’ como uma operação integrada. Eu odeio perder isso. / ... /
Existe um método len
:
>>> a = 'a string of some length'
>>> a.__len__()
23
>>> a.__len__
<method-wrapper '__len__' of str object at 0x02005650>
Python é uma linguagem de programação pragmática, e as razões para len()
sendo uma função e não um método de str
, list
, dict
etc. são pragmáticos.
O len()
built-in ofertas de função diretamente com tipos built-in: a implementação CPython de len()
realmente retorna o valor do campo ob_size
na PyVarObject
C struct que representa qualquer um de tamanho variável embutido objecto na memória. Esta é muito mais rápido do que chamar um método - não precisa de atributo de pesquisa para acontecer. Obtendo o número de itens em uma coleção é uma operação comum e deve trabalhar de forma eficiente para tais tipos básicos e diversos como str
, list
, array.array
etc.
No entanto, para promover a coerência, ao aplicar len(o)
a um tipo definido pelo usuário, o Python chama o.__len__()
como um fallback. __len__
, __abs__
e todos os outros métodos especiais documentados no Python Data Model tornar mais fácil para criar objetos que se comportam como os embutidos, possibilitando que as APIs expressivos e altamente consistentes chamamos de "Pythonic".
Ao implementar métodos especiais seus objetos podem apoiar iteração, operadores de sobrecarga infixas, gerenciar contextos em with
blocos etc. Você pode pensar o modelo de dados como uma maneira de usar-se a linguagem Python como um quadro onde os objetos criados podem ser integrados sem problemas.
A segunda razão, apoiado por citações de Guido van Rossum como esta , é que é mais fácil de ler e len(s)
gravação de s.len()
.
O len(s)
notação é consistente com operadores unários com notação de prefixo, como abs(n)
. len()
é usado muito mais frequentemente do que abs()
, e merece ser tão fácil de escrever.
Há também pode ser uma razão histórica:. Na língua ABC que precedeu Python (e foi muito influente na sua concepção), houve um operador unário escrito como #s
que significava len(s)
met% python -c 'import this' | grep 'only one'
There should be one-- and preferably only one --obvious way to do it.
Há algumas grandes respostas aqui, e assim antes de eu dar o meu próprio eu gostaria de destacar algumas das gemas (sem trocadilho rubi intencional) Eu li aqui.
- Python não é uma linguagem OOP pura -. É um propósito geral, a linguagem multi-paradigma que permite que o programador para usar o paradigma que está mais confortável com e / ou o paradigma de que é mais adequado para a sua solução
- Python tem funções de primeira classe, de modo
len
é realmente um objeto. Ruby, por outro lado, não tem funções de primeira classe. Assim, o objeto de funçãolen
tem seu próprio métodos que você pode inspecionar executandodir(len)
.
Se você não gosta da maneira como isso funciona em seu próprio código, é trivial para você reimplementar os recipientes usando seu método preferido (veja exemplo abaixo).
>>> 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
Você também pode dizer
>> x = 'test'
>> len(x)
4
Usando Python 2.7.3.
Ele não?
>>> "abc".__len__()
3