Python: Dynamically create class while providing arguments to __init_subclass__()
Asked Answered
M

1

9

How can I dynamically create a subclass of my class and provide arguments to its __init_subclass__() method?

Example class:

class MyClass:
    def __init_subclass__(cls, my_name):
        print(f"Subclass created and my name is {my_name}")

Normally I'd implement my subclass as such:

class MySubclass(MyClass, my_name="Ellis"):
    pass

But how would I pass in my_name when dynamically creating a subclass of MyClass using a metaclass? Normally I could use type() but it doesn't have the option of providing my_name.

MyDynamicSubclass = type("MyDynamicSubclass", (MyClass,), {})
Matheny answered 18/8, 2020 at 17:39 Comment(12)
type is a metaclass. If you want to use a different metaclass, call that instead. The interface should be similar.Collodion
So, according to the data model documentation type doesn't receive the argument. You would have to manually call it after the creationShaylynn
Oh, so just use MyDynamicSubclass.__init_subclass__(my_name="Ellis")?Matheny
What happens if you pass the keyword arguments to type at the end of the argument list? The documentation implies that it's worth trying :)Collodion
E.g. MyDynamicSubclass = type("MyDynamicSubclass", (MyClass,), {}, my_name='Ellis')Collodion
@EllisPercival yes, I think you have to do it that wayShaylynn
@MadPhysicist oh! That totally worked!Shaylynn
@Shaylynn docs.python.org/3/reference/… is what implies it would, in the first sentences of the section. I'll post an answer shortlyCollodion
@MadPhysicist yep, I missed thatShaylynn
@juanpa.arrivillaga. DoneCollodion
@EllisPercival. Thank you for an interesting question. It's been a while since I've looked into metaclasses and class creation.Collodion
@MadPhysicist you're welcome! I doubt this will be the last time I get confused by metaclasses xDMatheny
C
12

The basic documentation for type does not mention that it accepts an unlimited number of keyword-only arguments, which you would supply through the keywords in a class statement. The only place this is hinted in is in the Data Model in the section Creating the class object:

Once the class namespace has been populated by executing the class body, the class object is created by calling metaclass(name, bases, namespace, **kwds) (the additional keywords passed here are the same as those passed to __prepare__).

Normally, you would not use this feature with type exactly because of __init_subclass__:

The default implementation object.__init_subclass__ does nothing, but raises an error if it is called with any arguments.

Since you have overriden the default implementation, you can create your dynamic class as

MyDynamicSubclass = type("MyDynamicSubclass", (MyClass,), {}, my_name="Ellis")
Collodion answered 18/8, 2020 at 18:13 Comment(2)
Great, thank you! I didn't consider that the docs might omit that information. That works perfectly :)Matheny
@EllisPercival. They don't omit it as such. They just don't emphasize it. But I agree that they could be more explicit.Collodion

© 2022 - 2024 — McMap. All rights reserved.