stackoverflow question

Owen Jacobson angrybaldguy at gmail.com
Sun Mar 11 00:48:44 EST 2012


On 2012-03-10 22:21:55 +0000, Ethan Furman said:

> Owen Jacobson wrote:
>> On 2012-03-09 22:10:18 +0000, Ethan Furman said:
>> 
>>> Hey all!
>>> 
>>> I posted a question/answer on SO earlier, but there seems to be some 
>>> confusion around either the question or the answer (judging from the 
>>> comments).
>>> 
>>> http://stackoverflow.com/q/9638921/208880
>>> 
>>> If anyone here is willing to take a look at it and let me know if I did 
>>> not write it well, I would appreciate the feedback.
>>> 
>>> 
>>> Here's the question text:
>>> ------------------------
>>> I'm writing a metaclass to do some cool stuff, and part of its 
>>> processing is to check that certain attributes exist when the class is 
>>> created.  Some of these are mutable, and would normally be set in 
>>> `__init__`, but since `__init__` isn't run until the instance is 
>>> created the metaclass won't know that the attribute *will* be created, 
>>> and raises an error.  I could do something like:
>>> 
>>> class Test(meta=Meta):
>>> mutable = None
>>> def __init__(self):
>>> self.mutable = list()
>>> 
>>> But that isn't very elegant, and also violates DRY.
>>> 
>>> What I need is some way to have:
>>> 
>>> class Test(metaclass=Meta):
>>> mutable = list()
>>> 
>>> t1 = Test()
>>> t2 = Test()
>>> t1.mutable.append('one')
>>> t2.mutable.append('two')
>>> t1.mutable  # prints ['one']
>>> t2.mutable  # prints ['two']
>>> 
>>> Any ideas on how this can be accomplished?
>>> 
>>> Also, the metaclass doing the checking doesn't care what type of object 
>>> the attribute is, only that it is there.
>>> ---------------------------
>> 
>> Why check what you can ensure? The __init__ function your metaclass 
>> passes to type() doesn't have to be the __init__ method your metaclass 
>> received.

[… __init__-generation technique elided …]

>> All instances of classes whose metaclass is Meta will, guaranteed, have 
>> an instance field named 'mutable'. Its value is a list created at 
>> instance creation time, unless the instance's __init__ provides a 
>> different value.
> 
> The idea is good.  The devil is in the details, as usual.  How is the 
> metaclass going to know:
> 
>    1) which attributes to replace
>    2) what to replace them with?

I can think of at least three techniques; others are certainly possible:

1. As with the example code, the list is hard-coded in the metaclass's 
source code.
2. The list (or, rather, a dictionary) is drawn from a class attribute 
of the class being created:

	class Foo(object):
	    mandatory_fields = {'mutable': list, 'more_stuff': str}
	    __metaclass__ = IntrospectingMetaclass

3. A metaclass-returning factory produces new metaclasses on demand, 
each of which has a dict of mandatory fields baked into it. (This is a 
hybrid of the two approaches, and can easily have some messy side 
effects on your app's type ecology if used carelessly.)

Of course, you can also treat this the other way around: instead of 
enforcing that instances have specific fields, you could have users of 
those instances be aware that the field might not exist, and wrap 
access to the field in a try/except NameError block or use getattr to 
read the attribute.

What's appropriate really depends on how you plan to use this 
metaclass, and on the nature of the higher-level problem to which "I 
know, I'll use metaclasses" is your answer. How about telling us a 
slightly broader story about your problem?

-o




More information about the Python-list mailing list