[自学编程-Python] 面向对象之类的属性和方法
【预利其器,必先苦其心志,劳其筋骨,饿其体肤,空乏其身,行拂乱其所为,所以动心忍性,曾益其所不能。】
今日学习
学习内容
理解类的属性及方法
属性:静态属性(类属性)、实例属性
(资料图)
方法:静态方法、实例方法、类方法、属性包装
静态属性:一个类中,当某些属性值被所有实例共有的时候,那么可以定义为静态属性为所有的对象来使用。
实例属性:一个类中,当某些属性值对每个对象实例来说都不是相同时,哪就需要在初始化__init__()方法中定义实例属性来使用。
一、静态属性
为什么要使用静态属性? 简单来说就是为了节约内存
静态属性和实例属性占用单独的空间,静态属性创建后只会占用固定一块存储空间,而实例 属性每次创建都会额外的开辟一个存储空间。所以将各个实例的相同的属性定义成某些静态属性就可以节约计算机空间。
代码练习:
class Man: city = '北京' # 静态属性 可以被实例对象共有 sex = '男' hobby = '游戏' def __init__(self, name, age): self.name = name # 当某些属性值对每个实例对象都不相同时,就需要当都定义实例属性 self.age = age
man1 = Man('jason', 40) # 通过类对象实例化一个实例对象出来# 访问类属性print(man1.city) # 在类的外部,通过实例对象man1 来访问的类的静态属性print(Man.city) # 在类的外部,通过类名可以直接访问到类属性print(man1.name) # 在类的外部,通过实例对象man1 可以访问实例属性
二、实例方法:
实例方法:当实例需要执行某项任务时,就可以定义一个实例方法,实例方法必须要有一个self参数
编码练习:
class Bus317(object):
# 设置静态属性
# 假设比亚迪品牌是公有的属性
prod = 'BYD'
# 设置实例属性 driver,plate_number这些信息每个实例都不同,需要使用__init__方法初始化
def __init__(self,driver,plate_number,color='green'):
self.driver =driver
self.plate_number= plate_number
self.color = color
# 定义一个实例方法,实例方法必须要有self参数
def run(self):
print(f"{self.driver}开的{self.plate_number}往返于湖南XX大学与长华小区")
# 实例化BUS317
b1 = Bus317("路小飞",'湘A88888')
print(b1.driver,b1.plate_number,b1.color,b1.prod)
# 调用实例方法
b1.run()
注意:
对象的实例化(初始化)首先调用执行的是__new__()方法(这和下面的__init__()方法都是一个魔术方法)。__new__方法的作用是创建并且返回一个实例,然后在对这个实例进行初始化__init__()方法,否则是不会执行__init__方法的。
上述例子没有看到__new__方法是因为父类object中有new方法,子类BUS317直接继承了父类的方法
三、静态方法:
利用到了@staticmethod 装饰器,假若没有用到实例的数据和类的数据(静态属性),可以定义为静态方法供 类对象和实例对象使用,或者外部模块使用。
静态方法中不需要传入self参数,因此无法在静态方法中访问实例变量。
静态方法中不可以通过静态变量名直接访问类的静态变量,但可以通过类名引用静态变量。
# 在类的外部,也通过类或者实例对象调用静态方法
代码练习:
class Man: action = '每日一练' # 静态属性 可以被实例对象共有 def __init__(self): self.age = 0 # 当某些属性值对每个实例对象都不相同时,就需要当都定义实例属性 self.run(1) # 在类内的实例方法中,通过self来调用静态方法 @staticmethod # 静态方法:利用到了@staticmethod 装饰器,假若没有用到实例的数据和类的数据(静态属性), # 可以定义为静态方法 def run(num): # 静态方法中不需要传入self参数,因此无法在静态方法中访问实例变量 print('这是静态方法功能,无需访问类属性的方法') print(Man.action) # 但在类的静态方法中,可以通过类名访问类的属性 # print(self.age) # 但是不能访问实例属性 if num == 1: return num else: raise ValueError("number数值不对") # 抛出异常m = Man() # 类实例化对象
# 在类的外部,也通过类或者实例对象调用静态方法
代码输出:
这是静态方法功能,无需访问类属性的方法
每日一练
四、类方法:
使用@classmethod 装饰器。可以解决硬编码的问题。类方法只能在类中的实例方法中,可以通过self 来调用,
在类方法中,只能使用类的静态属性,不能调用实例属性。
编码练习:
class Pig(): # 静态属性 用于统计对象的个数 number = 0 # 定义一个类方法,方法内部可以访问这个类静态属性,这个类方法供多个实例对象使用 # cls表示当前类本身 ,将方法定义成类方法用于解决硬编码的问题 # 每创建一个对象number加1 @classmethod def counter(cls): print('这是类方法...' , cls) cls.number += 1 # 只能使用类的静态属性, # print(self.name) # 不能调用实例属性 name不存在 # 在类可中直接调用类方法 def __init__(self, name): self.name = name # Pig.number += 1 # 未定义类方法时,可通过类名访问类属性和修改类属性 self.counter() # 定义了类方法后,在实例方法中可以,使用self调用,默认传递的参数还是cls. # 避免了硬编码 , # def counter(self): # 后定义的实例方法会覆盖同名的类方法 # print('实例对象')# 调用p1 = Pig('八戒')print(p1.number) # 最早还是访问的类属性p2 = Pig('沙僧')print(p2.number) # 最早还是访问的类属性print(Pig.number) # 最早还是访问的类属性
输出:
这是类方法... <class '__main__.Pig'>
1
这是类方法... <class '__main__.Pig'>
2
2
五、属性包装:
使用@property 装饰器将一个方法包装,用起来像一个实例属性
被包装的方法一定要返回一个结果 ,被包装后的方法可以当成属性直接进行修改数值大小
编码练习:
# 属性包装:使用 @ property装饰器# 将一个方法包装,用起来像一个实例属性# 将age方法包装为一个属性class Person(object): def __init__(self, name, age): self.name = name self._age = self.check_age(age) # 属性不能和方法同名 # 当包装age后,自动生成几个装饰器。 age.setter,age.deleter # age方法一定要返回一个结果 # 包装age方法 @property def age(self): return self._age # 包装age方法后,可以把age当成属性直接修改数值大小 @age.setter # 默认生成的装饰器 def age(self, value): self._age = self.check_age(value) # 设置静态方法 @staticmethod def check_age(age): if 0 <= age <= 100: return age else: raise ValueError("输入的数值不在范围内")a1 = Person('cali', 100)print(a1.age)a1.age = 150 # 像调用属性一样调用方法print(a1.age)
代码输出:
100
raise ValueError("输入的数值不在范围内")
ValueError: 输入的数值不在范围内
六、总结:
# 实例属性的调用过程1、 当一个实例对象调用实例属性时,会先从自身实例对象对应的代码块中去找属性是否定义,2、 在实例对象对应的代码块中找不到,就去生成实例的类对象中找父类中,有没有同名的实例属性3、 在父类对象里的实例属性代码块中找不到,就去生成实例的类对象中找同名的类属性4、 若类中也不到同名类属性,就去父类中继续查找同名的类属性5、 若父类中也都找不到,就直接报无对应属性的错误注意:
1、 类属性为共用属性值,不建议通过某个实例来去修改它,但可以同时被多个实例对象来使用。2、 类方法为类和实例共用的方法,可以同时被多个实例对象来使用,也可以通过自身类来调用它。
3、 类方法可以调用类的属性,不可以调用实例属性4、 类的静态方法 为类和实例共用的方法,当没有用到实例的属性和类的数据(静态属性)时,可以定义静态方法
5、静态方法的一般设定的都是逻辑功能,设计时方法内部是不需要访问类属性和实例属性前提,但这个方法内当可以设置局部变量和形参