Trying to learn about metaclasses

Chris Kaynor ckaynor at zindagigames.com
Mon Jul 25 13:53:48 EDT 2011


On Mon, Jul 25, 2011 at 8:36 AM, Steven W. Orr <steveo at syslang.net> wrote:

> I have been doing a lot of reading. I'm starting to get it. I think it's
> really cool as well as dangerous, but I plan on being respectful of the
> construct. I found a web page that I found quite readable.
>
> http://cleverdevil.org/**computing/78/<http://cleverdevil.org/computing/78/>
>
> So, I tried to run the example code (below), and I get AttributeError. If
> someone can get me over this hump, I'd be grateful. It complains that Person
> has no _fields attribute, but the print hello I have in EnforcerMeta doesn't
> happen either. Am I doing something wrong?
>
> I'm running python 2.6.2
>
> Here's the error:
>
> 585 > ./meta1.py
> Traceback (most recent call last):
>  File "./meta1.py", line 38, in <module>
>    swo.name = 'swo'
>  File "./meta1.py", line 27, in __setattr__
>    if key in self._fields:
> AttributeError: 'Person' object has no attribute '_fields'
>
>
> And here's the code:
>
> #! /usr/bin/python
> # http://cleverdevil.org/**computing/78/<http://cleverdevil.org/computing/78/>
> class Field(object):
>    def __init__(self, ftype):
>        self.ftype = ftype
>
>    def is_valid(self, value):
>        return isinstance(value, self.ftype)
>
> class EnforcerMeta(type):
>    def __init(cls, name, bases, ns):
>        # Store the field definitions on the class as a dictionary
>        # mapping the field name to the Field instance.
>        print 'Hello'
>        cls._fields = {}
>
>        # loop through the namespace looking for Field instances.
>        for key, value in ns.items():
>            if isinstance(value, Field):
>                cls._fields[key] = value
>
> class Enforcer(object):
>    # attach the metaclass
>    __metaclass__ = EnforcerMeta
>
>    def __setattr__(self, key, value):
>        if key in self._fields:
>            if not self._fields[key].is_valid(**value):
>                raise TypeError('Invalid type for field.')
>        super(Enforcer, self).__setattr__(key, value)


If I understand what you are trying to do here (other than playing with
metaclasses), you should be able to implement this as a descriptor (
http://docs.python.org/reference/datamodel.html#implementing-descriptors).

Something like (untested):

class Field(object):
   def __init__(self, name, type):
      self.ftype = type
      self.name = name

   def __get__(self, instance, owner):
      return getattr(instance, self.name)

   def __set__(self, instance, value):
      if not self.is_valid(value):
               raise TypeError()
      setattr(instance, self.name, value)

   def is_valid(self, value):
       return isinstance(value, self.ftype)


>
> class Person(Enforcer):
>    name = Field(str)
>    age = Field(int)
>
> if __name__ == '__main__':
>    swo = Person()
>    swo.name = 'swo'
>    print 'swo:', swo
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-list/attachments/20110725/64dda2e6/attachment-0001.html>


More information about the Python-list mailing list