lenes una función para obtener la longitud de una colección. Funciona llamando al __len__método de un objeto . __something__los atributos son especiales y, por lo general, más de lo que parece, y por lo general no deben llamarse directamente.
Se decidió en algún momento hace mucho tiempo que obtener la longitud de algo debería ser una función y no un código de método, razonando que len(a)el significado sería claro para los principiantes, pero a.len()no tan claro. Cuando Python comenzó __len__ni siquiera existía y lenera algo especial que funcionaba con algunos tipos de objetos. Ya sea que la situación que esto nos deja tenga total sentido o no, está aquí para quedarse.
A menudo ocurre que el comportamiento "típico" de un operador integrado o es llamar (con una sintaxis diferente y más agradable) métodos mágicos adecuados (aquellos con nombres como __whatever__) en los objetos involucrados. A menudo, el operador integrado o tiene un "valor agregado" (es capaz de tomar diferentes caminos dependiendo de los objetos involucrados); en el caso de lenvs __len__, es solo un poco de verificación de cordura en el elemento integrado que falta en el 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
Cuando vea una llamada al lenintegrado, está seguro de que, si el programa continúa después de eso en lugar de generar una excepción, la llamada ha devuelto un número entero, no negativo y menos de 2 ** 31 - cuando ve una llamada a xxx.__len__(), no tiene certeza (excepto que el autor del código no está familiarizado con Python o no está bien ;-).
Otros componentes incorporados brindan aún más valor agregado más allá de simples comprobaciones de cordura y legibilidad. Al diseñar uniformemente todo Python para que funcione a través de llamadas a incorporaciones y el uso de operadores, nunca a través de llamadas a métodos mágicos, los programadores se libran de la carga de recordar qué caso es cuál. (A veces aparece un error: hasta 2.5, tenía que llamar foo.next()- en 2.6, mientras que todavía funciona para la compatibilidad con versiones anteriores, debe llamar next(foo), y en 3.*, el método mágico tiene el nombre correcto en __next__lugar del "oops-ey" next! - ).
Por lo tanto, la regla general debería ser nunca llamar a un método mágico directamente (pero siempre indirectamente a través de un método incorporado) a menos que sepa exactamente por qué necesita hacerlo (por ejemplo, cuando está anulando un método de este tipo en una subclase, si el subclase necesita diferir a la superclase que debe hacerse mediante una llamada explícita al método mágico).
Soy un usuario principiante de Python (no pensaba el programador principiante) y no estoy seguro acerca de "Cuando veas una llamada al len incorporado, estás seguro de que, si el programa continúa después de eso en lugar de generar una excepción". Intenté esto: def len(x): return "I am a string." print(len(42)) print(len([1,2,3]))e imprimió I am stringdos veces. ¿Puedes explicarlo más?
Darek Nędza
4
@ DarekNędza Esto no tiene nada que ver con lo anterior, que se trata de len incorporado. Acaba de definir su función len, que por supuesto puede devolver lo que quiera. OP habló sobre builtin len, que llama a __len__un método especial (no a una función) en el objeto en consideración.
Veky
@Veky ¿Cómo puedo estar seguro de que estoy llamando a la función incorporada, lenno a otra función (como en mi ejemplo) que tiene el mismo nombre - len. No hay ninguna advertencia como "Está redefiniendo la función incorporada len" o algo así. En mi opinión, no puedo estar seguro de lo que dijo Alex en su respuesta.
Darek Nędza
3
Alex dijo explícitamente que si llamas de forma incorporada, entonces estás seguro ..._. No dijo nada sobre estar seguro de que estás llamando integrado. Pero si quieres saber que, se puede: len in vars(__builtins__).values().
Veky
1
Lamentablemente, este es otro ejemplo de la falta de una clase base común para los objetos en Python. El cambio de contexto sintáctico siempre ha sido una locura. En algunos casos, es un modismo común usar un método de subrayado, en otros uno debería usar algo como una función para hacer algo común a muchos objetos. También es extraño porque muchos objetos no tienen uso semántico para len. A veces, el modelo de objetos es más como C ++, cocina hundida ..
uchuugaka
28
Puede pensar que len () es aproximadamente equivalente a
def len(x):return x.__len__()
Una ventaja es que te permite escribir cosas como
somelist =[[1],[2,3],[4,5,6]]
map(len, somelist)
en vez de
map(list.__len__, somelist)
o
map(operator.methodcaller('__len__'), somelist)
Sin embargo, hay un comportamiento ligeramente diferente. Por ejemplo en el 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()
Respuestas:
len
es una función para obtener la longitud de una colección. Funciona llamando al__len__
método de un objeto .__something__
los atributos son especiales y, por lo general, más de lo que parece, y por lo general no deben llamarse directamente.Se decidió en algún momento hace mucho tiempo que obtener la longitud de algo debería ser una función y no un código de método, razonando que
len(a)
el significado sería claro para los principiantes, peroa.len()
no tan claro. Cuando Python comenzó__len__
ni siquiera existía ylen
era algo especial que funcionaba con algunos tipos de objetos. Ya sea que la situación que esto nos deja tenga total sentido o no, está aquí para quedarse.fuente
A menudo ocurre que el comportamiento "típico" de un operador integrado o es llamar (con una sintaxis diferente y más agradable) métodos mágicos adecuados (aquellos con nombres como
__whatever__
) en los objetos involucrados. A menudo, el operador integrado o tiene un "valor agregado" (es capaz de tomar diferentes caminos dependiendo de los objetos involucrados); en el caso delen
vs__len__
, es solo un poco de verificación de cordura en el elemento integrado que falta en el método mágico:Cuando vea una llamada al
len
integrado, está seguro de que, si el programa continúa después de eso en lugar de generar una excepción, la llamada ha devuelto un número entero, no negativo y menos de 2 ** 31 - cuando ve una llamada axxx.__len__()
, no tiene certeza (excepto que el autor del código no está familiarizado con Python o no está bien ;-).Otros componentes incorporados brindan aún más valor agregado más allá de simples comprobaciones de cordura y legibilidad. Al diseñar uniformemente todo Python para que funcione a través de llamadas a incorporaciones y el uso de operadores, nunca a través de llamadas a métodos mágicos, los programadores se libran de la carga de recordar qué caso es cuál. (A veces aparece un error: hasta 2.5, tenía que llamar
foo.next()
- en 2.6, mientras que todavía funciona para la compatibilidad con versiones anteriores, debe llamarnext(foo)
, y en3.*
, el método mágico tiene el nombre correcto en__next__
lugar del "oops-ey"next
! - ).Por lo tanto, la regla general debería ser nunca llamar a un método mágico directamente (pero siempre indirectamente a través de un método incorporado) a menos que sepa exactamente por qué necesita hacerlo (por ejemplo, cuando está anulando un método de este tipo en una subclase, si el subclase necesita diferir a la superclase que debe hacerse mediante una llamada explícita al método mágico).
fuente
def len(x): return "I am a string." print(len(42)) print(len([1,2,3]))
e imprimióI am string
dos veces. ¿Puedes explicarlo más?__len__
un método especial (no a una función) en el objeto en consideración.len
no a otra función (como en mi ejemplo) que tiene el mismo nombre -len
. No hay ninguna advertencia como "Está redefiniendo la función incorporada len" o algo así. En mi opinión, no puedo estar seguro de lo que dijo Alex en su respuesta.len in vars(__builtins__).values()
.Puede pensar que len () es aproximadamente equivalente a
Una ventaja es que te permite escribir cosas como
en vez de
o
Sin embargo, hay un comportamiento ligeramente diferente. Por ejemplo en el caso de ints
fuente
operator.methodcaller
lugar deoperator.attrgetter
.Puede consultar los documentos de Pythond :
fuente