Python 有没有一种方法可以访问包含基类的dict(或类似的东西)?

Python 有没有一种方法可以访问包含基类的dict(或类似的东西)?,python,attributes,Python,Attributes,假设我们有以下类层次结构: class ClassA: @property def foo(self): return "hello" class ClassB(ClassA): @property def bar(self): return "world" 如果我像这样在ClassB上探索\uuuu dict\uuu,我只会看到bar属性: for name,_ in ClassB.__dict__.items(): if name.start

假设我们有以下类层次结构:

class ClassA:

    @property
    def foo(self): return "hello"

class ClassB(ClassA):

    @property
    def bar(self): return "world"
如果我像这样在ClassB上探索\uuuu dict\uuu,我只会看到bar属性:

for name,_ in ClassB.__dict__.items():

    if name.startswith("__"):
        continue

    print(name)
输出为巴

我可以使用自己的方法来获取指定类型的属性,也可以获取其祖先的属性。然而,我的问题是python中是否已经有一种方法可以让我在不重新发明轮子的情况下做到这一点

def return_attributes_including_inherited(type):
    results = []
    return_attributes_including_inherited_helper(type,results)
    return results

def return_attributes_including_inherited_helper(type,attributes):

    for name,attribute_as_object in type.__dict__.items():

        if name.startswith("__"):
            continue

        attributes.append(name)

    for base_type in type.__bases__:
        return_attributes_including_inherited_helper(base_type,attributes)
按如下方式运行我的代码

for attribute_name in return_attributes_including_inherited(ClassB):
    print(attribute_name)
。。。返回bar和foo

请注意,我正在简化一些事情:名称冲突,在本例中我可以使用dict时使用items(),跳过以_u开头的任何内容,忽略两个祖先本身有一个共同祖先的可能性,等等

EDIT1-我试图保持示例的简单性。但是我确实需要每个类和祖先类的属性名和属性引用。下面的一个答案让我走上了一条更好的道路,我会在它开始工作时发布一些更好的代码

EDIT2-这是我想要的,非常简洁。这是基于以下Eli的回答

def get_attributes(type):

    attributes = set(type.__dict__.items())

    for type in type.__mro__:
        attributes.update(type.__dict__.items())

    return attributes
它同时返回属性名及其引用

EDIT3-以下答案之一建议使用inspect.getmembers。这看起来非常有用,因为它就像dict一样,只对祖先类进行操作

由于我尝试做的大部分工作是查找用特定描述符标记的属性,并包括祖先类,因此下面是一些代码,可以帮助您完成这项工作,以防它对任何人都有帮助:

class MyCustomDescriptor:

    # This is greatly oversimplified

    def __init__(self,foo,bar):
        self._foo = foo
        self._bar = bar
        pass

    def __call__(self,decorated_function):
        return self

    def __get__(self,instance,type):

        if not instance:
            return self

        return 10

class ClassA:

    @property
    def foo(self): return "hello"

    @MyCustomDescriptor(foo="a",bar="b")
    def bar(self): pass

    @MyCustomDescriptor(foo="c",bar="d")
    def baz(self): pass

class ClassB(ClassA):

    @property
    def something_we_dont_care_about(self): return "world"

    @MyCustomDescriptor(foo="e",bar="f")
    def blah(self): pass

# This will get attributes on the specified type (class) that are of matching_attribute_type.  It just returns the attributes themselves, not their names.
def get_attributes_of_matching_type(type,matching_attribute_type):

    return_value = []

    for member in inspect.getmembers(type):

        member_name = member[0]
        member_instance = member[1]

        if isinstance(member_instance,matching_attribute_type):
            return_value.append(member_instance)

    return return_value

# This will return a dictionary of name & instance of attributes on type that are of matching_attribute_type (useful when you're looking for attributes marked with a particular descriptor)
def get_attribute_name_and_instance_of_matching_type(type,matching_attribute_type):

    return_value = {}

    for member in inspect.getmembers(ClassB):

        member_name = member[0]
        member_instance = member[1]

        if isinstance(member_instance,matching_attribute_type):
            return_value[member_name] = member_instance

    return return_value
您要使用:

您要使用:


遗憾的是,没有一个复合对象。(普通)python对象的每个属性访问首先检查
obj.\uuu dict\uuu
,然后检查其所有基类的属性;虽然有一些内部缓存和优化,但没有一个对象可以访问

也就是说,可以改进代码的一件事是使用
cls.\uuuuMRO\uuuuuuu
而不是
cls.\uuuuuuu bases\uuuuuuu
。。。而不是类的直接父级,
cls.\uuuu mro\uuuu
包含类的所有祖先,按照Python搜索的确切顺序,所有公共祖先只出现一次。这也将允许您的类型搜索方法是非递归的。松散地

def get_attrs(obj):
    attrs = set(obj.__dict__)
    for cls in obj.__class__.__mro__:
        attrs.update(cls.__dict__)
    return sorted(attrs)

。。。对默认的
dir(obj)
实现进行了合理的近似。

遗憾的是,没有一个复合对象。(普通)python对象的每个属性访问首先检查
obj.\uuu dict\uuu
,然后检查其所有基类的属性;虽然有一些内部缓存和优化,但没有一个对象可以访问

也就是说,可以改进代码的一件事是使用
cls.\uuuuMRO\uuuuuuu
而不是
cls.\uuuuuuu bases\uuuuuuu
。。。而不是类的直接父级,
cls.\uuuu mro\uuuu
包含类的所有祖先,按照Python搜索的确切顺序,所有公共祖先只出现一次。这也将允许您的类型搜索方法是非递归的。松散地

