|
|
### Metaclass Derivation Code |
### Metaclass Derivation Code |
|
|
metaReg = WeakValueDictionary() |
metaReg = WeakValueDictionary() # Weak, so unused metaclasses can die off |
|
|
def derivedMeta(metaclasses): |
def derivedMeta(metaclasses): |
derived = metaReg.get(metaclasses) |
derived = metaReg.get(metaclasses) |
types. Effectively, 'makeClass()' fully supports the three most popular |
types. Effectively, 'makeClass()' fully supports the three most popular |
Python metatypes: "classic classes", "new-style types", and |
Python metatypes: "classic classes", "new-style types", and |
'ExtensionClass'. You cannot, however, combine ExtensionClasses with |
'ExtensionClass'. You cannot, however, combine ExtensionClasses with |
new-style types, because their root metatype is different. That is, |
new-style types, because their root metatypes are different. That is, |
'type(type) is type', and 'type(ExtensionClass) is ExtensionClass'. There |
'type(type) is type', and 'type(ExtensionClass) is ExtensionClass'. There |
may be other ways to create illegal metatype combinations, but they should |
may be other ways to create illegal metatype combinations, but they should |
be detected and result in a TypeError. |
be detected and result in a TypeError. |
names. So if you set '__metaclasses__' to 'ThreadSafe, Persistent' |
names. So if you set '__metaclasses__' to 'ThreadSafe, Persistent' |
(or if your bases are instances of 'ThreadSafe' and 'Persistent'), the |
(or if your bases are instances of 'ThreadSafe' and 'Persistent'), the |
derived metaclass will be called 'ThreadSafe_Persistent'. That is, |
derived metaclass will be called 'ThreadSafe_Persistent'. That is, |
the return from 'makeClass()' will be of type (have a '__class__ of) |
the return from 'makeClass()' will be of type (have a '__class__' of) |
'ThreadSafe_Persistent'. |
'ThreadSafe_Persistent'. |
|
|
Metaclasses are derived according to the algorithm in the book "Putting |
Metaclasses are derived according to the algorithm in the book "Putting |
tomorrow, if one of your subclasses so desires! |
tomorrow, if one of your subclasses so desires! |
""" |
""" |
|
|
# Create either a plain Python class or an ExtensionClass, |
# Create either a "classic" Python class, an ExtensionClass, or a new-style |
# based on the nature of the base classes involved |
# class with autogenerated metaclass, based on the nature of the base |
|
# classes involved |
|
|
name = str(name) # De-unicode |
name = str(name) # De-unicode |
|
|
metaclasses = normalizeBases(metaclasses) |
metaclasses = normalizeBases(metaclasses) |
|
|
if metaclasses: |
if metaclasses: |
metaclass = derivedMeta(metaclasses) |
|
return metaclass(name,bases,dict) |
|
|
|
from new import classobj; return classobj(name,bases,dict) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# If we have metaclasses, it's not a classic class, so derive a |
|
# single metaclass, and ask it to create the class. |
|
|
|
metaclass = derivedMeta(metaclasses) |
|
return metaclass(name,bases,dict) |
|
|
|
# No metaclasses, it's a classic class, so use 'new.classobj' |
|
|
|
from new import classobj; return classobj(name,bases,dict) |
|
|
|
|
if __name__=='__main__': |
if __name__=='__main__': |