Parámetro __key__ para clases en Python
Frecuentes
Visto 3,663 veces
7
Tengo una matriz de vectores y quiero ordenarlos por longitud:
class Vector:
def __init__(self, x, y):
self.x, self.y = x, y
def __add__(a, b):
return Vector(a.x + b.x, a.y + b.y)
def __str__(a):
return str(a.x) + ' ' + str(a.y) + '\n'
def __key__(self):
return self.x * self.x + self.y * self.y
a = []
a.append(Vector(1,2))
a.append(Vector(1, 1))
a.sort()
print("".join(map(str,a)))
Dice: "tipos no ordenados: Vector() < Vector()" Quiere que cree lt
, gt
.. métodos. Pero quiero ordenar sin usar cmp
. ¿Es posible?
3 Respuestas
7
Yo implementaría __lt__
y __eq__
y luego usar el functools.total_ordering
decorador de clase para obtener el resto de los métodos de comparación.
Si no tiene sentido tener sus vectores ordenados así, siempre puede usar el key
palabra clave para sort
(o sorted
para esa materia):
mylist.sort(key = lambda v: v.x**2 + v.y**2)
Respondido 28 ago 12, 12:08
Esto es claro, pero semánticamente un poco dudoso: los vectores no están totalmente ordenados por longitud ya que, por ejemplo, (0,1) y (1,0) son diferentes pero se compararían como iguales. - Katriel
@katrielalex -- Algo cierto. Eres libre de implementar __eq__
y __lt__
como mejor le parezca. podrías hacer __eq__
define como self.x == other.x and self.y == other.y
por ejemplo. En este caso particular, realmente no veo cómo un vector puede ser "menor que" otro, así que en este caso, probablemente usaría por defecto un key
está ordenando, pero pensé que incluiría functools.total_ordering
ya que se parece más a lo que parece que OP está tratando de hacer. (También es un decorador útil para saber independientemente). - mgilson
Creo que esta es una buena idea, y creo que debería funcionar en base a la source
. La pregunta es: ¿ total_ordering
definir __gt__
de una manera que vuelve False
cuando x
y y
¿son iguales? Y parece que de la fuente. El resultado en este caso no será un pedido total, sino un pedido anticipado total; lo que es total aquí es realmente el relación, en lugar del orden. - remitente
Aunque mirando hacia atrás en esto, el problema que __eq__
devolverá verdadero para dos vectores diferentes. Probablemente no sea lo ideal... - remitente
total_ordering tiene trampas sutiles: regebro.wordpress.com/2010/12/13/… - Sr_y_Sra_D
6
Tienes dos variantes aquí: implementar __cmp__
Funcionar en Vector
clase o realice la clasificación de esta manera:
...
a.sort(key=Vector.__key__)
Respondido 28 ago 12, 20:08
Yo sugeriría cambiar el nombre de la __key__
método para __len__
, ya que el valor devuelto es, de hecho, la longitud del vector. Entonces usa a.sort(key=len)
, que muestra la intención mucho más claramente. - Lauritz V. Thaulow
¡@lazyr ciertamente no! __len__
es por la longitud de secuencias; Python espera que devuelva un número entero. (Además, el valor que se devuelve actualmente es el cuadrado de la longitud). - Carlos Knechtel
@lazyr: estoy de acuerdo con el principio de que __key__
no es el mejor nombre (incluso aparte de que posiblemente signifique algo específico en el futuro, no es muy específico), pero __len__
es un poco cuestionable, ya que help(len)
dice que es "el número de elementos de una secuencia o mapeo". Probablemente lo definiría como una función separada (no un método) llamada algo así como norm
. - lvc
Asimismo, vale la pena señalar que __cmp__
desaparece en python 3.x. (que el OP podría estar usando) - mgilson
2
Los documentos de Python dicen que lt/le/gt/ge/eq/ne son
[...] los llamados métodos de "comparación rica", y se llaman para operadores de comparación con preferencia a __cmp__()
Si implementa un __cmp__(self, other)
método, debe usarse para operaciones de comparación/clasificación.
Respondido 28 ago 12, 12:08
Vale la pena señalar que __cmp__
ya no se usa en python 3.x - mgilson
@mgilson de hecho, y dada la print
uso, es posible que OP ya esté usando Py3. - lvc
@Ivc: sí, y la sintaxis de "estilo antiguo" para la declaración de clase (aunque eso podría deberse a que el OP no sabe heredar siempre de object
en pitón 2.x). - mgilson
No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas python sorting key or haz tu propia pregunta.
Tenga en cuenta que probablemente no debería usar
__key__
como el nombre de uno de sus métodos. los nombres de métodos entre paréntesis por pares de guiones bajos están reservados para medios especiales por la especificación (esto significa que en cualquier momento, Guido podría decidir que quiere agregar__key__
como parte del modelo de datos de python y su método podría causar un comportamiento bastante interesante (no deseado).) - mgilsonAdemás, si solo está buscando una buena clase de vector, es posible que desee investigar
numpy
. Proporciona "ndarray" que se comportan de manera muy similar a los vectores, admite una forma de indexación muy interesante (y útil) y realiza todas las operaciones matemáticas en C, lo que las hace un poco más rápidas de lo que se obtendría con las propias. implementación. - mgilson@mgilson parece que OP estaba esperando
__key__
estar ya definido como parte del modelo de datos de Python, con un comportamiento análogo alkey
parámetro de palabra clave paralist.sort
. - Karl KnechtelSugerencia menor:
__str__
no debería devolver una nueva línea\n
, deja que eso sea manejado porprint
,join
, etc. declaraciones/funciones. - aneroidAdemás, es costumbre nombrar el primer argumento de los métodos
self
más bien quea
(a menos que sea un@staticmethod
o algo). No es obligatorio, pero cuando leí su código, me obligó a hacer una doble toma porque esa convención está muy arraigada en mi psique. - mgilson