Metaclasses and class variables

Bengt Richter bokr at oz.net
Fri Aug 5 01:53:17 CEST 2005


On Thu, 4 Aug 2005 17:53:28 +0200, Jan-Ole Esleben <esleben at gmail.com> wrote:

>Thanks! It's a bit icky, yes, but I've been so wrapped up in
>complicated thinking that I didn't see this. It's actually  quite an
>OK solution (I need it because I have an internal representation for
>method interfaces that needs to be saved somewhere without the user
>having to worry about it, and without them having to set variables.
>Method interfaces are class specific, and the only other thing I could
>do would be to have a dictionary of classes somewhere, but as the
>class itself uses its interface I can't see any really sensible way to
>go about this differently).
>
>Ole
>
>
>2005/8/4, Mike C. Fletcher <mcfletch at rogers.com>:
>> Jan-Ole Esleben wrote:
>>=20
>> >Yes, that works, but it is unfortunately not an option (at least not a
>> >good one).
>> >
>> >Is there no way to create a class variable that exists during
>> >definition of the class? (I cannot imagine there isn't, since
>> >technically it's possible and manually it can be done...)
>> >
>> >Ole
>> >
>> >
>> The metaclass hook occurs *after* class definition, anything using a
>> side-effect of a metaclass hook then, *must* occur after the execution
>> of the metaclass hook.  At the time you want to write classvar.append
>> the "class" is only a namespace, so, if you really need this feature
>> you'll need to look elsewhere for at least *part* of the solution.
>>=20
>> A global "classvar" that, when appended to, caches values until your
>> metaclass is called and transfers the cache to the class should *work*,
>> but egads that's ugly compared to just classvar =3D [] .  I guess what I'=
>d
>> ask is *why* is avoiding that single line so important.  It could be
>> there's a reasonable answer, but the amount of machinery required to
>> avoid it is going to be significant.
>>=20
>> class meta( type ):
>>     newClassVar =3D []
>>     def __new__( cls, name, bases, dictionary ):
>>         dictionary[ 'classvar' ] =3D cls.newClassVar[:]
>>         del cls.newClassVar[:]
>>         return super( meta, cls ).__new__( cls, name, bases, dictionary )
>> __metaclass__ =3D meta
>> classvar =3D meta.newClassVar
>>=20
>> or something along those lines...
>>=20
>> Um, ick, but HTH,
>> Mike
>>=20
>> --
What about using a closure variable instead of the global mentioned above? E.g.,

 >>> def cfactory():
 ...     classvar = []
 ...     class TheClass(object):
 ...         classvar.append(1)
 ...         classvar.append(2)
 ...     TheClass.classvar = classvar
 ...     return TheClass
 ...
 >>> tc = cfactory()
 >>> tc
 <class '__main__.TheClass'>
 >>> tc.classvar
 [1, 2]

I'm wondering what the real problem is. If you are creating some kind of class
variable that accumulates things related to methods, why can't the metaclass do
the whole job after the methods have all been defined cleanly?

OTOH, if not, have you considered that decorators execute a def-time of the decorated
functions -- which for methods defined in class scope will be during class definition
execution. E.g., you could make classvars accessible through a base class and pump into
via decorators (note that you can decorate with Base.deco or bind it by itself as below)

 >>> class Base(object):
 ...    classvar = []
 ...    @classmethod
 ...    def deco(cls, f):
 ...        cls.classvar.append((f.func_name, f.func_code.co_argcount))
 ...
 >>> deco = Base.deco
 >>> class TheClass(Base):
 ...     @deco
 ...     def foo(): pass
 ...     @Base.deco
 ...     def bar(x, y): print 'two args:', x, y
 ...
 >>> TheClass.classvar
 [('foo', 0), ('bar', 2)]

Incidentally, you can see that deco and classvar belong to the Base class, though
accessible as instance and class attributes

 >>> tc = TheClass()
 >>> tc.classvar
 [('foo', 0), ('bar', 2)]
 >>> TheClass.mro()
 [<class '__main__.TheClass'>, <class '__main__.Base'>, <type 'object'>]
 >>> vars(tc)
 {}
 >>> vars(TheClass).keys()
 ['__module__', 'foo', 'bar', '__doc__']
 >>> vars(Base).keys()
 ['__module__', 'deco', 'classvar', '__dict__', '__weakref__', '__doc__']

HTH. Add metaclasses and stir to taste ;-)

Regards,
Bengt Richter



More information about the Python-list mailing list