2008-09-17 13 views
18

ejemplo:¿Por qué no es la función 'len' heredada por los diccionarios y listas en Python

a_list = [1, 2, 3] 
a_list.len() # doesn't work 
len(a_list) # works 

Python ser (muy) orientado, no entiendo por qué la función 'len' no es objeto heredado por el objeto. Además, sigo intentando la solución incorrecta, ya que parece ser la más lógica para mí

+0

Las funciones no se heredan. Los métodos son ¿De qué objeto 'len' método le gustaría heredar? – tzot

+0

Esto es irrelevante ya que len solo llama al método __len__, por lo que los mismos problemas de herencia seguirán siendo válidos. –

+5

@Eli Se refiere al método '__len__' - ASÍ, interpretó los doble guión bajo en negrita. =) – MatrixFrog

Respuesta

40

explicación de Guido es here:

En primer lugar, he elegido len (x) en x.len() por razones de HCI (def __len __() llegó mucho más tarde). En realidad, existen dos razones entrelazadas, ambas HCI:

(a) Para algunas operaciones, la notación de prefijo simplemente lee mejor que postfix - las operaciones de prefijo (¡e infijo!) Tienen una larga tradición en matemática que le gusta las notaciones donde matemático pensando en un problema. Compare la facilidad con la que reescribimos una fórmula como x * (a + b) en x a + x b por la torpeza de hacer lo mismo utilizando una notación OO cruda.

(b) Cuando leo el código que dice len (x) sé que está pidiendo la longitud de algo. Esto me dice dos cosas: el resultado es un número entero, y el argumento es algún tipo de contenedor. Por el contrario, cuando leo x.len(), tengo que saber que x es un tipo de contenedor que implementa una interfaz o hereda de una clase que tiene un len() estándar. Sea testigo de la confusión que ocasionalmente tenemos cuando una clase que no implementa una asignación tiene un método get() o keys(), o algo que no es un archivo tiene un método write().

diciendo lo mismo de otra manera, veo 'len' como una operación incorporada. Odiaría perder eso./.../

+22

Para aquellos que no saben, HCI significa Interfaz Humano-Computadora. Entonces, cuando Guido dice que tomó la decisión por "razones de HCI", está diciendo que pensó que hacía el código más legible. –

+0

@Thomas: Python usa '|' para O a nivel de bits, al igual que C. – dan04

+1

En el que Guido argumenta que las funciones genéricas son mejores que los métodos. La mente se confunde. :/ –

2

Quizás esté buscando __len__. Si ese método existe, len (a) lo llama:

>>> class Spam: 
... def __len__(self): return 3 
... 
>>> s = Spam() 
>>> len(s) 
3 
10

Simplemente no lo es.

Puede, sin embargo, hacer:

>>> [1,2,3].__len__() 

3 

Adición de un método __len__() a una clase es lo que hace el trabajo len() magia.

2

Bueno, en realidad es un método de longitud, es sólo oculta:

>>> a_list = [1, 2, 3] 
>>> a_list.__len__() 
3 

El len() función incorporada parece ser simplemente un contenedor para una llamada a la oculta len() método del objeto.

No estoy seguro de por qué tomaron la decisión de implementar las cosas de esta manera.

11

La respuesta corta: 1) compatibilidad con versiones anteriores y 2) no hay suficiente diferencia para que realmente importe. Para una explicación más detallada, sigue leyendo.

El enfoque idiomático de Python para tales operaciones es métodos especiales que no están destinados a ser llamados directamente. Por ejemplo, para que x + y funcione para su propia clase, escriba un método __add__.Para asegurarse de que int(spam) convierta correctamente su clase personalizada, escriba un método __int__. Para asegurarse de que len(foo) haga algo sensato, escriba un método __len__.

Así es como siempre han sido las cosas con Python, y creo que tiene mucho sentido para algunas cosas. En particular, esto parece una forma sensata de implementar la sobrecarga del operador. En cuanto al resto, los diferentes idiomas no están de acuerdo; en Ruby convertirías algo a un entero llamando directamente al spam.to_i en lugar de decir int(spam).

Tiene razón en que Python es un lenguaje extremadamente orientado a objetos y que tener que llamar a una función externa en un objeto para obtener su longitud parece extraño. Por otro lado, len(silly_walks) no es más oneroso que silly_walks.len(), y Guido ha dicho que realmente lo prefiere (http://mail.python.org/pipermail/python-3000/2006-November/004643.html).

+3

Ah ... esto finalmente le dio sentido a todo. len() es más un operador que una función, realmente. – Nate

5

De esta manera encaja mejor con el resto del lenguaje. La convención en python es que agregue __foo__ métodos especiales a los objetos para que tengan ciertas capacidades (en lugar de, por ejemplo, derivar de una clase base específica). Por ejemplo, un objeto es

  • exigible si tiene un __call__ método
  • iterable si tiene un __iter__ método,
  • soporta acceso con [] si tiene __getitem__ y __setitem__.
  • ...

Uno de estos métodos especiales es __len__, que hace que tiene una longitud accesible con len().

Cuestiones relacionadas