Python hasattr converse

hasattr(obj, attribute) used to check whether an object has a specified attribute, but with an attribute, is there a way to find out where (all) it is defined?

Suppose my code gets the attribute name (or classmethod) as a string, and I want to call classname.attribute , but I don't have the class name.

One solution that comes to my mind is

 def finder(attr): for obj in globals(): try: if globals()[obj].__dict__[attr]: return(globals()[obj]) except: ... 

using:

 class Lime(object): @classmethod def lfunc(self): print('Classic') getattr(finder('lfunc'),'lfunc')() #Runs lfunc method of Lime class 

I am absolutely sure that this is not the best (and even the right way) to do this. Can anyone suggest a better way.

+4
source share
3 answers

It is always "possible." Wether is another story.

A quick and dirty way to do this is to iterate through all the classes sequentially and check if any attributes you have are defined. Of course, this is due to conflicts, and this will give the first class that has such a named attribute. If it exists in more than one, it's up to you what you want:

 def finder(attr): for cls in object.__subclasses__(): if hasattr(cls, attr): return cls raise ValueError 

Instead of searching in "globals", it searches for all subclasses of "object" - so the classes that should be found should not be in the module namespace where the finder function is.

If your methods are unique in the set of classes you are looking for, perhaps you can just collect a mapping of all the methods and use them to call them.

Suppose all your inehrit classes are from a class named "Base":

 mapper = {attr_name:getattr(cls, attr_name) for cls in base.__subclasses__() for attr_name, obj in cls.__dict__.items() if isinstance(obj, classmethod) } 

And you call them using mapper['attrname']()

This avoids a linear search every time the method is called, and therefore will be much better.

- EDIT -

__subclassess__ just find direct subclasses of the class, not the inheritance tree, so it will not be useful in "real life" - it may be in the specific case, which has OP in its hands.
If you need to find things in the inheritance tree, you must also review each subclass.

As for the old-style classes: this, of course, will not work - this is one of the motives for which, by default, they are applied differently in the new code.

As with attributes other than the class: they can only be found to test instances anyway, so you need to think about a different method - here, apparently, is not an OP problem

+4
source

This can help:

 import gc def checker(checkee, maxdepth = 3): def onlyDict(ls): return filter(lambda x: isinstance(x, dict), ls) collection = [] toBeInspected = {} tBI = toBeInspected gc.collect() for dic in onlyDict(gc.get_referrers(checkee)): for item, value in dic.iteritems(): if value is checkee: collection.append(item) elif item != "checker": tBI[item] = value def _auxChecker(checkee, path, collection, checked, current, depth): if current in checked: return checked.append(current) gc.collect() for dic in onlyDict(gc.get_referents(current)): for item, value in dic.iteritems(): currentPath = path + "." + item if value is checkee: collection.append(currentPath) else: try: _auxChecker(checkee, currentPath, collection, checked, value, depth + 1) if depth < maxdepth else None except TypeError: continue checked = [] for item, value in tBI.iteritems(): _auxChecker(checkee, item, collection, checked, value, 1) return collection 

How to use:

 referrer = [] class Foo: pass noo = Foo() bar = noo import xml import libxml2 import sys import os op = os.path xml.foo = bar foobar = noo for x in checker(foobar, 5): try: y= eval(x) referrer.append(x) except: continue del x, y 

ps: the attributes of the verifier will not be additionally checked, for recursive or nested links to the check itself.

+2
source

This should work under any circumstances, but it requires a lot of testing:

 import inspect import sys def finder(attr, classes=None): result = [] if classes is None: # get all accessible classes classes = [obj for name, obj in inspect.getmembers( sys.modules[__name__])] for a_class in classes: if inspect.isclass(a_class): if hasattr(a_class, attr): result.append(a_class) else: # we check for instance attributes if hasattr(a_class(), attr): result.append(a_class) try: result += finder(attr, a_class.__subclasses__()) except: # old style classes (that don't inherit from object) do not # have __subclasses; not the best solution though pass return list(set(result)) # workaround duplicates def main(attr): print finder(attr) return 0 if __name__ == "__main__": sys.exit(main("some_attr")) 
+1
source

All Articles