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, 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).
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?
__len__um método especial (não uma função) no objeto em consideração.
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.
len in vars(__builtins__).values().
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()
operator.methodcallervez de operator.attrgetter.
Você pode verificar a documentação do 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