Python: How can I get a list of function names from a __getattr__ function?

How to get a list of class functions from __getattr__ functions?

Python v2.7 if that matters.

Trying to use dir inside __getattr__ results in infinite recursion.

 class Hal(object): def __getattr__(self, name): print 'I don\'t have a %s function' % name names = dir(self) # <-- infinite recursion happens here print 'My functions are: %s' % ', '.join(names) exit() def close_door(self): pass x = Hal() x.open_door() 

Here is the output I want:

 I don't have a open_door function My functions are: close_door, __getattr__, __init__, __doc__, ... 

Any other solution that gets me the result I want will work fine. I want to fuzzy match strings in case the function does not exist, in order to try to suggest what the user might mean.

+6
source share
4 answers

Is there a reason you cannot do this?

 names = dir(self.__class__) 

Do you expect consumers to extend Hal instances to their own methods?

if you only want the methods you implemented without inline attachments, you can also try:

 names = [prop for prop in dir(self.__class__) if prop[1] != "_"] 
+2
source
 names = self.__class__.__dict__ 

perhaps?

 >>> class A: ... def hello(self,x): ... print "hello ",x ... def my_dir(self): ... print self.__class__.__dict__ ... >>> A().my_dir() {'__module__': '__main__', 'my_dir': <function my_dir at 0x029A5AB0>, 'hello': < function hello at 0x029A5CB0>, '__doc__': None} 
+2
source

This works, I think:

 import types class Hal(object): def __getattr__(self, name): print ('I don\'t have a %s function' % name) funcs = (name for name,func in self.__class__.__dict__.items() if isinstance(func,types.FunctionType)) #names = dir(self) # <-- infinite recursion happens here print ('My functions are: %s' % ', '.join(str(f) for f in funcs)) exit() @staticmethod def foo(): pass @classmethod def bar(cls): pass def qux(self): pass def close_door(self): pass x = Hal() x.foo = 'bar' x.open_door() 
+2
source

One solution is to create a copy of dir before adding the __getattr__ method:

 class Hal(object): def __init__(self): self._names = dir(self) def __getattr__(self, name): print self.names self.__getattr__ = __getattr__ 

However, for simple cases, you can simply call dir (and similarly getattr , or inspect.getmembers , or something else) in a class object to solve the problem. This does not work if the instance can have methods added after the build, but if this is not a problem, it is easy:

 names = dir(self.__class__) 

However, you get names to filter methods, there are a few things you need to do.

First you can use isinstance on getattr(self, name) and make sure it is a wrapper method (or get the type of the associated version and make sure it is an instance method). If you get the values โ€‹โ€‹directly from self.__class__.__dict__ , you wonโ€™t get the exact same thing as if you got the names in your favorite way and call either getattr(self, name) or getattr(self.__class__, name) In particular, the instance method will display as a function , which is easier to test than the wrapper method. Although some of the other cases are now more difficult to detect.

In any case, nothing based on the type will find things that act as methods, but are not (for example, because you assigned an inline function directly to an object, wrapped something in certain kinds of decorators, descriptors, used a class with the __callable__ method as function, etc.). If you are doing something unusual (or worried that someone might add something fantastic later), you really need to check if you can explicitly bind the element (or fake it by binding to None ), and then check whether the result is callable , and then maybe do additional tests to make sure it gets called correctly (because otherwise you will be fooled by @staticmethod and other similar things). Indeed, if this happens (and you really thought through your design and convinced yourself and at least one more person that this is not crazy ...), you should check everything you can imagine against every case that you have a...

If you want to know if methods are defined in Hal or an instance, and not in an object or another base class, there are several ways to do this, but the easiest is to simply subtract the members of the base classes. (Of course, if you don't need the methods defined in the instance, Hal.__dict__ already has what you want.)

0
source

All Articles