lené uma função para obter o comprimento de uma coleção. Ele funciona chamando o __len__método de um objeto . __something__os atributos são especiais e geralmente mais do que aparenta, e geralmente não devem ser chamados diretamente.
Foi decidido em algum momento atrás, obter o comprimento de algo deve ser uma função e não um código de método, raciocinando que len(a)o significado seria claro para iniciantes, mas a.len()não seria tão claro. Quando Python começou __len__nem existia e lenera uma coisa especial que funcionava com alguns tipos de objetos. Quer a situação que isso nos deixa faça sentido ou não, ela veio para ficar.
É comum que o comportamento "típico" de um operador interno ou seja chamar (com uma sintaxe diferente e mais agradável) métodos mágicos adequados (aqueles com nomes como __whatever__) nos objetos envolvidos. Freqüentemente, o operador integrado ou tem "valor agregado" (é capaz de seguir caminhos diferentes dependendo dos objetos envolvidos) - no caso de lenvs __len__, é apenas um pouco de verificação de sanidade no integrado que está faltando no método mágico:
>>>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
Ao ver uma chamada para o lenintegrado, você tem certeza de que, se o programa continuar depois disso, em vez de levantar uma exceção, a chamada retornou um número inteiro não negativo e menor que 2 ** 31 - quando você vê uma chamada para xxx.__len__(), você não tem certeza (exceto que o autor do código não está familiarizado com Python ou não é bom ;-).
Outros recursos integrados fornecem ainda mais valor agregado além das simples verificações de integridade e legibilidade. Ao projetar uniformemente todo o Python para funcionar por meio de chamadas a builtins e uso de operadores, nunca por meio de chamadas a métodos mágicos, os programadores são poupados do fardo de lembrar qual caso é qual. (Às vezes, um erro ocorre: até o 2.5, você tinha que chamar foo.next()- no 2.6, embora isso ainda funcione para compatibilidade com versões anteriores, você deve chamar next(foo), e em 3.*, o método mágico é nomeado corretamente em __next__vez de "oops-ey" next! - )
Portanto, a regra geral deve ser nunca chamar um método mágico diretamente (mas sempre indiretamente por meio de um embutido), a menos que você saiba exatamente por que precisa fazer isso (por exemplo, quando você está substituindo tal método em uma subclasse, se o a subclasse precisa se submeter à superclasse, o que deve ser feito por meio de uma chamada explícita ao método mágico).
Eu sou um usuário iniciante de Python (não o pensamento de programador iniciante) e não tenho certeza sobre "Quando você vê uma chamada para o len embutido, você tem certeza que, se o programa continuar depois disso, em vez de levantar uma exceção". Eu tentei isso: def len(x): return "I am a string." print(len(42)) print(len([1,2,3]))e foi impresso I am stringduas vezes. Você pode explicar mais?
Darek Nędza
4
@ DarekNędza Isso não tem nada a ver com o acima, que é sobre len embutido. Você acabou de definir sua função len, que pode retornar o que você quiser. OP falou sobre len embutido, que chama __len__um método especial (não uma função) no objeto em consideração.
Veky
@Veky Como posso ter certeza de que estou chamando uma função interna e lennão alguma outra função (como no meu exemplo) que tinha o mesmo nome - len. Não há nenhum aviso como "Você está redefinindo a função interna len" ou algo assim. Na minha opinião, não tenho certeza do que Alex afirmou em sua resposta.
Darek Nędza
3
Alex disse explicitamente se você está chamando de builtin, então você tem certeza ..._. Ele não disse nada sobre ter certeza de que você está ligando para builtin Mas se você quer saber isso, você pode: len in vars(__builtins__).values().
Veky
1
Infelizmente, este é outro exemplo da falta de uma classe base comum para objetos em Python. A troca de contexto sintática sempre foi louca. Em alguns casos, é um idioma comum usar um método de sublinhado, em outros, deve-se usar algo como uma função para fazer algo comum a muitos objetos. Também é estranho porque muitos objetos não têm uso semântico para len. Às vezes, o modelo de objeto é mais como C ++, pia de cozinha ..
uchuugaka
28
Você pode pensar em len () como sendo aproximadamente equivalente a
def len(x):return x.__len__()
Uma vantagem é que permite que você escreva coisas como
somelist =[[1],[2,3],[4,5,6]]
map(len, somelist)
ao invés de
map(list.__len__, somelist)
ou
map(operator.methodcaller('__len__'), somelist)
No entanto, há um comportamento ligeiramente diferente. Por exemplo, no caso de ints
>>>(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()
Respostas:
len
é uma função para obter o comprimento de uma coleção. Ele funciona chamando o__len__
método de um objeto .__something__
os atributos são especiais e geralmente mais do que aparenta, e geralmente não devem ser chamados diretamente.Foi decidido em algum momento atrás, obter o comprimento de algo deve ser uma função e não um código de método, raciocinando que
len(a)
o significado seria claro para iniciantes, masa.len()
não seria tão claro. Quando Python começou__len__
nem existia elen
era uma coisa especial que funcionava com alguns tipos de objetos. Quer a situação que isso nos deixa faça sentido ou não, ela veio para ficar.fonte
É comum que o comportamento "típico" de um operador interno ou seja chamar (com uma sintaxe diferente e mais agradável) métodos mágicos adequados (aqueles com nomes como
__whatever__
) nos objetos envolvidos. Freqüentemente, o operador integrado ou tem "valor agregado" (é capaz de seguir caminhos diferentes dependendo dos objetos envolvidos) - no caso delen
vs__len__
, é apenas um pouco de verificação de sanidade no integrado que está faltando no método mágico:Ao ver uma chamada para o
len
integrado, você tem certeza de que, se o programa continuar depois disso, em vez de levantar uma exceção, a chamada retornou um número inteiro não negativo e menor que 2 ** 31 - quando você vê uma chamada paraxxx.__len__()
, você não tem certeza (exceto que o autor do código não está familiarizado com Python ou não é bom ;-).Outros recursos integrados fornecem ainda mais valor agregado além das simples verificações de integridade e legibilidade. Ao projetar uniformemente todo o Python para funcionar por meio de chamadas a builtins e uso de operadores, nunca por meio de chamadas a métodos mágicos, os programadores são poupados do fardo de lembrar qual caso é qual. (Às vezes, um erro ocorre: até o 2.5, você tinha que chamar
foo.next()
- no 2.6, embora isso ainda funcione para compatibilidade com versões anteriores, você deve chamarnext(foo)
, e em3.*
, o método mágico é nomeado corretamente em__next__
vez de "oops-ey"next
! - )Portanto, a regra geral deve ser nunca chamar um método mágico diretamente (mas sempre indiretamente por meio de um embutido), a menos que você saiba exatamente por que precisa fazer isso (por exemplo, quando você está substituindo tal método em uma subclasse, se o a subclasse precisa se submeter à superclasse, o que deve ser feito por meio de uma chamada explícita ao método mágico).
fonte
def len(x): return "I am a string." print(len(42)) print(len([1,2,3]))
e foi impressoI am string
duas vezes. Você pode explicar mais?__len__
um método especial (não uma função) no objeto em consideração.len
não alguma outra função (como no meu exemplo) que tinha o mesmo nome -len
. Não há nenhum aviso como "Você está redefinindo a função interna len" ou algo assim. Na minha opinião, não tenho certeza do que Alex afirmou em sua resposta.len in vars(__builtins__).values()
.Você pode pensar em len () como sendo aproximadamente equivalente a
Uma vantagem é que permite que você escreva coisas como
ao invés de
ou
No entanto, há um comportamento ligeiramente diferente. Por exemplo, no caso de ints
fonte
operator.methodcaller
vez deoperator.attrgetter
.Você pode verificar a documentação do Pythond :
fonte