Standing Objects ... possible?
Jason Orendorff
jason at jorendorff.com
Mon Feb 11 04:28:53 EST 2002
Paul Rubin wrote:
> Jason Orendorff wrote:
> > Philip Swartzleonard writes:
> > > What i want is a construct like:
> > >
> > > object Foo( ancestor ):
> > > pass
> >
> > Yep, it exists.
>
> This has gone past me somehow. Can someone explain it? Thanks.
I will, but I warn you that this isn't understood by many people.
You must use this knowledge only for good. :)
When you write:
class X(BasicX, OtherBaseClass):
name = 'foo'
bar = 2
blah = None
what happens as a result is a lot like this:
X = type('X',
(BasicX, OtherBaseClass),
{'name': 'foo', 'bar': 2, 'blah': None})
type is itself a builtin type; when Python calls it like that,
it creates a "type object", which is the same as saying that
it creates the class X. The arguments, you can see, are
determined by the source code for the class. They are:
'X' - the class name
(BasicX, OtherBaseClass) - a tuple of the base classes
{...} - a dictionary of the new class's members.
If you define methods within class X, then those functions
go in the member dictionary too.
Here, try it yourself:
>>> X = type('MyType', (), {'n': 5}) # Create a class manually!
>>> X
<class '__main__.MyType'>
>>> X.n
5
Weird, huh?
"Metaclassing" means asking Python to call something else,
instead of type(), to create the class. There are a few ways
to trigger this. The easiest is to use __metaclass__.
def make_a_type(name, bases, dict):
""" My custom function for creating a class. """
# Do some silly things...
print "Making a type!"
print "A message for you:", dict.get('msg')
dict['made_by'] = 'Jason' # add my name here
return type(name, bases, dict) # type() does the real work
class X:
__metaclass__ = make_a_type
msg = 'Hello, world!'
>>> X.made_by
'Jason'
You can use whatever callable __metaclass__ you want.
For example, your __metaclass__ could be an actual class whose
constructor takes three arguments.
class Course(object):
# This is actually a real, ordinary class.
# Since we want to use it as a metaclass, its
# constructor must take 3 arguments (plus 'self').
def __init__(self, name, bases, dict):
self.name = name
self.bases = bases
self.dict = dict
def __repr__(self):
return "<%s>" % self.name
class CS1280:
__metaclass__ = Course
professor = 'Cleese'
title = 'Introduction to Programming with SPAMTRAN'
class CS6196:
__metaclass__ = Course
professor = 'van Rossum'
title = 'Metaprogramming in Python 2.2'
Now you see that this is creating "standing objects" as desired.
Python creates CS1280 and CS6196 by calling Course(); so they
are Course objects.
(You could make the class Course a subclass of type,
if you really want the objects to behave like typical classes
rather than typical objects.)
(There is also a subtler way of getting a metaclass other than
type(); but I won't get into it. For a more technical overview,
consult http://www.python.org/2.2/descrintro.html#metaclasses .)
## Jason Orendorff http://www.jorendorff.com/
More information about the Python-list
mailing list