Customizing class attribute access in classic classes

Discussion in 'Python' started by Geoff Bache, Oct 29, 2011.

  1. Geoff Bache

    Geoff Bache Guest

    Hi,

    I'm wondering if there is any way to customize class attribute access
    on classic classes?

    So this works:

    class Meta(type):
    def __getattr__(cls, name):
    return "Customized " + name

    class A:
    __metaclass__ = Meta

    print A.blah

    but it turns A into a new-style class.

    If "Meta" does not inherit from type, the customization works but A
    ends up not being a class at all, severely restricting its usefulness.
    I then hoped I could get "Meta" to inherit from types.ClassType but
    that wasn't allowed either.

    Is there any way to do this or is it just a limitation of classic
    classes?

    Regards,
    Geoff Bache
    Geoff Bache, Oct 29, 2011
    #1
    1. Advertising

  2. Geoff Bache

    Geoff Bache Guest

    On Oct 30, 4:16 am, Ben Finney <> wrote:
    > Geoff Bache <> writes:
    > > I'm wondering if there is any way to customize class attribute access
    > > on classic classes?

    >
    > Why do that? What is it you're hoping to achieve, and why limit it to
    > classic classes only?
    >


    I'm building a mocking tool, CaptureMock, which works by intercepting
    and capturing particular calls, recording and replaying them.
    A user can just say "intercept httplib for me" and it will record all
    the interactions with httplib and allow a test that can be run without
    doing anything via http or writing any handcrafted "mock-code".

    So I need to be able to intercept also static attribute access, say
    httplib.HTTPConnection.request.

    httplib.HTTPConnection is a classic class. I can make my intercepting
    version of it into a new-style class but the risk is that that will
    change its behaviour in subtle ways, negating the point of the tool.

    As for limiting it to classic classes only, I obviously need to do it
    on new-style classes also. But I know how to do that...

    Regards,
    Geoff Bache
    Geoff Bache, Oct 30, 2011
    #2
    1. Advertising

  3. On Sat, 29 Oct 2011 14:06:12 -0700, Geoff Bache wrote:

    > Hi,
    >
    > I'm wondering if there is any way to customize class attribute access on
    > classic classes?
    >
    > So this works:
    >
    > class Meta(type):
    > def __getattr__(cls, name):
    > return "Customized " + name
    >
    > class A:
    > __metaclass__ = Meta
    >
    > print A.blah
    >
    > but it turns A into a new-style class.


    And why is this a problem?

    In any case, metaclasses work for classic classes. Metaclasses go back to
    pre-Python 1.5, long before new-style classes and type unification.

    http://www.python.org/doc/essays/metaclasses/

    You just have to do a lot more work:


    class Meta:
    def __init__(self, name, bases, namespace):
    self.__name__ = name
    self.__bases__ = bases
    self.__dict__ = namespace
    def __str__(self):
    return "<Meta instance>"
    __repr__ = __str__
    def __getattr__(self, name):
    return "Customized " + name
    def __call__(self):
    return self

    (The purpose of the __str__ and __repr__ methods is to make it possible
    to experiment in the interactive interpreter, without a lot of mysterious
    and puzzling "str object is not callable" TypeErrors. Trust me on this.)

    And in use:

    >>> class Spam:

    .... __metaclass__ = Meta
    .... a = 1
    ....
    >>> Spam.b

    'Customized b'


    But note that using classic classes, there is no equivalent of
    __getattribute__ or descriptors, so there is no way to customize access
    of an attribute which actually does exist:

    >>> Spam.a

    1


    --
    Steven
    Steven D'Aprano, Oct 30, 2011
    #3
  4. Geoff Bache

    Geoff Bache Guest

    Thanks for this Steven. I'm however gettings some pretty odd effects,
    both on method access and inheritance. I expanded your example a
    bit...

    class Meta:
    def __init__(self, name, bases, namespace):
    self.__name__ = name
    self.__bases__ = bases
    self.__dict__ = namespace
    def __str__(self):
    return "<Meta instance>"
    __repr__ = __str__
    def __getattr__(self, name):
    return "Customized " + name
    def __call__(self):
    return self

    class Base:
    def basemethod(self):
    return "base"


    class A(Base):
    __metaclass__ = Meta
    def method(self):
    return "answer"

    The effect seems to be to make all methods of A into static methods,
    and to ignore its base classes altogether:

    >>> a = A()
    >>> print a.blah2

    Customized blah2
    >>> print a.method()

    Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    TypeError: method() takes exactly 1 argument (0 given)
    >>> print a.method(1)

    answer
    >>> print A.method(1)

    answer
    >>> print a.basemethod()

    Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    TypeError: 'str' object is not callable
    >>> isinstance(a, Base)

    False

    Regards,
    Geoff Bache
    Geoff Bache, Oct 30, 2011
    #4
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Robin Becker
    Replies:
    0
    Views:
    282
    Robin Becker
    Feb 15, 2005
  2. venk
    Replies:
    5
    Views:
    321
  3. aaragon
    Replies:
    11
    Views:
    560
    terminator
    Nov 13, 2006
  4. Quek
    Replies:
    3
    Views:
    335
  5. Roman Puttkammer

    customizing attribute values for control properties

    Roman Puttkammer, Dec 5, 2003, in forum: ASP .Net Building Controls
    Replies:
    0
    Views:
    126
    Roman Puttkammer
    Dec 5, 2003
Loading...

Share This Page