#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 класса…