python:наследование атрибутов/переменных класса с полиморфизмом?

В моих начинаниях в качестве ученика python я недавно застрял на некотором странном (с моей точки зрения) поведении, если я пытался работать с атрибутами класса. Я не жалуюсь, но был бы признателен за полезные комментарии, которые прольют свет на этот вопрос.

Чтобы сократить сложный вопрос до более краткого, я бы сформулировал его так:

Каков "питонический" способ обеспечить, чтобы атрибут класса вел себя более похоже на статическую переменную в дереве наследования?

Мне кажется, что атрибут класса ведет себя как значение по умолчанию "copy on read" с полиморфными характеристиками. Пока я выполняю операции "только для чтения", он остается "синглтоном", но как только я обращаюсь к классу-атрибуту с присваиванием через производный класс или экземпляр, он превращается в новую ссылку, теряя связь с унаследованной базовой ссылкой.

(У этого есть потенциал для некоторых интересных возможностей, но вы должны понять это, чтобы

class A(object):
    classvar = 'A'
    def setclassvar(self, value):
        A.classvar = value                   
    def __str__(self):
        return "%s id(%s) " %(A.classvar, hex(id(A.classvar))[2:-1].upper())

class A1(A):
    pass

class B(object):
    classvar = 'B'
    def setclassvar(self, value):
        self.__class__.classvar = value            
    def __str__(self):
        cvar = self.__class__.classvar
        return "%s id(%s) " %(cvar, hex(id(cvar))[2:-1].upper())

class B1(B):
    def setclassvar(self, value):
        self.__class__.classvar = value

a, a1 = A(), A1()
a1.setclassvar('a')
print "new instance A: %s" %a
print "new instance A1: %s" %a

b, b1 = B(), B1()
b1.setclassvar('bb')
print "new instance B: %s" %b
print "new instance B1: %s" %b1

a1.setclassvar('aa')
print "new value a1: %s" %a
print "new value a: %s" %a

a1.classvar = 'aaa'
print "direct access a1: %s id(%s)" %(a1.classvar, hex(id(a1.classvar))[2:-1].upper())
print "method access a1: %s" %a1
print "direct access a: %s" %a

получается следующее:

новый экземпляр A: a id(B73468A0) 
новый экземпляр A1: a id(B73468A0) 
новый экземпляр B: B id(B73551C0) 
новый экземпляр B1: bb id(AD1BFC) 
новое значение a1: aa id(AD1BE6) 
новое значение a: aa id(AD1BE6) 
прямой доступ a1: aa id(A3A494)
метод доступа a1: aa id(AD1BE6) 
прямой доступ a: aa id(AD1BE6)

Таким образом, либо прямой (присваивающий) доступ object.classvar, либо опосредованный через self.__class__.classvar - это не то же самое, что BASECLASS.classvar.

Является ли это проблемой области видимости или чем-то совершенно другим.

Жду ваших ответов и заранее спасибо. :-)


Edit: Был ответ на очень короткое время, предлагающий использовать дескрипторы классов, например: Как сделать свойство класса?.

К сожалению, это не работает:

class Hotel(Bar):
    def __init__(self):        
        Hotel.bar += 1

hotel = Hotel()
assert hotel.bar == 51
assert hotel.bar == foo.bar

Второе утверждение не срабатывает! hotel.bar не ссылается на тот же объект, что и foo.bar, а hotel.bar ссылается на что-то другое, чем Hotel.bar!


2-е редактирование: Я прекрасно понимаю, что синглтоны считаются "антипаттерном", и я не собирался их использовать (широко). Поэтому я не упоминал их в вопросе. Несмотря на то, что существует множество решений, обсуждающих и предлагающих решения с синглтонами и о синглтонах, мой вопрос остается: Почему класс-переменная может так легко отсоединить свою ссылку? Ruby ведет себя более естественно для меня: http://snippets.dzone.com/posts/show/6649

7
задан Community 23 May 2017 в 12:30
поделиться