hasattr(obj, attribute)
用于检查一个对象是否具有指定的属性,但是给定一个属性是否有办法知道它定义在哪里(全部)?
假设我的代码将属性(或类方法)的名称作为字符串获取,我想调用classname.attribute
但我没有类名。
我想到的一个解决方案是
def finder(attr):
for obj in globals():
try:
if globals()[obj].__dict__[attr]:
return(globals()[obj])
except:
...
用法:
class Lime(object):
@classmethod
def lfunc(self):
print('Classic')
getattr(finder('lfunc'),'lfunc')() #Runs lfunc method of Lime class
我很确定这不是最好的(甚至是正确的方法)。有人可以提供更好的方式。
答案 0 :(得分:4)
总是“可能”。另一个历史是可取的。
快速而肮脏的方法是在所有类上线性迭代,并检查是否有任何定义属性。当然,这会受到冲突的影响,并且会产生具有这种命名属性的第一个类。如果它存在于多个中,则由您自行决定您想要的内容:
def finder(attr):
for cls in object.__subclasses__():
if hasattr(cls, attr):
return cls
raise ValueError
不是搜索“globals”,而是搜索“object”的所有子类 - 因此要找到的类不需要位于finder
函数所在的模块的名称空间中。
如果你的方法在你正在搜索的一组类中是唯一的,那么你可能只是组装所有方法的映射并用它来代替它们。
让我们假设你的所有类都来自名为“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) }
你用mapper['attrname']()
这避免了在每次方法调用时进行线性搜索,因此会更好。
- 编辑 -
__subclassess__
只是找到一个类的直接子类,而不是继承树 - 所以它在“现实生活”中不会有用 - 也许它是OP掌握的具体情况。<登记/>
如果需要在继承树中查找内容,则还需要对每个子类进行递归。
对于旧式的课程:当然这不起作用 - 这是在新代码中默认打破它们的动机之一。
至于非类属性:它们只能被发现检查实例 - 所以必须考虑另一种方法 - 这似乎不是O.P.的关注点。
答案 1 :(得分:2)
这可能会有所帮助:
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
使用方法:
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:对于checkee本身的递归或嵌套引用,不会进一步检查checkee的属性。
答案 2 :(得分:1)
这应该适用于所有情况,但仍需要进行大量测试:
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"))