Customizing class attribute access in classic classes

G

Geoff Bache

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
 
G

Geoff Bache

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
 
S

Steven D'Aprano

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:
.... __metaclass__ = Meta
.... a = 1
....'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:
1
 
G

Geoff Bache

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:
Traceback (most recent call last):
Traceback (most recent call last):
False

Regards,
Geoff Bache
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,994
Messages
2,570,223
Members
46,814
Latest member
SpicetreeDigital

Latest Threads

Top