def get_attrs(obj):
    attrs = set(obj.__dict__)
    for cls in obj.__class__.__mro__:
        attrs.update(cls.__dict__)
    return sorted(attrs)

。。。与默认的
dir(obj)
实现相当接近。

您应该使用python的
inspect
模块来实现任何此类内省功能

.
.
>>> class ClassC(ClassB):
...     def baz(self):
...         return "hiya"
...
>>> import inspect
>>> for attr in inspect.getmembers(ClassC):
...   print attr
... 
('__doc__', None)
('__module__', '__main__')
('bar', <property object at 0x10046bf70>)
('baz', <unbound method ClassC.baz>)
('foo', <property object at 0x10046bf18>)
。
.
>>>C类(B类):
...     def baz(自我):
...         返回“你好”
...
>>>进口检验
>>>对于inspect.getmembers(ClassC)中的attr:
...   打印属性
... 
(“文件”,无)
(“模块”、“主模块”)
(‘酒吧’,)
(‘baz’,)
(‘foo’,)

阅读有关
inspect
模块的更多信息。

对于任何此类内省功能,您应该使用python的
inspect
模块

.
.
>>> class ClassC(ClassB):
...     def baz(self):
...         return "hiya"
...
>>> import inspect
>>> for attr in inspect.getmembers(ClassC):
...   print attr
... 
('__doc__', None)
('__module__', '__main__')
('bar', <property object at 0x10046bf70>)
('baz', <unbound method ClassC.baz>)
('foo', <property object at 0x10046bf18>)
。
.
>>>C类(B类):
...     def baz(自我):
...         返回“你好”
...
>>>进口检验
>>>对于inspect.getmembers(ClassC)中的attr:
...   打印属性
... 
(“文件”,无)
(“模块”、“主模块”)
(‘酒吧’,)
(‘baz’,)
(‘foo’,)

阅读更多关于
inspect
模块的信息。

这是我当年编写的一个函数。最好的答案是使用
inspect
模块,因为使用
\uuuuuu dict\uuuuuu
为我们提供了所有函数(我们的+继承的)和(所有?)数据成员和属性。其中,
inspect
为我们提供了足够的信息来剔除我们不想要的东西

def _inspect(a, skipFunctionsAlways=True, skipMagic = True):
    """inspects object attributes, removing all the standard methods from 'object',
    and (optionally) __magic__ cruft.

    By default this routine skips __magic__ functions, but if you want these on
    pass False in as the skipMagic parameter.

    By default this routine skips functions, but if you want to see all the functions,
    pass in False to the skipFunctionsAlways function. This works together with the
    skipMagic parameter: if the latter is True, you won't see __magic__ methods.
    If skipFunctionsAlways = False and skipMagic = False, you'll see all the __magic__
    methods declared for the object - including __magic__ functions declared by Object

    NOT meant to be a comprehensive list of every object attribute - instead, a
    list of every object attribute WE (not Python) defined. For a complete list
    of everything call inspect.getmembers directly"""

    objType = type(object)
    def weWantIt(obj):
        #return type(a) != objType
        output= True
        if (skipFunctionsAlways):
            output = not ( inspect.isbuiltin(obj) ) #not a built in 

        asStr = ""
        if isinstance(obj, types.MethodType):
            if skipFunctionsAlways:  #never mind, we don't want it, get out.
                return False
            else:
                asStr = obj.__name__
                #get just the name of the function, we don't want the whole name, because we don't want to take something like:
                #bound method LotsOfThings.bob of <__main__.LotsOfThings object at 0x103dc70>
                #to be a special method because it's module name is special
                #WD-rpw 02-23-2008

                #TODO: it would be great to be able to separate out superclass methods
                #maybe by getting the class out of the method then seeing if that attribute is in that class?
        else:
            asStr = str(obj)

        if (skipMagic):
            output = (asStr.find("__") == -1 ) #not a __something__

        return (output)

    for value in inspect.getmembers( a, weWantIt ):
        yield value
def\u检查(a,skipFunctionsAlways=True,skipMagic=True):
“”“检查对象属性,从“对象”中删除所有标准方法,
和(可选)魔术克鲁夫特。
默认情况下,此例程跳过_; magic __;函数,但如果您希望启用这些函数
将False作为skipMagic参数传入。
默认情况下,此例程跳过函数,但如果要查看所有函数,
将False传递给skipFunctionsAlways函数。这与
skipMagic参数:如果后者为True,则不会看到_魔法___)方法。
如果skipFunctionsAlways=False和skipMagic=False,您将看到所有的魔法__
为对象声明的方法-包括由对象声明的_magic____)函数
不是指每个对象属性的综合列表,而是
我们(不是Python)定义的每个对象属性的列表
对于所有内容,直接调用inspect.getmembers“”
对象类型=类型(对象)
def weWantIt(obj):
#返回类型(a)!=对象类型
输出=真
如果(skipFunctionsAlways):
输出=非(inspect.isbuiltin(obj))#非内置
asStr=“”
如果isinstance(对象,类型.方法类型):
如果SkipFunctionsallways:#没关系,我们不想要它,滚出去。
返回错误
其他:
asStr=对象名称__
#只获取函数的名称,我们不需要完整的名称,因为我们不希望获取类似以下内容:
#的绑定方法LotsOfThings.bob
#是一个特殊的方法,因为它的模块名是特殊的