Python 作文:为什么是;“容器实例”;当“时,属性未更新”;“包含实例”;你变了吗?
我想更好地理解容器对象属性和包含对象属性之间的关系 我想了解这个示例的输出: 我创建了一辆高级轿车和一个高级轮胎。Python 作文:为什么是;“容器实例”;当“时,属性未更新”;“包含实例”;你变了吗?,python,class,oop,composition,python-descriptors,Python,Class,Oop,Composition,Python Descriptors,我想更好地理解容器对象属性和包含对象属性之间的关系 我想了解这个示例的输出: 我创建了一辆高级轿车和一个高级轮胎。 Tire还有一个属性age,应该“指向”名为bmw的汽车实例的属性。 因此,我认为通过更改bmw实例的属性,倍耐力属性age也应该更新,因为它引用了相同的变量。从示例中可以看出,情况并非如此 我怎样才能真正更新它呢? 我计划多次使用作文,所以在最后一节课上使用它是非常不切实际的 finalInstance.age=先前的instances.tire.car.age class Ca
Tire还有一个属性age,应该“指向”名为bmw的汽车实例的属性。 因此,我认为通过更改bmw实例的属性,倍耐力属性age也应该更新,因为它引用了相同的变量。从示例中可以看出,情况并非如此 我怎样才能真正更新它呢? 我计划多次使用作文,所以在最后一节课上使用它是非常不切实际的 finalInstance.age=先前的instances.tire.car.age
class Car:
def __init__(self, age):
self.age = age
class Tire:
def __init__(self, car):
self.car = car
self.age = self.car.age
bmw = Car(age=1)
print('Car age is ',bmw.age)
pirelli = Tire(car=bmw)
print('Tire age is ',pirelli.age)
bmw.age = 2
print('Car age is now ',bmw.age)
print('Tire age is now ',pirelli.age)
我希望这一产出:
Car age is 1
Tire age is 1
Car age is now 2
Tire age is now 2
但我得到的是:
Car age is 1
Tire age is 1
Car age is now 2
Tire age is now 1
谁能帮我找到一种方法让self.age=self.car.age自动更新轮胎
多谢各位 可能更适合设计一款
级车,它有轮胎
,而不是相反
在这种情况下,使用属性getter和属性setter,您可以将汽车年龄的变化与其轮胎的老化耦合起来
大概是这样的:
class Car:
def __init__(self, age, tire):
self._age = age
self.tire = tire
@property
def age(self):
return self._age
@age.setter
def age(self, age):
delta = age - self.age
self._age += delta
self.tire.age += delta
class Tire:
def __init__(self, age=1):
self.age = age
pirelli = Tire()
bmw = Car(1, pirelli)
print('Car age is ',bmw.age)
bmw.age = 2
print('Car age is now ',bmw.age)
print('Tire age is now ',pirelli.age)
输出:
Car age is 1
Car age is now 2
Tire age is now 2
Python中的赋值操作符=
确实更改了指定给该对象的名称所指向的对象
换句话说,在您的示例中,行self.age=self.car.age
指向运行该行时在self.car
中定义的数字(对象)。当您稍后运行bmw.age=2
以更改car类中的属性时,它将指向一个新对象。但是bmw.car.age
没有改变
您必须首先很好地理解这一点,并且简单明了的方法就是使用属性self.car.age
的完整路径,即使在Tire
类中也是如此
然后,如果您真的认为需要动态更改属性,我们必须求助于“反应式”编程—一种方法,其中状态中的一个更改自动传播到代码中的其他位置。Python允许以多种方式实现这一点。下面是一个例子
因此,Python必须处理这类事情的强大机制之一是“”——该语言指定,如果对象绑定为类属性——也就是说,在类
主体中定义,而不仅仅是在\uuuuu init\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu或其他方法中定义——则具有\uuu get\uuuuuuuuuuuuuuuuuuuuuuuuuuuuu(或两个其他特殊命名方法),检索或尝试重新绑定(使用=
)该类实例中的该属性将通过该类中的该对象。该对象称为“描述符”
Python的属性
decorator使用这种机制来提供为属性创建setter和getter的最常用案例。但是,由于您需要对许多类似属性使用相同的访问和获取规则,因此创建一个专门的描述符类更为合理,它将“知道”属性的源,并始终转到其源以获取或设置其值
下面的代码以及“汽车、轮胎和螺钉”类提供了一个示例:
类链接属性:
定义初始化(自身,容器路径):
self.container\u path=容器路径
定义设置名称(自身、所有者、名称):
self.name=名称
def_get_容器(自身,实例):
容器=实例
对于self.container_path.split(“.”)中的组件:
container=getattr(容器、组件)
返回容器
定义获取(自身、实例、所有者):
如果实例为“无”:
回归自我
container=self.\u get\u container(实例)
返回getattr(容器,self.name)
定义集(自身、实例、值):
container=self.\u get\u container(实例)
setattr(容器、self.name、值)
等级车:
定义初始(自我、年龄):
self.age=年龄
轮胎等级:
年龄=LinkedAttribute(“汽车”)
定义初始(自我,汽车):
self.car=汽车
self.age=self.car.age
等级螺钉:
年龄=链接属性(“轮胎、汽车”)
def u u初始(自身,轮胎):
self.tire=轮胎
在交互式口译员中,我们有:
[37]中的:宝马=汽车(2)
...:
In[38]:t1=轮胎(宝马)
...:
In[39]:s1=螺钉(t1)
In[40]:t1.age
Out[40]:2
In[41]:bmw.age=5
In[42]:t1.age
Out[42]:5
In[43]:s1.年龄
Out[43]:5
在[44]中:s1.age=10
在[45]中:bmw.age
Out[45]:10
当然,如果您不想允许从包含的类修改父类的任何属性,只需省去(或放置一个保护标志)在\uuuu set\uuuu
方法上。是否可以将类结构保留为OP?a轮胎
,它有一辆汽车
,不知道它的轮胎
…是的,可以通过发布者
订阅者
:一个轮胎将向它的汽车注册,以监听汽车年龄的变化,并在发布car.age
change时自行调整……这会让人感觉很轻松