Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #56720 > unrolled thread

Metaclass/abc hackery

Started byDemian Brecht <demianbrecht@gmail.com>
First post2013-10-11 19:47 -0700
Last post2013-10-12 06:56 +0200
Articles 2 — 2 participants

Back to article view | Back to comp.lang.python


Contents

  Metaclass/abc hackery Demian Brecht <demianbrecht@gmail.com> - 2013-10-11 19:47 -0700
    Re: Metaclass/abc hackery Marco Buttu <marco.buttu@gmail.com> - 2013-10-12 06:56 +0200

#56720 — Metaclass/abc hackery

FromDemian Brecht <demianbrecht@gmail.com>
Date2013-10-11 19:47 -0700
SubjectMetaclass/abc hackery
Message-ID<mailman.1027.1381546064.18130.python-list@python.org>

[Multipart message — attachments visible in raw view] — view raw

As with most I'm sure, short of using abc's, I've had very little exposure
to metaclasses. So, when digging into abc implementation, I figured it
would be a good idea to dig into metaclasses, their usage and actually try
writing one.

What I did may be contrived, but it was fun nonetheless and a good
introduction to how metaclasses can be used (of course, they should only be
used when absolutely required and no other solution is readily available
due to the black magic that happens under the hood): I ended up writing a
proof of concept that's abc-like in nature. However, it doesn't depend on
inheritance. It allows you to say: "I want to make sure that this object
/look/ like this type when instantiated".

Again, simple proof of concept that has holes in it and is likely
altogether a bad idea, but it was fun to throw together nonetheless, so I
thought I'd share: https://gist.github.com/demianbrecht/6944269 (check out
the tests at the bottom for usage).

Working on this though brought up a question: Is there anything in the
data model that acts like "__setattr__" but when operating on a class
definition instead of an instance? I'd be able to get rid of the late_bind
function if something like that's available... Not likely something that
would be used very often, but would likely sometimes be useful.

Thanks,

-- 

*Demian Brecht
*http://demianbrecht.github.com

[toc] | [next] | [standalone]


#56724

FromMarco Buttu <marco.buttu@gmail.com>
Date2013-10-12 06:56 +0200
Message-ID<5258D66C.8040404@gmail.com>
In reply to#56720
On 10/12/2013 04:47 AM, Demian Brecht wrote:
>
> Working on this though brought up a question: Is there anything in the
> data model that acts like "__setattr__" but when operating on a class
> definition instead of an instance? I'd be able to get rid of the
> late_bind function if something like that's available... Not likely
> something that would be used very often, but would likely sometimes be
> useful.
>
> Thanks,

I am not sure about your question, but I try to explain a bit some 
possibilities. If you define a __setattr__ method in the metaclass, then 
you can intercept the attribute assignments only after class creation:

 >>> class MetaFoo(type):
...     def __setattr__(cls, name, value):
...         print("in __setattr__(): ", name, value)
...         super().__setattr__(name, value)
...
 >>>
 >>> class Foo(metaclass=MetaFoo):
...     a = 33

As you can see, the above code does not print the message. But after 
class creation it does:

 >>> Foo.a = 33
in __setattr__():  a 33

This because during the class creation there is any class yet, so it is 
not possible to intercept argument assignment by __setattr__.
If you want to intercept the assignments during class creation too, you 
can intercept the class attribute dictionary assignment. In this case 
you can just write a dictionary object that overrides __setitem__, and 
then by overriding the __prepare__ metaclass method in order to return 
this dictionary:

 >>> class Namespace(dict):
...     def __setitem__(self, name, value):
...         print('In Namespace.__setitem__():', name, value)
...         super().__setitem__(name, value)
...
 >>> class MetaFoo(type):
...     def __prepare__(clsname, bases):
...         return Namespace()
...     def __setattr__(cls, name, value):
...         print("In MetaFoo.__setattr__(): ", name, value)
...         super().__setattr__(name, value)
...
 >>> class Foo(metaclass=MetaFoo):
...     a = 33
...
In Namespace.__setitem__(): __module__ __main__
In Namespace.__setitem__(): __qualname__ Foo
In Namespace.__setitem__(): a 33
 >>> Foo.a = 33
In MetaFoo.__setattr__():  a 33

Of course, it is not a so good solution, because if you need to manage 
in the same way either the attributes before or after the class 
creation, you have to do it by writing some code outside the methods:

 >>> def manage(name, value):
...     print('do something with', name, value)
...
 >>> class Namespace(dict):
...     def __setitem__(self, name, value):
...         print('In Namespace.__setitem__():', name, value)
...         manage(name, value)
...         super().__setitem__(name, value)
...
 >>> class MetaFoo(type):
...     def __prepare__(clsname, bases):
...         return Namespace()
...     def __setattr__(cls, name, value):
...         print("In MetaFoo.__setattr__(): ", name, value)
...         manage(name, value)
...         super().__setattr__(name, value)
...
 >>> class Foo(metaclass=MetaFoo):
...     a = 33
...
In Namespace.__setitem__(): __module__ __main__
do something with __module__ __main__
In Namespace.__setitem__(): __qualname__ Foo
do something with __qualname__ Foo
In Namespace.__setitem__(): a 33
do something with a 33
 >>> Foo.a = 33
In MetaFoo.__setattr__():  a 33
do something with a 33

-- 
Marco Buttu

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.python


csiph-web