Réponses:
lenest une fonction pour obtenir la longueur d'une collection. Cela fonctionne en appelant la __len__méthode d' un objet .__something__Les attributs sont spéciaux et généralement plus qu'il n'y paraît, et ne doivent généralement pas être appelés directement.
Il a été décidé il y a longtemps que la longueur de quelque chose devait être une fonction et non un code de méthode, le raisonnement que cette len(a)signification serait clair pour les débutants mais a.len()ne serait pas aussi clair. Lorsque Python a commencé, il __len__n'existait même pas et lenétait une chose spéciale qui fonctionnait avec quelques types d'objets. Que la situation que cela nous laisse ait ou non un sens total, elle est là pour rester.
Il arrive souvent que le comportement "typique" d'un opérateur intégré ou d'un opérateur soit d'appeler (avec une syntaxe différente et plus agréable) des méthodes magiques appropriées (celles avec des noms comme __whatever__) sur les objets impliqués. Souvent, l’opérateur intégré ou l’opérateur a une «valeur ajoutée» (il peut emprunter des chemins différents en fonction des objets impliqués) - dans le cas de lenvs __len__, il s’agit juste d’un peu de vérification de la cohérence de l’intégré qui manque dans le méthode magique:
>>> 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
Lorsque vous voyez un appel à la fonction lenintégrée, vous êtes sûr que, si le programme continue après cela plutôt que de lever une exception, l'appel a renvoyé un entier, non négatif et inférieur à 2 ** 31 - lorsque vous voyez un appel àxxx.__len__() , vous n'avez aucune certitude (sauf que l'auteur du code n'est pas familier avec Python ou n'est pas bon ;-).
D'autres éléments intégrés offrent encore plus de valeur ajoutée au-delà des simples contrôles de cohérence et de la lisibilité. En concevant uniformément tout Python pour qu'il fonctionne via des appels à des fonctions intégrées et l'utilisation d'opérateurs, jamais par des appels à des méthodes magiques, les programmeurs sont épargnés du fardeau de se souvenir de quel cas est quel cas. (Parfois une erreur se glisse: jusqu'à 2.5, vous deviez appeler foo.next()- en 2.6, alors que cela fonctionne toujours pour la compatibilité ascendante, vous devriez appeler next(foo), et dans 3.*, la méthode magique est correctement nommée __next__au lieu du "oops-ey" next! - ).
Donc, la règle générale devrait être de ne jamais appeler une méthode magique directement (mais toujours indirectement via un intégré) à moins que vous ne sachiez exactement pourquoi vous devez faire cela (par exemple, lorsque vous surchargez une telle méthode dans une sous-classe, si le la sous-classe doit s'en remettre à la superclasse qui doit être effectuée via un appel explicite à la méthode magique).
def len(x): return "I am a string." print(len(42)) print(len([1,2,3]))et il a imprimé I am stringdeux fois. Pouvez-vous l'expliquer davantage?
__len__une méthode spéciale (et non une fonction) sur l'objet considéré.
lennon une autre fonction (comme dans mon exemple) qui porte le même nom - len. Il n'y a pas d'avertissement comme "Vous redéfinissez la fonction intégrée len" ou quelque chose comme ça. À mon avis, je ne peux pas être sûr de ce qu'Alex a déclaré dans sa réponse.
len in vars(__builtins__).values().
Vous pouvez penser à len () comme étant à peu près équivalent à
def len(x):
return x.__len__()
Un avantage est qu'il vous permet d'écrire des choses comme
somelist = [[1], [2, 3], [4, 5, 6]]
map(len, somelist)
au lieu de
map(list.__len__, somelist)
ou
map(operator.methodcaller('__len__'), somelist)
Il y a cependant un comportement légèrement différent. Par exemple dans le cas des 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.methodcallerau lieu de operator.attrgetter.
Vous pouvez consulter les documents 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