How are Python metaclasses different from regular class inheritance?
Question:
This might be too much of an open ended question, but I’m just now learning about metaclasses in Python and I don’t understand how a metaclass is any different than just having a child class inherit from the parent class, like
class child(parent):
Wouldn’t this serve the same purpose of a metaclass? I guess maybe I don’t understand the purpose of a metaclass.
Answers:
The difference is that inheriting from a class does not affect how the class is created, it only affects how instances of the class are created. If you do:
class A(object):
# stuff
class B(A):
# stuff
then A does not have any opportunity to “hook in” when B is created. Methods of A may be called when an instance of B is created, but not when the class B itself is created.
Metaclasses allow you to define custom behavior for when a class is created. Refer to the question I marked as duplicate for examples of how metaclasses work, and convince yourself that there are effects in those examples that you can’t achieve with normal inheritance.
class AccessorType(type):
def __init__(self, name, bases, d):
type.__init__(self, name, bases, d)
accessors = {}
prefixs = ["get_", "set_", "del_"]
for k in d.keys():
v = getattr(self, k)
for i in range(3):
if k.startswith(prefixs[i]):
accessors.setdefault(k[4:], [None, None, None])[i] = v
for name, (getter, setter, deler) in accessors.items():
# create default behaviours for the property - if we leave
# the getter as None we won't be able to getattr, etc..
# [...] some code that implements the above comment
setattr(self, name, property(getter, setter, deler, ""))
This might be too much of an open ended question, but I’m just now learning about metaclasses in Python and I don’t understand how a metaclass is any different than just having a child class inherit from the parent class, like
class child(parent):
Wouldn’t this serve the same purpose of a metaclass? I guess maybe I don’t understand the purpose of a metaclass.
The difference is that inheriting from a class does not affect how the class is created, it only affects how instances of the class are created. If you do:
class A(object):
# stuff
class B(A):
# stuff
then A does not have any opportunity to “hook in” when B is created. Methods of A may be called when an instance of B is created, but not when the class B itself is created.
Metaclasses allow you to define custom behavior for when a class is created. Refer to the question I marked as duplicate for examples of how metaclasses work, and convince yourself that there are effects in those examples that you can’t achieve with normal inheritance.
class AccessorType(type):
def __init__(self, name, bases, d):
type.__init__(self, name, bases, d)
accessors = {}
prefixs = ["get_", "set_", "del_"]
for k in d.keys():
v = getattr(self, k)
for i in range(3):
if k.startswith(prefixs[i]):
accessors.setdefault(k[4:], [None, None, None])[i] = v
for name, (getter, setter, deler) in accessors.items():
# create default behaviours for the property - if we leave
# the getter as None we won't be able to getattr, etc..
# [...] some code that implements the above comment
setattr(self, name, property(getter, setter, deler, ""))