I am well aware of fact that classes can be declared dynamically in python using type
and have used it here and there. But I am still unclear what are the differences between these two functions.
def class_factory():
def init(self, attr):
self.attr = attr
class_ = type('DynamicClass', (), {'__init__' : init})
return class_
and
def class_factory():
class DynamicClass:
def __init__(self, attr):
self.attr = attr
return DynamicClass
I have seen first pattern used in a lot of code-bases (like django) but never seen second one so far. Still I find second one more clear, syntactically.
I am struggling to find proper explanation about why people use first pattern
for declaring dynamic classes and not second
one. I experimented with both functions and could not find any notable differences between classes obtained from both functions. I am hoping for a clear explanation about differences between above two patterns/syntaxes from any aspect (performance-wise or any other) they differ.
Thanks,
A
class
statement is a declarative syntax for a call to a metaclass.is equivalent to
where
{...}
is some mapping constructed from the body of theclass
statement. Just as a simple example, without going into full detail:would define a function name
__init__
, then pass{'__init__': __init__, 'some_attr': 'foo string'}
toSomeMeta
. The name__init__
only exists in a temporary namespace created by theclass
statement, without affecting any name__init__
that might exist outside the statement.To answer your question, sometimes it is more flexible or simpler to construct the third argument the metaclass yourself than to let the
class
statement do it for you. The same goes for the second argument. The first argument is fixed by the syntax of theclass
statement, but could be generated at run-time if you call the metaclass yourself.Note that this means you can really abuse the
class
statement.EnumMeta
from theenum
module, in my opinion, stretches what you should do with one. Here's a really abusive example. The metaclass doesn't actually have to be a type; it just has to be callable, and it needs to accept three positional arguments. It can accept additional keyword arguments as well. It can then do anything it wants with those arguments, and return anything it wants as well.Foo
isn't even a class; it's bound to3
.