Finding the public callables of self

R

Russell Warren

Is there any better way to get a list of the public callables of self
other than this?

myCallables = []
classDir = dir(self)
for s in classDir:
attr = self.__getattribute__(s)
if callable(attr) and (not s.startswith("_")):
myCallables.append(s) #collect the names (not funcs)

I don't mean a shorter list comprehension or something that just drops
the line count, but whether or not I need to go at it through dir and
__getattribute__. This seems a bit convoluted and with python it often
seems there's something already canned to do stuff like this when I do
it. At first I thought self.__dict__ would do it, but callable methods
seem to be excluded so I had to resort to dir, and deal with the
strings it gives me.

Thanks,
Russ
 
L

Lonnie Princehouse

import inspect
myCallables = [name for name, value in inspect.getmembers(self) if not
name.startswith('_') and callable(value)]


Instance methods aren't in self.__dict__ because they're a part of the
class. To made a comprehensive list of all the attributes available to
an instance, you have to traverse the attribute dictionaries of the
instance, its class, and all of the base classes in the right order.
(inspect.getmro returns the base classes in method resolution order)
 
S

Sion Arrowsmith

Russell Warren said:
Is there any better way to get a list of the public callables of self
other than this?

myCallables = []
classDir = dir(self)
for s in classDir:
attr = self.__getattribute__(s)
if callable(attr) and (not s.startswith("_")):
myCallables.append(s) #collect the names (not funcs)

I don't mean a shorter list comprehension or something that just drops
the line count, but whether or not I need to go at it through dir and
__getattribute__. This seems a bit convoluted and with python it often
seems there's something already canned to do stuff like this when I do
it. At first I thought self.__dict__ would do it, but callable methods
seem to be excluded so I had to resort to dir, and deal with the
strings it gives me.

This last sentence suggests to me something like:

attrs = set(s for s in dir(self) if not s.startswith('_'))
myCallables = attrs.difference(a.__dict__)
return list(myCallables)

(which you can get down to one line if you want).
 
K

Kent Johnson

Russell said:
Is there any better way to get a list of the public callables of self
other than this?

myCallables = []
classDir = dir(self)
for s in classDir:
attr = self.__getattribute__(s)
if callable(attr) and (not s.startswith("_")):
myCallables.append(s) #collect the names (not funcs)
I don't mean a shorter list comprehension or something that just drops
the line count, but whether or not I need to go at it through dir and
__getattribute__. This seems a bit convoluted and with python it often
seems there's something already canned to do stuff like this when I do
it.

Use getattr(self, s) instead of self.__getattribute__(s).

You could streamline it a bit with a list comprehension:
myCallables = [ s for s in dir(self) if not s.startswith('_') and
callable(getattr(self, s)) ]

At first I thought self.__dict__ would do it, but callable methods
seem to be excluded so I had to resort to dir, and deal with the
strings it gives me.

The callables are attributes of the class and its base classes, not of
self. self.__dict__ just contains instance attributes.

Kent
 
B

bruno at modulix

Sion said:
At first I thought self.__dict__ would do it, but callable methods

This last sentence suggests to me something like:

attrs = set(s for s in dir(self) if not s.startswith('_'))
myCallables = attrs.difference(a.__dict__)
err... s/a.__dict__/self.__dict__/
return list(myCallables)


Won't work as expected:
.... class_attrib = 42
.... def __init__(self, attr):
.... self.attr = attr
.... def doit(self):
.... if callable(self.attr):
.... return self.attr(self)
........ attrs = set(s for s in dir(obj) if not s.startswith('_'))
.... callables = attrs.difference(obj.__dict__)
.... return list(callables)
....
getcallables(t) ['doit', 'class_attrib']
t.attr(t) 'Tricky'
t.class_attrib()
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: 'int' object is not callable


There are 2 reliable ways to know if an object is callable:
- using callable()
- trying to call it
 
R

Russell Warren

import inspect
myCallables = [name for name, value in inspect.getmembers(self) if not
name.startswith('_') and callable(value)]

Thanks. I forgot about the inspect module. Interestingly, you've also
answered my question more than I suspect you know! Check out the code
for inspect.getmembers():

def getmembers(object, predicate=None):
"""Return all members of an object as (name, value) pairs sorted by
name.
Optionally, only return members that satisfy a given predicate."""
results = []
for key in dir(object):
value = getattr(object, key)
if not predicate or predicate(value):
results.append((key, value))
results.sort()
return results

Seems familiar! The fact that this is using dir(), getattr(), and
callable() seems to tell me there is no better way to do it. I guess
my method wasn't as indirect as I thought!

And thanks for the reminder about getattr() instead of
__getattribute__() and other streamlining tips.

Russ
 
L

Lonnie Princehouse

Ha! I didn't realize that was getmembers' implementation. What a hack
;-)

In fact, your way is faster, since getmembers is taking the time to
sort its results (presumably so that repeated calls to the same object
will yield the same list; I don't think dir has a guaranteed ordering)
 

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
474,436
Messages
2,571,696
Members
48,796
Latest member
Greg L.
Top