The following code works as expected
class Foo: pass
a1 = Foo
a2 = Foo
print(a1 == a2)
# True
now if I dynamically generate them and compare it it doesn't work
def eq(a,b):
return str(a) == str(b)
t1 = type("Foo", (), {"__eq__": eq})
t2 = type("Foo", (), {"__eq__": eq})
print(t1 == t2)
# False
Moreover when running this, I get the error
print(t1.__eq__(t2))
Traceback (most recent call last):
File "foo.py", line 51, in <module>
print(t1.__eq__(t2))
TypeError: eq() missing 1 required positional argument: 'b'
What's the correct way to setup a builtin methods with using a type function ?
sidenote:
I need this kind of functionality, where I am dynamically creating the types either from types(in this case it's a identity function where I return output same as input) or type annotation which are not of type type but either typing.Alias or typing.Generic. Here is the snippet to get bigger picture
from typing import List
class Foo: pass
def build_type(type_):
'''Build type definition of new user-defined types or annotations.'''
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))
}
return type(type_name, (), attrs)
t1 = build_type(Foo)
t2 = build_type(Foo)
print(t1 == t2) # True
a1 = build_type(List[Foo])
a2 = build_type(List[Foo])
print(a1 == a2) # False
As you were told in comments, methods have to be members of the class, not of the instance.
As you are dynamically building classes and not simple objects, you should use a custom meta-class with a specific __eq__
method:
You example would become:
...
class Builder(type):
"""Custom meta-class defining type equality as name equality"""
def __eq__(self, other):
return str(self) == str(other)
def build_type(type_):
'''Build type definition of new user-defined types or annotations.'''
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))
}
return Builder(type_name, (), attrs)
...
If you run it, you should get as expected:
True
True