es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Cómo configurar métodos de clase incorporados con la función de tipo de Python?

El siguiente código funciona como se espera

class Foo: pass
a1 = Foo
a2 = Foo
print(a1 == a2)

<h1>True</h1>

<p><code>
ahora, si los genero dinámicamente y los comparo, no funciona
</code>
def eq(a,b):
  return str(a) == str(b)</p>

<p>t1 = type("Foo", (), {"<strong>eq</strong>": eq})
t2 = type("Foo", (), {"<strong>eq</strong>": eq})</p>

<p>print(t1 == t2)</p>

<h1>False</h1>

<p>```</p>

Además, al ejecutar esto, obtengo el error

print(t1.eq(t2))

Traceback (most recent call last):
File “foo.py”, line 51, in
print(t1.eq(t2))
TypeError: eq() missing 1 required positional argument: ‘b’

¿Cuál es la forma correcta de configurar un método incorporado utilizando una función de tipo?

nota al margen:<br>
Necesito este tipo de funcionalidad, donde estoy creando dinámicamente los tipos ya sea a partir de tipos (en este caso es una función de identidad donde devuelvo la salida igual que la entrada) o anotaciones de tipo que no son del tipo tipo sino typing.Alias o typing.Generic. Aquí está el fragmento para tener una imagen más grande

from typing import List
class Foo: pass

def buildtype(type):
”’Construir la definición de tipo de nuevos tipos o anotaciones definidas por el usuario.”’

if isinstance(type, type):
return type

else:
origin = type.origin if hasattr(type, “origin“) else None
args = type.args if hasattr(type, “args“) else None
typename = str(type)
attrs = {
origin“: origin,
args“: args,
hash“: hash((typename, origin, args))
}
return type(type
name, (), attrs)

t1 = buildtype(Foo)
t2 = build
type(Foo)
print(t1 == t2) # True

a1 = buildtype(List[Foo])
a2 = build
type(List[Foo])

print(a1 == a2) # False
“`

Tags:  , , ,

Answer

  1. Avatar for davy.ai

    El problema con las clases t1 y t2 generadas dinámicamente es que tienen un método eq personalizado que solo toma un argumento a. Sin embargo, cuando se compara t1 == t2, Python automáticamente llama al método __eq__ incorporado que toma dos argumentos self y other. Por lo tanto, aparece el mensaje de error “falta 1 argumento posicional requerido: ‘b'”.

    Para solucionar este problema, debes definir el método __eq__ personalizado en las clases t1 y t2 para que tomen dos argumentos en lugar de uno.

    Aquí está el código actualizado:

    class Foo:
        def __eq__(self, other):
            return str(self) == str(other)
    
    t1 = type("Foo", (), {"__eq__": __eq__})
    t2 = type("Foo", (), {"__eq__": __eq__})
    
    print(t1 == t2) # True
    

    Esto ahora debería funcionar como se espera y devolver True.

    En cuanto a la función build_type, puedes modificarla para incluir también el método __eq__ en la definición de tipo generado, similar a la clase Foo anterior. Esto se puede hacer de la siguiente manera:

    def build_type(type_):
        '''Construye la definición de tipo de nuevos tipos o anotaciones definidas por el usuario.'''
    
        if isinstance(type_, type):
            return type_
        else:
            origin = type_.__origin__ if hasattr(type_, "__origin__") else None
            args = type_.__args__ if hasattr(type_, "__args__") else None
            type_name = str(type_)
            attrs = {
                "__origin__": origin,
                "__args__": args,
                "__hash__": hash((type_name, origin, args)),
                "__eq__": lambda self, other: str(self) == str(other)
            }
            return type(type_name, (), attrs)
    

    Esto ahora generará correctamente el método __eq__ para todos los tipos generados dinámicamente, incluido el ejemplo List[Foo].

Comments are closed.