I have taken a very elementary approach to tracking the use of parent class method calls while working with the child instance. I have modified the __getattribute__
method, so that it writes initial parent method calls into child.parent_method_dict
, and thereafter calls from the child.parent_method_dict
rather than back to the parent class. I am messing with such basic elements here, so I have to ask is there a safer or better way to construct this ability to track parent class method usage. Should I look to somehow assign the parent class methods to the child class so I don't need to use parent_method_dict
?
class Parent(object):
def __init__(self):
pass
def a(self, *args, **kwargs):
return 'hello'
def b(self, *args, **kwargs):
return 'goodbye'
class Child(Parent):
def __init__(self):
super(Child, self).__init__()
self.count = 0
self.parent_method_dict = {}
def __getattribute__(self, attr):
if attr not in ['a', 'b']:
return super(Child, self).__getattribute__(attr)
_parent_dict = self.parent_method_dict
if attr in _parent_dict:
_attr = _parent_dict[attr]
_attr.func_count += 1
return _attr
_attr = super(Child, self).__getattribute__(attr)
print 'getting attribute {}'.format(attr)
if callable(_attr):
print 'can return value'
def _attr_val(*args, **kwargs):
print 'calculating value'
print 'self', self
self.count += 1
return_val = _attr(*args, **kwargs)
return return_val
_attr_val.func_count = 0
_parent_dict[attr] = _attr_val
return _attr_val
_parent_dict[attr] = _attr
return _attr
I know I can implement much more complex forms of tracking, or uses of the tracked information. With the about models, I just wanted to see what goes where.
>>> child = Child()
>>> child.count
0
>>> child.a()
getting attribute a
can return value
calculating value
self <Child object at 0x1036575d0>
'hello'
>>> child.a()
calculating value
self <Child object at 0x1036575d0>
'hello'
>>> child.b()
getting attribute b
can return value
calculating value
self <Child object at 0x1036575d0>
'goodbye'
>>> child.count
3
>>> child.a.func_count
2
>>> child.b.func_count
1
>>> child.parent_method_dict
{'a': <function _attr_val at 0x1035d5f50>, 'b': <function _attr_val at 0x1035d5848>}
The methods return the expected values. The different counts are accurate.
ADDED NOTE to address @Marcin:
Here is a new Parent
class:
class Parent(object):
def __init__(self):
pass
def a(self, *args, **kwargs):
print 'hello'
return self
def b(self, *args, **kwargs):
print 'goodbye'
return self
Inside Child.__init__
, I added self.sequence = []
. Inside def _attr_val(*args, **kwargs)
, I added self.sequence.append(attr)
. So now I get:
>>> c = Child()
>>> c.a().b().a().a().b()
getting attribute a
can return value
calculating value
self <Child object at 0x10361fe90>
hello
getting attribute b
can return value
calculating value
self <Child object at 0x10361fe90>
goodbye
calculating value
self <Child object at 0x10361fe90>
hello
calculating value
self <Child object at 0x10361fe90>
hello
calculating value
self <Child object at 0x10361fe90>
goodbye
<Child object at 0x10361fe90>
>>> c.sequence
['a', 'b', 'a', 'a', 'b']
Now, I can track the sequence of chained methods. So lets say c.a().b()....n()
was a very expensive and also very dependent on the actual sequence. I can now save the value, identified by the sequence needed to calculate it. Additionally, I can easily replicate the sequence at a later time.
See Question&Answers more detail:
os