1

I'm trying to dynamically create subclasses in Python with type:

class A:
    @classmethod
    def create_subclass(cls, name, attrs):
        return type(name, (cls,), attrs)

for i in range(5):
    x = A.create_subclass("B", {"func": abs})

print(A.__subclasses__())

and here's what I see in the output:

[<class '__main__.B'>, <class '__main__.B'>, <class '__main__.B'>, <class '__main__.B'>, <class '__main__.B'>]

Obviously, this was not my intention. Two questions in that respect:

  1. How does Python handles multiple classes with identical names?
  2. What is a pythonic way to handle it? Of course, I can look up the name in the already existing subclasses, but then how to deal with namespaces/modules?
3
  • I am not entirely sure but my guess is that since __subclasses__ returns a list, maybe previous subclasses are not removed from there and so they stay there, also they are not the same object, I tested by adding a variable to the dict: {'var': i} so each of them have different ones. Then I iterated over the returned list and retrieved that name, they all had their own values so they are not overwritten and apparently are not deleted, so you can still use them if you need, you just apparently need to get them from that list Commented Dec 30, 2021 at 13:03
  • 1
    See this answer. Commented Dec 30, 2021 at 13:42
  • 2
    Names are just metadata associated with a class. What's important is the class object itself. A.__subclasses__() contains references to 5 distinct classes that just happen to have the same value for their __name__ attributes. Commented Dec 30, 2021 at 18:58

1 Answer 1

1

Python doesn't care overmuch about the classname, these will be different classes, you just need to have a mechanism to save and look up the classes you want.

class A:

    def __repr__(self):
        return f"{self.__class__.__name__} floor={self.floor}"


    @classmethod
    def create_subclass(cls, name, attrs):
        return type(name, (cls,), attrs)

di_cls = {}
#save them in a dictionary
for i in range(5):
    di_cls[i] = A.create_subclass("B", {"func": abs, "floor" : i})

for i, cls in di_cls.items():
    print(f"{cls()}")

class config:
    #put them in hierarchical namespaces
    cls_level1 = A.create_subclass("B", {"func": abs, "floor" : 11})

    class level2:
        cls_level2 = A.create_subclass("B", {"func": abs, "floor" : 22})

print(f"{config.cls_level1()=}")
print(f"{config.level2.cls_level2()}")

l1 = config.cls_level1()
l2 = config.level2.cls_level2()

print(f"{isinstance(l1, A)=}")
print(f"{isinstance(l2, A)=}")
print(f"{isinstance(l2, config.level2.cls_level2)=}")
print(f"{isinstance(l2, config.cls_level1)=}")


output:

B floor=0
B floor=1
B floor=2
B floor=3
B floor=4
config.cls_level1()=B floor=11
B floor=22
isinstance(l1, A)=True
isinstance(l2, A)=True
isinstance(l2, config.level2.cls_level2)=True
isinstance(l2, config.cls_level1)=False

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.