日期:2021年1月26日
今天是学习Python的第九天,东西还是挺多了,开始使用小本本记一些代码和用法,方便记忆和查阅,今天没有练习,看几个案例。
学习用的教材是GitHub上骆昊编写的《Python - 100天从新手到大师》
一、@property装饰器
用一个下划线来提示自己类中的属性是受保护的,但是直接暴露给外界也是有问题的。可以使用@property包装器来包装getter(访问器)和setter(修改器)方法来对属性进行访问,安全且方便。
class Rect:
def __init__(self,l,w):
self._l=l
self._w=w
# 访问器 - getter方法
@property
def l(self):
return self._l
# 修改器 - setter方法
@l.setter
def l(self,l):
self._l=l
def distance(self):
print('面积为:',self._l*self._w)
def main():
s1=Rect(2,3)
s1.distance()
print(s1.l)
s1.l=5
print(s1.l)
s1.distance()
if __name__ == "__main__":
main()
💡 需要注意的就是,使用访问器用@property
开头,然后return
返回值;使用修改器使用@属性.setter
开头,修改对应属性参数。主程序中需要调用的时候直接使用对象.属性
即可
二、__ slots __魔法
Python是一门动态语言,允许在程序运行中给对象绑定新的属性或方法,也可以对已绑定的部分进行解绑。如果需要限定自定义类型的对象只能绑定某些属性,可以通过定义
__slots__
来进行限定,且对子类没有作用。
以上面的例子为,在新建Rect类的时候添加一句__slots__==('_l','_w','_n')
类Rect的对象就限定只能绑定3个属性:_l
、_w
、_n
这时候主程序可以使用s1._n
进行赋值,如果使用别的属性名称,如s1._t=1
,就会报错AttributeError: 'Rect' object has no attribute '_t'
三、静态方法和类方法
静态方法:在调用时不需要类的实例(不需要self参数)
类方法:不需要对象实例,第一个参数约定为
cls
,代表当前类相关的信息的对象(类本身也是一个对象,有的地方称之为类的元数据对象),通过这个参数可以获取和类相关的信息并创建出类的对象。
静态方法(@staticmethod):
class 类名:
# 创建静态方法
@staticmethod
def 方法名(参数):
pass
def main():
# 调用静态方法
类名.方法名(参数)
if __name__ == "__main__":
main()
类方法(@classmethod):
from time import localtime,sleep
from os import system
class Clock:
def __init__(self,hour=0,minute=0,second=0):
self._hour=hour
self._minute=minute
self._second=second
# 创建类方法
@classmethod
def now(cls):
ctime=localtime()
return cls(ctime.tm_hour,ctime.tm_min,ctime.tm_sec)
def run(self):
self._second+=1
if self._second==60:
self._second=0
self._minute+=1
if self._minute==60:
self._minute=0
self._hour+=1
if self._hour==24:
self._hour=0
def output(self):
while 1:
self.run()
system('cls')
print('当前时间:%02d:%02d:%02d' % (self._hour,self._minute,self._second))
sleep(1)
def main():
# 调用类方法
s=Clock.now()
s.output()
if __name__=='__main__':
main()
💡 普通方法、类方法、静态方法的区别:
method(普通方法):
通过实例调用时,可以引用类内部的任何属性和方法
classmethod(类方法):
无需实例化, 可以调用类属性和类方法,无法取到普通的成员属性和方法
staticmethod(静态方法):
无论用类调用还是用实例调用,都无法取到类内部的属性和方法, 完全独立的一个方法
四、类之间的关系
类之间有三种关系:is-a、has-a、use-a
-
is-a(继承),例如学生和人的关系
-
has-a(关联),例如学生和班级的关系;如果是整体和部分的关联,称之为聚合关系;如果整体进一步负责了部分生命的周期,称之为合成关系。
-
use-a(依赖),例如学生有一个看书的行为,其中使用到了教室,那么学生和教室就是依赖关系。
五、继承
子类可以继承父类提供的属性和方法,还可以定义自己特有的属性和方法。
-
子类的定义:
直接在括号内写上父类名
class 子类(父类)
,多个父类使用逗号隔开。 -
初始化:
使用关键字
super
,在def __init__(self,父类参数,新参数):
后加入super.__init__(父类参数)
以调用父类的初始化函数,注意不需要写self,然后再下面初始化新参数。
写个学C++的例子:公司的工资管理
"""
请按照以下要求实现某个公司的工资管理。
要求如下:
定义四个类:雇员类、经理类、销售员类、销售经理类。
定义雇员类为基类,其中包含员工编号、姓名、月工资三个数据成员,
以及计算月工资、显示月工资的成员函数,构造函数、析构函数也应显式定义。
销售员、销售经理、经理的月收入按下述规定计算
经理:月工资固定8000元。
销售员:按当月销售额的5%提成。
销售经理:月固定工资4000元,并按部门月销售总额的0.5%提成。
类名:
Employee雇员、Manager公司经理、Saleperson销售员、Salemanager销售经理
变量:
number工号、name姓名、salary月工资、gdgz固定工资、sale销售总额
"""
class Employee:
def __init__(self,num,name):
self._num=num
self._name=name
self._salary=0
def show(self):
print('月工资为:',self._salary)
class Manager(Employee):
def __init__(self,num,name):
super().__init__(num,name)
self._salary=8000
class Saleperson(Employee):
def __init__(self,num,name,sale):
super().__init__(num,name)
self._sale=sale
self._salary=self._sale*0.05
class SaleManager(Saleperson,Manager):
def __init__(self,num,name,sale):
super().__init__(num,name,sale)
self._salary=4000+self._sale*0.005
def main():
while 1:
print('\n*****工资查询*****\n1.公司经理\n2.销售员\n3.销售经理\n0.退出\n')
x=int(input('请输入查询的序号:'))
if x==0:
break
num=int(input('工号:'))
name=input('姓名:')
if x==1:
p=Manager(num,name)
elif x==2:
sale=int(input('销售总额:'))
p=Saleperson(num,name,sale)
elif x==3:
sale=int(input('销售总额:'))
p=SaleManager(num,name,sale)
else:
print('输入有误,请重新输入!\n')
continue
p.show()
if __name__=='__main__':
main()
💡 Python中没有像C++中的虚继承,完全使用super
来查找父类,实际在使用过程中发现,上面的钻石继承中,如果把class SaleManager(Saleperson,Manager):
中的两个父类调换顺序,会出现TypeError: __init__() takes 3 positional arguments but 4 were given
的错误。猜测原因是,Saleperson的属性比Manager多一个?查了很久没看到网上文献里面有带多个参数的钻石继承,给自己留个坑待埋。