Наконец-то я нашел способ сделать это.
Ключевым моментом является отказ от цели получения экземпляров c с действительным полем pvar , поскольку это невозможно:
Поскольку этота же самая _ init _ () функция (существующая в классе P), которая обрабатывает для создания объектов pvar , невозможно создать pvar в случаях c , который будет указывать на pvar в экземпляре p , чтобы отразить его значение, и это также даст возможность изменить этозначение p pvar каждый раз, когда значение c * pvar будет меняться.Это создает слишком много противоречивых условий для проверки.
Следовательно, поскольку экземпляры c не могут иметь реального поля pvar , лучше всего настроить механизмуправление созданием (с _ setattr _ ) и доступом (с _ getattr _ ) к этим c казалось бы pvar объектов, чтобы создать иллюзию их существования.
class P(object):
def __init__(self,pvar_arg,foo="^^^ "):
self.pvar = pvar_arg
self.cat = foo
def printname(self):
print self.name
class C(P):
def __init__(self,name,pobject,foo=''):
self.__dict__['name'] = name
P.__init__(self,None,pobject.cat+foo)
C.dic[name] = pobject
def __setattr__(self,xn,val):
if xn!='pvar':
self.__dict__[xn] = val
elif self.name in C.dic:
# During the creation of an instance c,
# this condition is False because the instruction
# C.dic[name] = pobject is written after
# P.__init__(self,None,pobject.cat+foo).
# Hence the value of pobject.pvar is preserved,
# not changed with the value val being None
# due to P.__init__(self,None,pobject.cat+foo)
# that provokes self.pvar = pvar_arg and
# consequently a call __setattr__(self,'pvar',None)
C.dic[self.name].pvar = val
def __getattribute__(self,xn):
if xn=='pvar':
return object.__getattribute__(C.dic[self.name],'pvar')
else:
return object.__getattribute__(self,xn)
dic = {}
p1 = P("1")
p2 = P("2","QZX ")
print '--- p1 = P("1") and p2 = P("2","QZX ") executed ---'
print "p1.__dict__ ==",p1.__dict__
print "p2.__dict__ ==",p2.__dict__
print 'p1.pvar==',p1.pvar
print 'p2.pvar==',p2.pvar
c1a = C("c1a",p1,'sea')
c1b = C("c1b",p1,'mountain')
c1c = C("c1c",p1,'desert')
c2a = C("c2a",p2,'banana')
c2b = C("c2b",p2)
c2c = C("c2c",p2,'pear')
print '\n--- creations of c1a, c1b, c1c, c2a, c2b, c2c executed ---'
print "p1.__dict__ ==",p1.__dict__
print "p2.__dict__ ==",p2.__dict__
print "c1a.__dict__ ==",c1a.__dict__
print "c1b.__dict__ ==",c1b.__dict__
print "c1c.__dict__ ==",c1c.__dict__
print "c2a.__dict__ ==",c2a.__dict__
print "c2b.__dict__ ==",c2b.__dict__
print "c2c.__dict__ ==",c2c.__dict__
print 'p1.pvar==',p1.pvar
print 'p2.pvar==',p2.pvar
print '(c1a.pvar, c1b.pvar, c1c.pvar)==',(c1a.pvar,c1b.pvar,c1c.pvar)
print '(c2a.pvar, c2b.pvar, c2c.pvar)==',(c2a.pvar,c2b.pvar,c2c.pvar)
c1a.pvar = "newpvar1"
print '\n--- c1a.pvar = "newpvar1" executed ---'
print 'p1.pvar==',p1.pvar
print 'p2.pvar==',p2.pvar
print '(c1a.pvar, c1b.pvar, c1c.pvar)==',(c1a.pvar,c1b.pvar,c1c.pvar)
print '(c2a.pvar, c2b.pvar, c2c.pvar)==',(c2a.pvar,c2b.pvar,c2c.pvar)
c2c.pvar = 45789
print '\n--- c2c.pvar = 45789 executed ---'
print 'p1.pvar==',p1.pvar
print 'p2.pvar==',p2.pvar
print '(c1a.pvar, c1b.pvar, c1c.pvar)==',(c1a.pvar,c1b.pvar,c1c.pvar)
print '(c2a.pvar, c2b.pvar, c2c.pvar)==',(c2a.pvar,c2b.pvar,c2c.pvar)
result
--- p1 = P("1") and p2 = P("2","QZX ") executed ---
p1.__dict__ == {'cat': '^^^ ', 'pvar': '1'}
p2.__dict__ == {'cat': 'QZX ', 'pvar': '2'}
p1.pvar== 1
p2.pvar== 2
--- creations of c1a, c1b, c1c, c2a, c2b, c2c executed ---
p1.__dict__ == {'cat': '^^^ ', 'pvar': '1'}
p2.__dict__ == {'cat': 'QZX ', 'pvar': '2'}
c1a.__dict__ == {'name': 'c1a', 'cat': '^^^ sea'}
c1b.__dict__ == {'name': 'c1b', 'cat': '^^^ mountain'}
c1c.__dict__ == {'name': 'c1c', 'cat': '^^^ desert'}
c2a.__dict__ == {'name': 'c2a', 'cat': 'QZX banana'}
c2b.__dict__ == {'name': 'c2b', 'cat': 'QZX '}
c2c.__dict__ == {'name': 'c2c', 'cat': 'QZX pear'}
p1.pvar== 1
p2.pvar== 2
(c1a.pvar, c1b.pvar, c1c.pvar)== ('1', '1', '1')
(c2a.pvar, c2b.pvar, c2c.pvar)== ('2', '2', '2')
--- c1a.pvar = "newpvar1" executed ---
p1.pvar== newpvar1
p2.pvar== 2
(c1a.pvar, c1b.pvar, c1c.pvar)== ('newpvar1', 'newpvar1', 'newpvar1')
(c2a.pvar, c2b.pvar, c2c.pvar)== ('2', '2', '2')
--- c2c.pvar = 45789 executed ---
p1.pvar== newpvar1
p2.pvar== 45789
(c1a.pvar, c1b.pvar, c1c.pvar)== ('newpvar1', 'newpvar1', 'newpvar1')
(c2a.pvar, c2b.pvar, c2c.pvar)== (45789, 45789, 45789)
Замечания:
атрибут name должен быть определен до инструкции
P. init (self, None, pobject.cat + foo)
потому что выполнение этой инструкции вызывает
__setattr__(self,'pvar',"1")
, которая сама выполняет инструкцию
C.dic[self.name].pvar = "1"
при выполнении, например,
c1a = C("c1a",p1,'sea')
.
AnHence, этот вызов требует self.name в качестве ключа для dic.
Я ввел foo и cat до
обосновать необходимость написания инструкции
P. init (self, None, pobject.cat + foo)
в противном случае, поскольку в экземплярах c фактически не определено pvar , этот метод не будет полезен.
Существует две ситуациикоторый __setattr__
называется: при создании экземпляра и при изменении атрибутов существующего экземпляра.Когда экземпляр создается, значение pvar экземпляра p должно оставаться неизменным инструкцией C.dic[self.name].pvar = None
.Следовательно, условие elif self.name in C.dic:
Чтобы это условие дало правильный результат, инструкция C.dic[name] = pobject
должна следовать за вызовом P.__init__(self,None,pobject.cat+foo)
.
РЕДАКТИРОВАТЬ 1
Я думаю, что лучше написать
def __setattr__(self,xn,val):
if xn=='pvar':
self.__class__.dic[self.name].pvar = val
, чем
def __setattr__(self,xn,val):
if xn=='pvar':
C.dic[self.name].pvar = val
В первом случае переводчик должен искать ссылкуклассу self C (то есть под именем '_ class _' ) в пространстве имен self.
Во втором случае интерпретатор должен искать ту же ссылку (но под именем 'C' ) в пространстве имен уровня, на котором классы P и C определены.
Это второе пространство имен может быть более большим, чем ограниченное пространство имен экземпляра.В первом случае имя '_ class _' ищется как ключ в словаре, реализующем пространство имен self.Во втором имя 'C' - это ключ, который ищется в словаре уровня, включающего классы P и C .
Идентичность этих двух объектов можно проверить с помощью функции id ()
.
.
EDIT 2
Для объекта dic
существует еще одна возможность: вместо того, чтобы делать его атрибутом класса C , его можно определить во внешней области видимости класса C .Если этот внешний уровень является модулем, то dic является глобальным объектом.
class P(object):
def __init__(self,pvar,foo="^^^ "):
self.pvar = pvar
self.cat = foo
def printname(self):
print self.name
class C(P):
def __init__(self,name,pobject,foo=''):
self.__dict__['name'] = name
P.__init__(self,None,pobject.cat+foo)
dic[name] = pobject
def __setattr__(self,xn,val):
if xn!='pvar':
self.__dict__[xn] = val
elif self.name in dic:
# During the creation of an instance c,
# this condition is False because the instruction
# dic[name] = pobject is written after
# P.__init__(self,None,pobject.cat+foo).
# Hence the value of pobject.pvar is preserved,
# not changed with the value val being None
# due to P.__init__(self,None,pobject.cat+foo)
# that provokes self.pvar = pvar_arg and
# consequently a call __setattr__(self,'pvar',None)
dic[self.name].pvar = val
def __getattribute__(self,xn):
if xn=='pvar':
return object.__getattribute__(dic[self.name],'pvar')
else:
return object.__getattribute__(self,xn)
dic = {}
Результат точно такой же
При этом dic теряет свою природу.
.
.
РЕДАКТИРОВАТЬ 3
Наконец, есть еще один способ: вместо создания иллюзорного атрибута pvar для каждого экземпляра c с помощью функций __setattr__
и __getattribute__
лучше по моему мнению, использовать функцию со словарем dic в качестве аргумента по умолчанию, и это заменит их.
class P(object):
def __init__(self,pvar,foo="^^^ "):
self.pvar = pvar
self.cat = foo
def printname(self):
print self.name
class C(P):
def __init__(self,name,pobject,foo=''):
P.__init__(self,None,pobject.cat+foo)
self.__dict__['name'] = name
del self.pvar
self.pvar(pobject)
def pvar(self,x = None,dic = {}):
if x.__class__==P: # a pobject
dic[self.name] = x
elif x: # a value
dic[self.name].pvar = x
else: # to return value
return dic[self.name].pvar
p1 = P("1")
p2 = P("2","QZX ")
print '--- p1 = P("1") and p2 = P("2","QZX ") executed ---'
print "p1.__dict__ ==",p1.__dict__
print "p2.__dict__ ==",p2.__dict__
print 'p1.pvar==',p1.pvar
print 'p2.pvar==',p2.pvar
c1a = C("c1a",p1,'sea')
c1b = C("c1b",p1,'mountain')
c1c = C("c1c",p1,'desert')
c2a = C("c2a",p2,'banana')
c2b = C("c2b",p2)
c2c = C("c2c",p2,'pear')
print '\n--- creations of c1a, c1b, c1c, c2a, c2b, c2c executed ---'
print "p1.__dict__ ==",p1.__dict__
print "p2.__dict__ ==",p2.__dict__
print "c1a.__dict__ ==",c1a.__dict__
print "c1b.__dict__ ==",c1b.__dict__
print "c1c.__dict__ ==",c1c.__dict__
print "c2a.__dict__ ==",c2a.__dict__
print "c2b.__dict__ ==",c2b.__dict__
print "c2c.__dict__ ==",c2c.__dict__
print 'p1.pvar==',p1.pvar
print 'p2.pvar==',p2.pvar
print '(c1a.pvar(),c1b.pvar(),c1c.pvar())==',(c1a.pvar(),c1b.pvar(),c1c.pvar())
print '(c2a.pvar(),c2b.pvar(),c2c.pvar())==',(c2a.pvar(),c2b.pvar(),c2c.pvar())
c1a.pvar("newpvar1")
print '\n--- c1a.pvar("newpvar1") executed ---'
print 'p1.pvar==',p1.pvar
print 'p2.pvar==',p2.pvar
print '(c1a.pvar(),c1b.pvar(),c1c.pvar())==',(c1a.pvar(),c1b.pvar(),c1c.pvar())
print '(c2a.pvar(),c2b.pvar(),c2c.pvar())==',(c2a.pvar(),c2b.pvar(),c2c.pvar())
c2c.pvar(45789)
print '\n--- c2c.pvar(45789) ---'
print 'p1.pvar==',p1.pvar
print 'p2.pvar==',p2.pvar
print '(c1a.pvar(),c1b.pvar(),c1c.pvar())==',(c1a.pvar(),c1b.pvar(),c1c.pvar())
print '(c2a.pvar(),c2b.pvar(),c2c.pvar())==',(c2a.pvar(),c2b.pvar(),c2c.pvar())
Результаты такие же, только использование c.pvar () немного отличается:
--- p1 = P("1") and p2 = P("2","QZX ") executed ---
p1.__dict__ == {'cat': '^^^ ', 'pvar': '1'}
p2.__dict__ == {'cat': 'QZX ', 'pvar': '2'}
p1.pvar== 1
p2.pvar== 2
--- creations of c1a, c1b, c1c, c2a, c2b, c2c executed ---
p1.__dict__ == {'cat': '^^^ ', 'pvar': '1'}
p2.__dict__ == {'cat': 'QZX ', 'pvar': '2'}
c1a.__dict__ == {'cat': '^^^ sea', 'name': 'c1a'}
c1b.__dict__ == {'cat': '^^^ mountain', 'name': 'c1b'}
c1c.__dict__ == {'cat': '^^^ desert', 'name': 'c1c'}
c2a.__dict__ == {'cat': 'QZX banana', 'name': 'c2a'}
c2b.__dict__ == {'cat': 'QZX ', 'name': 'c2b'}
c2c.__dict__ == {'cat': 'QZX pear', 'name': 'c2c'}
p1.pvar== 1
p2.pvar== 2
(c1a.pvar(),c1b.pvar(),c1c.pvar())== ('1', '1', '1')
(c2a.pvar(),c2b.pvar(),c2c.pvar())== ('2', '2', '2')
--- c1a.pvar("newpvar1") executed ---
p1.pvar== newpvar1
p2.pvar== 2
(c1a.pvar(),c1b.pvar(),c1c.pvar())== ('newpvar1', 'newpvar1', 'newpvar1')
(c2a.pvar(),c2b.pvar(),c2c.pvar())== ('2', '2', '2')
--- c2c.pvar(45789) ---
p1.pvar== newpvar1
p2.pvar== 45789
(c1a.pvar(),c1b.pvar(),c1c.pvar())== ('newpvar1', 'newpvar1', 'newpvar1')
(c2a.pvar(),c2b.pvar(),c2c.pvar())== (45789, 45789, 45789)
Обратите внимание, что в этом последнем коде P экземпляры не могут быть значениями C ', потому что объект передан c Метод .pvar () никогда не будет рассматриваться как значение.