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).
Je suis un utilisateur débutant de Python (pas le programmeur débutant pensait) et je ne suis pas sûr de "Quand vous voyez un appel au len intégré, vous êtes sûr que si le programme continue après cela plutôt que de lever une exception". J'ai essayé ceci: 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?
Darek Nędza
4
@ DarekNędza Cela n'a rien à voir avec ce qui précède, qui concerne le len intégré. Vous venez de définir votre fonction len, qui peut bien sûr renvoyer ce que vous voulez. OP a parlé de len intégré, qui appelle __len__une méthode spéciale (et non une fonction) sur l'objet considéré.
Veky
@Veky Comment puis-je être sûr que j'appelle la fonction intégrée et 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.
Darek Nędza
3
Alex a explicitement dit que si vous appelez builtin, alors vous êtes sûr ..._. Il n'a rien dit sur le fait que vous appeliez builtin. Mais si vous voulez savoir, vous pouvez: len in vars(__builtins__).values().
Veky
1
Malheureusement, c'est un autre exemple de l'absence d'une classe de base commune pour les objets en Python. Le changement de contexte syntaxique a toujours été dingue. Dans certains cas, il est courant d'utiliser une méthode de soulignement, dans d'autres, on devrait utiliser quelque chose comme une fonction pour faire quelque chose de commun à de nombreux objets. C'est aussi étrange car de nombreux objets n'ont aucune utilité sémantique pour len. Parfois, le modèle d'objet ressemble plus à C ++, cuisine sombre ..
uchuugaka
28
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()
Réponses:
len
est 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 maisa.len()
ne serait pas aussi clair. Lorsque Python a commencé, il__len__
n'existait même pas etlen
é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.la source
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 delen
vs__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:Lorsque vous voyez un appel à la fonction
len
inté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 appelernext(foo)
, et dans3.*
, 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).
la source
def len(x): return "I am a string." print(len(42)) print(len([1,2,3]))
et il a impriméI am string
deux fois. Pouvez-vous l'expliquer davantage?__len__
une méthode spéciale (et non une fonction) sur l'objet considéré.len
non 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 à
Un avantage est qu'il vous permet d'écrire des choses comme
au lieu de
ou
Il y a cependant un comportement légèrement différent. Par exemple dans le cas des ints
la source
operator.methodcaller
au lieu deoperator.attrgetter
.Vous pouvez consulter les documents Pythond :
la source