简体   繁体   English

如何仅获取父类对象的属性

[英]How to get attributes of parent class object only

I have 2 classes: 我有2节课:

class Parent(object):
    def __init__(self, id, name):
        self.id = id
        self.name = name
        self.__parent_vars = ['id', 'name']  # make a copy

    def print_values(self):
        res = {}
        for el in self.__parent_vars:
            res[el] = vars(self)[el]
        return res


class Child(Parent):
    def __init__(self, id, name, last_name, age):
        Parent.__init__(self, id, name)
        self.last_name = last_name
        self.age = age

What I want to do - is to get from Child parameters of Parent class. 我想做的-是从Parent类的Child参数获取的。 I made it using additional variable and it works, but I need more elegant solution without additional variable. 我使用附加变量使它生效,但是我需要没有附加变量的更优雅的解决方案。 I need it for pickle class. 我上泡菜课需要它。 If I create additional variable it breaks my Schemas in a big project. 如果我创建其他变量,它将破坏一个大项目中的架构。

I try to find something like this: 我试图找到这样的东西:

c = Child(12,"Foo","whatever",34)
vars(c.super())

with expected output: 具有预期的输出:

{'id': 12, 'name': 'Foo'}

I found this question: Get attributibutes in only base class (Python) but it has significant difference of mine, so I can't use that solution. 我发现了这个问题: 仅在基类(Python)中获得属性,但是它与我的有很大的不同,所以我不能使用该解决方案。

I am afraid you cannot easily. 恐怕你不容易。 In Python, classes only carry methods and static attributes. 在Python中,类仅包含方法和静态属性。 Non static attributes are commonly stored in the __dict__ attribute of the objects. 非静态属性通常存储在对象的__dict__属性中。 That means that except in special cases, you cannot easily know which attributes where assigned in a parent class method, in a child class method or even outside any method. 这意味着,除非在特殊情况下,否则您不容易知道在父类方法,子类方法甚至任何方法之外分配了哪些属性。

I can only imagine a meta_class that would instrument the __init__ method to store which attributes were changed during its call: 我只能想象一个meta_class可以检测__init__方法来存储在调用期间更改了哪些属性:

import collections
import functools
import inspect

class Meta_attr(type):
    init_func = {}
    attrs = collections.defaultdict(set)

    def __new__(cls, name, bases, namespace, **kwds):
        c = type.__new__(cls, name, bases, namespace, **kwds)
        cls.init_func[c] = c.__init__
        @functools.wraps(c.__init__)
        def init(self, *args, **kwargs):
            before = set(self.__dict__.keys())
            cls.init_func[c](self, *args, **kwargs)
            after = set(self.__dict__.keys())
            cls.attrs[c].update(after.difference(before))
        init.__signature__ = inspect.signature(c.__init__)
        c.__init__ = init
        return c

class Parent(object, metaclass=Meta_attr):
    def __init__(self, id, name):
        self.id = id
        self.name = name

    def print_values(self):
        res = {}
        for el in Meta_attr.attrs[Parent]:
            res[el] = vars(self)[el]
        return res


class Child(Parent):
    def __init__(self, id, name, last_name, age):
        Parent.__init__(self, id, name)
        self.last_name = last_name
        self.age = age

It gives: 它给:

>>> c = Child(1,"a","b", 20)
>>> c.print_values()
{'id': 1, 'name': 'a'}

BEWARE : if an attribute is set outside of the __init__ method, it will not be registered by this meta class... 注意 :如果在__init__方法之外设置了属性,则此元类将不会注册该属性...

I found one more solution. 我找到了另一个解决方案。 It looks simplier, so I used it. 看起来比较简单,所以我用了。 It based on using Marshmallow Schemas. 它基于使用棉花糖模式。 Also It is more usiful in my project because I already used marshmallow Schemas. 另外,在我的项目中它更有用,因为我已经使用了棉花糖模式。 The idea: I create 2 classes and 2 different Schemas. 这个想法:我创建2个类和2个不同的模式。 And can serialize bigger class (Child) using just Parent schema: 并且可以仅使用父模式来序列化更大的类(子级):

Code

Define 2 classes: 定义2个类别:

class Parent(object):
    def __init__(self):
        self.id = 'ID'
        self.name = 'some_name'

class Child(Parent):
    def __init__(self):
        Parent.__init__(self)
        self.last_name = 'last_name'
        self.age = 15

from marshmallow import Schema, fields, EXCLUDE

Define 2 Schemas: 定义2个模式:

class ParentSchema(Schema):
    ba = Parent()
    id = fields.Str(missing=ba.id)
    name = fields.Str(missing=ba.name)

class ChildSchema(Schema):
    ba = Child()
    id = fields.Str(missing=ba.id)
    name = fields.Str(missing=ba.name)

    last_name = fields.Str(missing=ba.last_name)
    age = fields.Int(missing=ba.age)

use it to get only Parent attributes for Child object: 使用它仅获取Child对象的Parent属性:

user_data = {'id':'IDIDID', 'name':'add_name', 'last_name':'FAMILIYA'}
res = ParentSchema().load(user_data, unknown=EXCLUDE)

# output:
res
{'name': 'add_name', 'id': 'IDIDID'}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM