Reputation: 2006
I'm trying to create a function that dynamically generates a class with a specified set of mixins and attributes. Here's a simplified version of my code:
def post_type_factory(name, singular_name, mixins, **kwargs):
# Dynamically create a class with the specified mixins
class PostType(*mixins):
name = name
def __init__(self, *args, **kwargs):
for amixin in mixins:
amixin.__init__(*args, **kwargs)
return PostType
However, when I run this code, I get an error: NameError: name 'name' is not defined. I want PostType to inherit from the classes specified in mixins and have a name attribute set to the name argument passed to post_type_factory.
Can anyone explain why the name variable isn't visible in the class definition and suggest how to fix this?
Upvotes: 0
Views: 42
Reputation: 2845
The class body executes before the function is run. Thus name
is not in the scope of the class body. See here for more details: https://docs.python.org/3/tutorial/classes.html#class-definition-syntax
A fix is thus:
def post_type_factory(name, singular_name, mixins, **kwargs):
# Dynamically create a class with the specified mixins
class PostType(*mixins):
def __init__(self, *args, **kwargs):
for amixin in mixins:
amixin.__init__(*args, **kwargs)
self.name = name
return PostType(**kwargs)
A note on inheritance:
When calling the __init__
function you should not forget to provide self
.
Thus:
def post_type_factory(name, singular_name, mixins, **kwargs):
# Dynamically create a class with the specified mixins
class PostType(*mixins):
def __init__(self, *args, **kwargs):
for amixin in mixins:
amixin.__init__(self, *args, **kwargs)
self.name = name
return PostType(**kwargs)
What is more, using super()
, you can automatically call all mixin constructors.
Thus:
def post_type_factory(name, singular_name, mixins, **kwargs):
# Dynamically create a class with the specified mixins
class PostType(*mixins):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.name = name
return PostType(**kwargs)
Upvotes: 1