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我非常确定这不是最好的(甚至是正确的方式)。有没有人能提供一个更好的方法。
发布于 2013-04-17 01:25:17
它总是“可能的”。这是否可取是另一回事。
一种快速而肮脏的方法是对所有类进行线性迭代,并检查是否定义了您拥有的属性。当然,这会受到冲突的影响,并且它将产生第一个具有这样一个命名属性的类。如果它存在于多个数据库中,则由您决定要使用哪一个:
def finder(attr):
for cls in object.__subclasses__():
if hasattr(cls, attr):
return cls
raise ValueError而不是搜索“全局”,这将搜索"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手中的特定情况下。
如果需要在继承树中查找对象,还需要递归遍历每个子类。
至于旧式类:当然这是行不通的--这是它们在新代码中被默认破坏的动机之一。
至于非类属性:它们只能在检查实例时才能找到-所以必须考虑另一种方法-似乎不是这里的操作人员所关心的问题。
发布于 2013-04-17 01:24:09
这可能会有所帮助:
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, yps:对于对checkee本身的递归或嵌套引用,将不会进一步检查checkee的属性。
发布于 2013-04-17 01:39:46
这应该在所有情况下都可以工作,但仍然需要进行大量测试:
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"))https://stackoverflow.com/questions/16042880
复制相似问题