Как получить атрибуты только родительского объекта класса - PullRequest
3 голосов
/ 04 июля 2019

У меня есть 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

Что я хочу сделать - это получить из Child параметры класса Parent. Я сделал это, используя дополнительную переменную, и она работает, но мне нужно более элегантное решение без дополнительной переменной. Мне нужно это для класса рассола. Если я создаю дополнительную переменную, это нарушает мои схемы в большом проекте.

Я пытаюсь найти что-то вроде этого:

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

с ожидаемым результатом:

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

Я нашел этот вопрос: Получить атрибуты только в базовом классе (Python) , но у меня есть существенная разница, поэтому я не могу использовать это решение.

1 Ответ

1 голос
/ 04 июля 2019

Боюсь, вы не можете легко.В Python классы содержат только методы и статические атрибуты.Нестатические атрибуты обычно хранятся в атрибуте __dict__ объектов.Это означает, что за исключением особых случаев, вы не можете легко узнать, какие атрибуты были назначены в методе родительского класса, в методе дочернего класса или даже вне какого-либо метода.

Я могу только представить себе мета-класс, который бы использовал метод __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

Это дает:

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

ВНИМАНИЕ : если атрибут установлен вне метода __init__, он не будет зарегистрирован этим мета-классом ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...