On 4/12/2013 3:17 AM, Ulrich Eckhardt wrote:
Am 11.04.2013 10:19, schrieb Steven D'Aprano:
if sys.version >= '3':

Use sys.version_info >= (3,), otherwise your code breaks when upgrading
to Python 10 and greater. ;^)


The second question that came up was if there is a way to keep a
metaclass defined inside the class or if the only way is to provide it
externally. [...]

Not in general, since the metaclass has to exist independently of the
class.

Thanks for your explanations, they are appreciated.


 > The class is an instance of your metaclass. That means that the
 > metaclass must exist first, so it can be instantiated when you
 > define the class.

I don't like the approach to define the code to post-process a class
before defining the class. It's a bit like top-posting, it messes up the
reading order. Since I really intend to post-process the class, it seems
that metaclasses are simply not the right tool.

Using a post-processing object as a metaclass or decorator necessarily requires predefinition. Such objects are usually used more than once.

For one-off postprocessing, I probably would not bother.

At the moment, this leaves me with two options:

1. post-process the class

class X:
     pass
# attach constants to clas X
for i in (1, 2, 3):
     setattr(X, 'f{}' % i, i)

2. generate code inline

class Y: pass
     # generate constants in local (class-)namespace
     for i in (1, 2, 3):
         locals()['f{}' % i] = i

Mutating class locals() currently works in CPython, but is explicitly not guaranteed to work by the language definition.

In both cases, variables (loop variable 'i') are leaked into the
surrounding namespace, which is kind-of ugly. The second approach also
seems a bit hackish and I can't use the class-in-definition there, which
is limiting when you want to attach e.g. constants of type X to X.


Also PEP 3115 "Metaclasses in Python 3000"[2] seems to
consider postprocessing of a class definition as better handled by a
class decorator, which is something I haven't looked at yet.

Generally, class decorators are less brain-melting than metaclasses.

Alas, they also need to be defined before the class, messing with the
mentioned order of declaration. They can be used to call a class
function though which then does the necessary postprocessing...

3. post-process the class triggered with decorator

def postprocess_class(cls):
     """invoke postprocess() on the decorated object"""
     cls.postprocess()
     del cls.postprocess
     return cls

@postprocess_class
class Z:
     @classfunction
     def postprocess(cls):
         # attach constants to class
         for i in (1, 2, 3):
             setattr(cls, 'f{}' % i, i)


I guess I'll stay with variant 1 for now, since it requires the least
amount of code and the least amount of questions from other developers
here.


--
http://mail.python.org/mailman/listinfo/python-list

Reply via email to