Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Python > Obtaining a callable class method object from a specific class

Reply
Thread Tools

Obtaining a callable class method object from a specific class

 
 
Nathan Duran
Guest
Posts: n/a
 
      04-10-2008
This is a contrived pseudocode example which has been broken out of a
larger problem, so it may seem like a strange thing to want to do,
but...

I have a group of objects which inherit (single) from a common base
class like so:

---
class Root(object):
@classmethod
def CumulativeScore(cls, arg):
#Ask every child class to
#generate a score and add
#them together
cumulativescore = 0
for base in cls.mro():
cumulativescore += base.Score(arg)
return cumulativescore
#No Score method defined in Root so don't try to call one!

class BranchChild(Root):
@classmethod
def Score(cls, arg):
return 1

class LeafChild(BranchChild):
@classmethod
def Score(cls, arg):
return 3

class LeafChild2(BranchChild):
pass
#No Score method defined here, either!

---

The goal is to be able to call CumulativeScore(arg) on an instance of
any of these objects (Root, Branch or Leaf) which will then chain
calls (top down) to each subclass' Score method if (and only if) one
is defined, returning the sum of all of these calls. Kinda like
constructor chaining, only I don't want it to be explicit/cooperative
because super() doesn't seem to work in classmethods and I want to
reduce the amount of redundant boilerplate code in the subclasses
(which will be numerous).

In order to do this I really need a way to ask LeafChild to give me
*its* Score method *if* it has one of its own. I don't want its
parent's method or its grandparent's method (until I get to them of
course), just the one that's (optionally) defined in LeafChild, so
getattr() and __dict__ are of no use to me. The only thing I've been
able to find that actually works is inspect.classify_class_attrs().
While it delivers the expected behavior, classify_class_attrs spews
out a ton of superfluous information which I have to parse myself, and
the method objects it returns in its tuples are not callable to boot.
This leads to ugly looking code like this:

---
@classmethod
def CumulativeScore(cls, arg):
cumulativescore = 0
mro = list(cls.mro())
mro.reverse()
for base in mro:
matchfunc = [getattr(base, "Score") for attr in
inspect.classify_class_attrs(base) if attr[0] == "Score" and attr[2]
== base]
if len(matchfunc) == 1:
cumulativescore += matchfunc[0](arg)
return cumulativescore
---

In looking through the inspect module's documentation, it seems as
though getmembers() once offered the functionality I require, but no
longer:

"Changed in version 2.2: im_class used to refer to the class that
defined the method."

I've gotten the feeling from the Python documentation that
classmethods are seen as third-class citizens, but they are
unfortunately perfect for my needs, and it doesn't seem like this
should be as complicated as it is. Is there a simpler, more elegant
way to ask a class object if it has a particular method definition
that I've missed somewhere? If not, why can't classify_class_attrs at
least return a callable method object for me (yes, I've read the
"unifying" paper)?

Thanks!


 
Reply With Quote
 
 
 
 
Arnaud Delobelle
Guest
Posts: n/a
 
      04-10-2008
On Apr 10, 7:47*pm, Nathan Duran <(E-Mail Removed)> wrote:
> This is a contrived pseudocode example which has been broken out of a *
> larger problem, so it may seem like a strange thing to want to do, *
> but...
>
> I have a group of objects which inherit (single) from a common base *
> class like so:
>
> ---
> class Root(object):
> * * *@classmethod
> * * *def CumulativeScore(cls, arg):
> * * * * *#Ask every child class to
> * * * * *#generate a score and add
> * * * * *#them together
> * * * * *cumulativescore = 0
> * * * * *for base in cls.mro():
> * * * * * * *cumulativescore += base.Score(arg)
> * * * * *return cumulativescore
> * * *#No Score method defined in Root so don't try to call one!
>
> class BranchChild(Root):
> * * *@classmethod
> * * *def Score(cls, arg):
> * * * * *return 1
>
> class LeafChild(BranchChild):
> * * *@classmethod
> * * *def Score(cls, arg):
> * * * * *return 3
>
> class LeafChild2(BranchChild):
> * * *pass
> * * *#No Score method defined here, either!
>


I won't question why you want to do this...
Here is a solution base on a metaclass, but it feels wrong.

@classmethod
def score(cls, args):
return 0

def totalscore(rootcls, arg):
return sum(cls.score(arg) for cls in rootcls.mro()
if hasattr(cls, 'score'))

class MetaScore(type):
def __new__(meta, name, bases, attrs):
attrs.setdefault('score', score)
return type.__new__(meta, name, bases, attrs)

class Root(object):
__metaclass__ = MetaScore

class Branch(Root):
@classmethod
def score(cls, arg):
return 1

class Leaf(Branch):
@classmethod
def score(cls, arg):
return 3

class Leaf2(Branch):
pass

--------- Test ---------

>>> totalscore(Root, 1)

0
>>> totalscore(Branch, 1)

1
>>> totalscore(Leaf, 1)

4
>>> totalscore(Leaf2, 1)

1

--
Arnaud

 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Obtaining specific .csv data (one data at a time) Kamarulnizam Rahim Ruby 5 02-02-2011 08:43 AM
substitution of a method by a callable object netimen Python 8 10-23-2008 05:34 AM
Making Non Callable Objects Callable exiquio Python 2 10-07-2008 06:02 PM
Static method object not callable Edward Diener Python 8 03-27-2008 09:51 PM
Can string be callable as a method ? Jia Lu Python 1 05-28-2007 02:46 PM



Advertisments