помощь с наследованием python

#python #django

#python #django

Вопрос:

Задан произвольный объект:

 class Val(object):
    def __init__(self):
        this_val = 123
  

Я хочу создать абстрактный базовый класс, у которого есть атрибут, который является Val() :

 class A(object):
    foo = Val()
  

Я ожидал бы, что когда мои дети наследуют от этого класса, они получат копии Val() . Например:

 class B(A):
    pass
class C(A):
    pass
  

Я бы ожидал следующего поведения:

 >>> b = B()
>>> c = C()
>>> c.foo.this_val = 456
>>> b.foo.this_val
123
  

Но вместо этого я получаю:

 >>> b.this_val
456
  

Я понимаю, что я мог бы просто self.foo = Val() использовать init для достижения такого поведения, но у меня есть требование, чтобы foo оставался атрибутом (это менеджер моделей в django). Кто-нибудь может предложить обходной путь для этого?

РЕДАКТИРОВАТЬ: мне действительно нужно иметь доступ к значению в качестве атрибута класса, поэтому мое желаемое поведение:

 >>> C.foo.this_val = 456
>>> B.foo.this_val
123
  

Ответ №1:

Атрибут foo существует только на A . Вам придется использовать метакласс для добавления нового Val к каждому классу.

 class Val(object):
    def __init__(self):
        self.this_val = 123

class MC(type):
  def __init__(self, name, bases, d):
    super(MC, self).__init__(name, bases, d)
    self.foo = Val()

class A(object):
  __metaclass__ = MC

class B(A):
  pass

B.foo.this_val = 456
print A.foo.this_val
print B.foo.this_val
  

Ответ №2:

Возможно, использование дескриптора соответствовало бы вашим требованиям:

 class Val(object):
    def __init__(self):
        self.this_val = 123

class ValDesc(object):
    def __init__(self):
        self.cls_lookup = {}

    def __get__(self, obj, objtype=None):
        return self.cls_lookup.setdefault(objtype, Val())

class A(object):
    foo = ValDesc()

class B(A):
    pass
class C(A):
    pass
  

Теперь, если вы убедитесь, что ни для одного из ваших объектов не установлен атрибут экземпляра «foo», у них будет атрибут класса, индивидуальный для каждого подкласса:

 b = B()
c = C()
cc = C()
c.foo.this_val = 456
print c.foo.this_val   # 456
print cc.foo.this_val  # 456
print b.foo.this_val   # 123
  

РЕДАКТИРОВАТЬ: С помощью правки, которую я сделал несколько часов назад, изменив ключ в __get__ на быть objtype вместо obj.__class__ , это также работает при прямом доступе к атрибутам класса:

 print B.foo.this_val   # 123
print C.foo.this_val   # 456
  

Ответ №3:

Сделайте оба.

Сделайте это атрибутом класса, но также инициализируйте его для нового экземпляра в __init__ функции. Таким образом, сохраненная ссылка не является общей.

Комментарии:

1. Однако мне нужно ссылаться на него как на атрибут. Я хочу сделать C.foo.this_val и B.foo.this_val и получить разные результаты. Извините, если это было непонятно. У меня нет экземпляра : (

2. Тогда переопределите это в определениях отдельных классов?

3. Я действительно надеялся, что этого не произойдет. Должен быть какой-то неясный частный метод python, который я могу переопределить для достижения этого?

4. Э, даже если бы это было, это было бы сложнее, чем просто переопределить его в defs класса…