module wide metaclass for new style classes

D

Daniel Nogradi

I used to have the following code to collect all (old style) class
names defined in the current module to a list called reg:


def meta( reg ):
def _meta( name, bases, dictionary ):
reg.append( name )
return _meta

reg = [ ]
__metaclass__ = meta( reg )

class c1:
pass

class c2:
pass

print reg


This would correctly print [ 'c1', 'c2' ]. Now I would like to switch
to new style classes but replacing class c1: and class c2: by class
c1(object): and class c2(object): doesn't work because the metaclass
associated with object will be called and not mine. Of course if I
would add __metaclass__ = meta(reg) to all class definitions that
would work, but how do I do this on the module level?
 
G

Gabriel Genellina

I used to have the following code to collect all (old style) class
names defined in the current module to a list called reg:

def meta( reg ):
def _meta( name, bases, dictionary ):
reg.append( name )
return _meta

reg = [ ]
__metaclass__ = meta( reg )

class c1:
pass

class c2:
pass

print reg

This would correctly print [ 'c1', 'c2' ]. Now I would like to switch
to new style classes but replacing class c1: and class c2: by class
c1(object): and class c2(object): doesn't work because the metaclass
associated with object will be called and not mine. Of course if I
would add __metaclass__ = meta(reg) to all class definitions that
would work, but how do I do this on the module level?

That code doesn't work even for classic classes. Anyway, you don't have
to add __metaclass__ everywhere, only to the base class(es).

If all you want to register is contained in a single module, I prefer a
function that iterates over all defined classes:

from inspect import isclass
for obj in globals().values():
if isclass(obj): # may be stricter too, like issubclass(obj, Base)
reg.append(obj)
 
P

Peter Otten

Daniel said:
I used to have the following code to collect all (old style) class
names defined in the current module to a list called reg:


def meta( reg ):
def _meta( name, bases, dictionary ):
reg.append( name )
return _meta

reg = [ ]
__metaclass__ = meta( reg )

class c1:
pass

class c2:
pass

print reg

That code does not create classes. Here's a slightly simplified version:
reg = []
def __metaclass__(name, bases, dict):
.... reg.append(name)
....
class A: pass ....
reg ['A']
A is None
True # oops!
This would correctly print [ 'c1', 'c2' ]. Now I would like to switch
to new style classes but replacing class c1: and class c2: by class
c1(object): and class c2(object): doesn't work because the metaclass
associated with object will be called and not mine. Of course if I
would add __metaclass__ = meta(reg) to all class definitions that
would work, but how do I do this on the module level?

If present, __metaclass__ serves as a factory for classes without an
explicit base class. For example,

__metaclass__ = type

would turn c1 and c2 into newstyle classes (that inherit from object).
If you want side effects you can wrap the metaclass into a function:
reg = []
def __metaclass__(name, bases, dict):
.... reg.append(name)
.... return type(name, bases, dict)
....
class A: pass ....
class B: pass ....
reg ['A', 'B']
issubclass(A, object)
True

Peter
 
D

Daniel Nogradi

I used to have the following code to collect all (old style) class
names defined in the current module to a list called reg:


def meta( reg ):
def _meta( name, bases, dictionary ):
reg.append( name )
return _meta

reg = [ ]
__metaclass__ = meta( reg )

class c1:
pass

class c2:
pass

print reg

That code does not create classes. Here's a slightly simplified version:
reg = []
def __metaclass__(name, bases, dict):
... reg.append(name)
...
class A: pass ...
reg ['A']
A is None
True # oops!
This would correctly print [ 'c1', 'c2' ]. Now I would like to switch
to new style classes but replacing class c1: and class c2: by class
c1(object): and class c2(object): doesn't work because the metaclass
associated with object will be called and not mine. Of course if I
would add __metaclass__ = meta(reg) to all class definitions that
would work, but how do I do this on the module level?

If present, __metaclass__ serves as a factory for classes without an
explicit base class. For example,

__metaclass__ = type

would turn c1 and c2 into newstyle classes (that inherit from object).
If you want side effects you can wrap the metaclass into a function:
reg = []
def __metaclass__(name, bases, dict):
... reg.append(name)
... return type(name, bases, dict)
...
class A: pass ...
class B: pass ...
reg ['A', 'B']
issubclass(A, object)
True

Thanks a lot, and sorry for the copy-paste error, I had the 'return
type(...)' line but didn't know that this already creates new-style
classes.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,997
Messages
2,570,239
Members
46,827
Latest member
DMUK_Beginner

Latest Threads

Top