各位同学好,在上一节中我们学习了类实例化的基本方法:https://blog.csdn.net/dgvv4/article/details/122275348?spm=1001.2014.3001.5501
今天在上一节的基础上继续补充,和大家分享一下类属性的定义及使用方法。
1. 定义类属性
在定义的类中,在初始化函数之前定义到变量称为类属性,是这个类特有的。一旦类实例化之后,那么实例对象默认就可以访问这个类属性。
绑定在一个实例上的属性不会影响其他实例,但是,类本身也是一个对象,如果在类上绑定一个属性,则所有实例都可以访问类的属性,并且,所有实例访问的类属性都是同一个。也就是说,实例属性每个实例各自拥有,互相独立,而类属性有且只有一份。
这里定义的类属性 pay_rate,不仅可以通过类来访问 Item.pay_rate,也能通过实例来访问 item1.pay_rate。我们可以通过 __dict__ 查看实例或者类的属性,如最后两行代码,可见类属性pay_rate是属于类Item特有的。
#(1)创建类
class Item:
#(2)创建类属性
pay_rate = 0.8 # 定义类属性,代表商品折扣8折
#(3)初始化
# 第一个参数 self代表类实例化对象,属性name需要字符串类型,属性price需要浮点类型,属性quantity默认值为10
def __init__(self, name:str, price:float, quantity=10):
# 指定输入输入值的范围,如果不符合就报错,报错内容是逗号后面的
assert price >=0, f'price {price} cannot smaller than 0'
assert quantity >=0, f'quantity {quantity} cannot smaller than 0'
# 属性分配
self.name = name
self.price = price
self.quantity = quantity
#(3)在类中定义方法,第一个参数默认是self实例化对象
def calculate_total_price(self):
# 返回单价和数量的乘积
return self.price * self.quantity
#(4)类实例化
item1 = Item('phone', 100, 5) # Item类的实例化对象item1,传入各属性对应的值
item2 = Item('MacBook', 1000, 3)
#(5)调用类中的方法
res = item1.calculate_total_price()
print(res) # 500
#(6)通过类本身访问类属性
print(Item.pay_rate) # 0.8
#(7)通过实例化对象访问类属性
print(item1.pay_rate) # 0.8
print(item2.pay_rate) # 0.8
# 打印类的所有属性
print(Item.__dict__) # {'__module__': '__main__', 'pay_rate': 0.8, '__init__': <function Item.__init__ at 0x0000023A6989A940>, 'calculate_total_price': <function Item.calculate_total_price at 0x0000023A6989ACA0>, '__dict__': <attribute '__dict__' of 'Item' objects>, '__weakref__': <attribute '__weakref__' of 'Item' objects>, '__doc__': None}
# 打印实例的所有属性
print(item1.__dict__) # {'name': 'phone', 'price': 100, 'quantity': 5}
2. 类属性的应用
在类中定义了一个方法,调用类属性用于计算,self.price * Item.pay_rate,其中price调用的是实例属性,pay_rate调用的是类属性,类属性是不变的。
如下代码中,实例属性 price 可根据不同的实例展现不同的值,而类属性 pay_rate 是固定的,通过实例访问类属性改变它的值 item2.pay_rate = 0.5,不会影响 Item.pay_rate 的结果。
#(1)创建类
class Item:
#(2)创建类属性
pay_rate = 0.8 # 定义类属性,代表商品折扣8折
#(3)初始化,self代表类实例化对象,属性name需要字符串类型,属性price需要浮点类型,属性quantity默认值为10
def __init__(self, name:str, price:float, quantity=10):
# 指定输入输入值的范围,如果不符合就报错,报错内容是逗号后面的
assert price >=0, f'price {price} cannot smaller than 0'
assert quantity >=0, f'quantity {quantity} cannot smaller than 0'
# 属性分配
self.name = name
self.price = price
self.quantity = quantity
#(4)在类中定义方法,第一个参数默认是self实例化对象
def calculate_total_price(self):
# 返回单价和数量的乘积
return self.price * self.quantity
#(5)调用类属性
# 在类中定义方法,用于计算商品折扣
def apply_discount(self):
# 计算新的价格,pay_rate是Item类自身的属性,在类的内部不能用实例属性self.pay_rate来调用它
self.price = self.price * Item.pay_rate
#(6)Item类的实例化对象item1
item1 = Item('phone', 100, 5)
print(item1.price) # 100
#(7)调用商品打折的方法
item1.apply_discount()
print(item1.price) # 80.0
#(8)实例化对象item2
item2 = Item('MacBook', 1000, 3)
print(item2.price) # 1000
# 通过实例化属性改变类属性
item2.pay_rate = 0.5 # 没有发生变化
# 调用类方法
item2.apply_discount()
print(item2.price) # 800.0
3. 不同的实例分配不同的类属性
就拿这个案例来说,如果并不是所有的商品都打8折,假如phone打8折,而MacBook打5折,计算时,肯定不能每一次都去重新写类属性。
这时候在调用类属性时,需通过实例访问类属性,用于计算。如下面代码中 self.price = self.price * self.pay_rate,这里的price属性和pay_rate属性都是通过实例来访问的,可以通过实例来改变各属性对应的值。item2.pay_rate = 0.5,就可以将 self.pay_rate 改为0.5。
如果是通过类来访问的类属性,那么调用该方法时,即使外部给实例属性赋予了新的值,但是这里仍使用的是类属性的值,没有改变。
#(1)创建类
class Item:
#(2)创建类属性
pay_rate = 0.8 # 创建类属性,代表商品折扣8折
#(3)初始化,self代表类实例化对象,属性name需要字符串类型,属性price需要浮点类型,属性quantity默认值为10
def __init__(self, name:str, price:float, quantity=10):
# 指定输入输入值的范围,如果不符合就报错,报错内容是逗号后面的
assert price >=0, f'price {price} cannot smaller than 0'
assert quantity >=0, f'quantity {quantity} cannot smaller than 0'
# 属性分配
self.name = name
self.price = price
self.quantity = quantity
#(4)在类中定义方法,第一个参数默认是self实例化对象
def calculate_total_price(self):
# 返回单价和数量的乘积
return self.price * self.quantity
#(5)调用类属性
# 在类中定义方法,用于计算商品折扣
def apply_discount(self):
# 计算新的价格,类属性pay_rate通过实例属性来访问,可以在外部通过实例来访问这个属性,并改变这个属性的值
self.price = self.price * self.pay_rate
#(6)类实例化对象
item1 = Item('phone', 100, 5)
#(7)调用类中的商品打折方法(该方法调用类属性)
item1.apply_discount() # 默认8折
print(item1.price) # 80.0
# 类实例化对象
item2 = Item('MacBook', 1000, 3)
# 通过实例对象访问类属性,并改变该实例所对应的类属性的值
item2.pay_rate = 0.5
# 调用打折方法,已经改变了属性的值
item2.apply_discount()
print(item2.price) # 500.0
4. 访问多个实例的属性
现在有很多实例化对象,如何去批量访问这些实例的属性呢。定义一个列表形式的类属性 all_instance,在每一次初始化之后,将定义好了的实例化对象追加到列表中,Item.all_instance.append(self) ,这里是通过类来访问类属性,这样外部就改变不了类属性 all_instance 中的值。最后通过一个for循环遍历类属性中的所有实例,打印实例的属性结果。
#(1)创建类
class Item:
#(2)创建类属性
pay_rate = 0.8 # 创建类属性
all_instance = [] # 存放所有已经定义的实例
#(3)初始化,指定需要传入的实例属性的值是什么类型的
def __init__(self, name:str, price:float, quantity=10):
# 指定输入输入值的范围,如果不符合就报错,报错内容是逗号后面的
assert price >=0, f'price {price} cannot smaller than 0'
assert quantity >=0, f'quantity {quantity} cannot smaller than 0'
# 分配属性
self.name = name
self.price = price
self.quantity = quantity
# 每次初始化后都会将创建好了的实例存追加到列表中
# 这里通过类访问的类属性,在外部就改变不了all_instance的值
Item.all_instance.append(self) # 将实例self追加到列表中
#(4)定义计算总价的方法
def calculate_total_price(self):
# 返回单价乘数量
return self.price * self.quantity
#(5)定义打折方法,调用类属性
def price_discount(self):
# 通过实例访问类属性pay_rate,可在外部通过实例改变类属性的默认值
self.price = self.price * self.pay_rate
#(6)实例化了很多对象,在完成类初始化之后,都将这些实例存放在all_instance属性中
item1 = Item('phone', 100, 5)
item2 = Item('MacBook', 200, 6)
item3 = Item('ipad', 300, 7)
item4 = Item('Mouse', 400, 8)
item5 = Item('keyboard', 500, 9)
#(7)访问所有实例化对象
for instance in Item.all_instance:
# 打印所有实例的属性
print('name:', instance.price, 'price:', instance.price, 'quantity:', instance.quantity)
#(8)直接输出实例化对象
print(Item.all_instance)
# [<__main__.Item object at 0x0000023A698B7D00>, <__main__.Item object at 0x0000023A698B7250>, <__main__.Item object at 0x0000023A698B7610>, <__main__.Item object at 0x0000023A698B7A60>, <__main__.Item object at 0x0000023A698B7B50>]
5. __repr__() 显示属性
如上面代码的第(8)步,直接输出实例化对象时 print(Item.all_instance),本意往往是想了解该对象的基本信息,但默认情况下,我们得到的信息只会是“类名+object at+内存地址”。
当我们输出某个实例化对象时,其调用的就是该对象的 __repr__() 方法,输出的是该方法的返回值。 print(Item.all_instance) 等同于执行 print(Item.all_instance.__repr__()),程序的输出结果是一样的。
因此,在类中定义 __repr__() 的输出格式 return f"Item('{self.name}', {self.price}, {self.quantity})",这样的话,在外部输出实例化对象时,就可以按照这个格式打印结果了。
#(1)创建类
class Item:
#(2)创建类属性
pay_rate = 0.8 # 创建类属性
all_instance = [] # 存放所有已经定义的实例
#(3)初始化,指定需要传入的实例属性的值是什么类型的
def __init__(self, name:str, price:float, quantity=10):
# 指定输入输入值的范围,如果不符合就报错,报错内容是逗号后面的
assert price >=0, f'price {price} cannot smaller than 0'
assert quantity >=0, f'quantity {quantity} cannot smaller than 0'
# 分配属性
self.name = name
self.price = price
self.quantity = quantity
# 每次初始化后都会将创建好了的实例存追加到列表中
# 这里通过类访问的类属性,在外部就改变不了all_instance的值
Item.all_instance.append(self) # 将实例self追加到列表中
#(4)定义计算总价的方法
def calculate_total_price(self):
# 返回单价乘数量
return self.price * self.quantity
#(5)定义打折方法,调用类属性
def price_discount(self):
# 通过实例访问类属性pay_rate,可在外部通过实例改变类属性的默认值
self.price = self.price * self.pay_rate
#(6)显示属性,接收实例
def __repr__(self):
return f"Item('{self.name}', {self.price}, {self.quantity})"
#(7)实例化多个对象
item1 = Item('phone', 100, 5)
item2 = Item('MacBook', 200, 6)
item3 = Item('ipad', 300, 7)
item4 = Item('Mouse', 400, 8)
item5 = Item('keyboard', 500, 9)
#(8)输出实例化对象,调用的就是该对象的 __repr__() 方法,输出的是该方法的返回值
print(Item.all_instance)
# [Item('phone', 100, 5), Item('MacBook', 200, 6), Item('ipad', 300, 7), Item('Mouse', 400, 8), Item('keyboard', 500, 9)]