Catching all methods before they execute

  • Thread starter jamesthiele.usenet
  • Start date
J

jamesthiele.usenet

I have run into some cases where I would like to run a class method
anytime any class method is invoked.
That is, if I write
x.foo

then it will be the same as writing
x.bar
x.foo

for any method in class x (with the possible exception of 'bar').

The first few times I wanted to print out a data structure for
debugging purposes. Most recently it was to save a data structure to
allow "undo" operations. I've realized that this is a generalized
problem and I was hoping that someone could point me to the correct
hook to accomplish this (python seems to have a hook for everything).
 
M

Michael Hoffman

I have run into some cases where I would like to run a class method
anytime any class method is invoked.

Perhaps you want __getattribute__ on a new-style class?
 
J

jamesthiele.usenet

Perhaps you want __getattribute__ on a new-style class?

Perhaps I do. The docs say that __getattribute__ is called on all
attribute references, so I tried to make an undoable list as follows:
% cat Undoable.py
class Undoable(object):
def __init__(self, superclass):
self.superclass = superclass
print "__init__"

def __getattribute__(self, name):
print "__getattribute__"
self.SaveState(self)
self.superclass.__getattribute__(self, name)

def SaveState(self):
print "SaveState"

def RestoreState(self):
pass

l = Undoable(list)
l = [1, 2, 3]
print l.count(1)
% python Undoable.py
__init__
1

It appears that __init__ in Undoable is called, count() in list is
called, but not __getattribute__ or SaveState in Undoable.

What don't I understand?
 
M

Michael Hoffman

l = Undoable(list)
l = [1, 2, 3]

You just rebound l, so it no longer refers to an Undoable, it
refers to a list. This design won't work, you need something
more like:

l = Undoable([1, 2, 3])

There were a few other pitfalls in your design... Here,
try something like this instead:

class SurrogateNotInitedError(exceptions.AttributeError):
pass

class Surrogate(object):
"""
the data is stored in _data
>>> list1 = [0, 1, 2, 3]
>>> list2 = [4, 5, 6, 7]
>>> surrogate = Surrogate(list1)
>>> surrogate.reverse()
>>> list1 [3, 2, 1, 0]
>>> surrogate._data = list2
>>> surrogate.append(8)
>>> list2
[4, 5, 6, 7, 8]
"""
def __init__(self, data):
self._data = data

def __getattr__(self, name):
if name == "_data":
raise SurrogateNotInitedError, name
else:
try:
return getattr(self._data, name)
except SurrogateNotInitedError:
raise SurrogateNotInitedError, name

You can modify this to make an UndoableSurrogate with appropriate saving
of state. Note the use of __getattr__ instead of __getattribute__. The
latter is not needed since there are not any attributes defined on
Surrogate instead.
 

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

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,482
Members
44,901
Latest member
Noble71S45

Latest Threads

Top