Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/python-3.x/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 使用vars()仅检索自己的属性_Python_Python 3.x_Class_Attributes - Fatal编程技术网

Python 使用vars()仅检索自己的属性

Python 使用vars()仅检索自己的属性,python,python-3.x,class,attributes,Python,Python 3.x,Class,Attributes,在python中,vars()检索对象的所有属性。对于从其他类派生的类的实例,是否有一种方便的方法过滤掉“继承的”属性?我这样做的目的是仅在自己的属性上定义\uuuu eq\uu比较 根据我的理解,这些属性不是继承的,而是直接存在于对super()的调用的实例中。\uu init\uu(),因此不会有内置的分离机制 class Base: def __init__(self): self.a = 0 class Derived(Base): def __ini

在python中,
vars()
检索对象的所有属性。对于从其他类派生的类的实例,是否有一种方便的方法过滤掉“继承的”属性?我这样做的目的是仅在自己的属性上定义
\uuuu eq\uu
比较

根据我的理解,这些属性不是继承的,而是直接存在于对
super()的调用的实例中。\uu init\uu()
,因此不会有内置的分离机制

class Base:
    def __init__(self):
        self.a = 0


class Derived(Base):
    def __init__(self):
        super().__init__()
        self.b = 1


derived = Derived()

# results in {'a': 0, 'b': 1}
# how can I make this return {'b': 1}?
print(vars(derived))
我当前的解决方案可行,但需要为每个类定义它:

class Derived(Base):
    def __init__(self):
        super().__init__()
        pre_init_attrs = set(vars(self).keys())
        # own init
        self.b = 1

        # process own init
        post_init_attrs = set(vars(self).keys())
        self._own_attrs = post_init_attrs.difference(pre_init_attrs)

    def vars(self):
        return {key: self.__dict__[key] for key in self._own_attrs}

有没有一种方法可以通过修饰符或元类来实现这一点?

您所要求的与Python中类的工作方式不太一样

vars
已经从基类中过滤出继承的属性

但是
self.a
不是继承的。它被显式地添加到您的
self
实例中,因为您的
\uuu init\uu
显式地调用
super()。如果您的
\uuu init\uuu
调用了
self.addx()
,并且
派生的.addx
方法执行了
self.x=0
,那么该调用实际上没有什么特别之处,它的工作方式与您在这里所做的完全相同

你可以写一个装饰师来做你想做的事,但也许退一步更好

为什么不存储希望每个类作为类的一部分提供的字段列表

或者,既然您似乎试图模拟更像Java风格的类,其中每个类的属性集都是固定的,那么为什么不直接使用
@dataclass
(或者,如果您需要3.7之前的兼容性或额外功能,则使用第三方
@attr.s
)呢?这会自动记录哪些字段属于哪个类,以及与之相关的许多其他事情

>>> from dataclasses import dataclass, fields
>>> 
>>>> @dataclass
... class Base:
...     a: int = 0
... 
>>> @dataclass
... class Derived(Base):
...     b: int = 1
...
>>> derived = Derived()
>>> derived
Derived(a=0, b=1)
>>> def ownfields(obj):
...     fs = fields(obj)
...     for base in type(obj).__bases__:
...         basefs = set(fields(base))
...         fs = [f for f in fs if f not in basefs]
...     return fs
...
>>> ownfields(derived)
[Field(name='b',type=<class 'int'>,default=1,default_factory=<dataclasses._MISSING_TYPE object at 0x10571ca58>,init=True,repr=True,hash=None,compare=True,metadata=mappingproxy({}),_field_type=_FIELD)]
>>> def ownvars(obj):
...     return {field.name: getattr(obj, field.name) for field in ownfields(obj)}
...
>>> ownvars(derived)
{'b': 1}

例如,如果您从多个类继承,而这些类本身不是数据类,但都是以菱形模式从数据类继承,那么这仍然不起作用。我不确定在这种情况下,预期的行为是什么。可能只需遵循
类型(obj).mro()[1://code>?这不会比其他任何事情更令人惊讶,而且它似乎是与查找最一致的并行…

感谢您给我指出ATTR;我听说过数据类,但代码库是3.7之前的版本。注意,我已经知道“继承的”属性不是继承的,而是直接在派生实例上定义的。我提到“继承的”属性(带引号)作为引用这些属性的一种方式,而不是“从派生实例中对基初始值设定项的调用中定义的属性”@LemonPi Right;关键是,跟踪属性可能比动态计算属性更好,至少如果您可以通过使用类似于
@dataclass
@attr.s
\uuu slots\uuu
的方法进一步利用相同的信息,我想在这种情况下您可以这样做。
>>> def ownfields(obj):
...     fs = fields(obj)
...     for base in type(obj).__bases__:
...         try:
...             basefs = set(fields(base))
...         except TypeError:
...             pass
...         else:
...             fs = [f for f in fs if f not in basefs]
...     return fs