面向对象
一、面向对象初步
1、面向对象的人狗大战例子
1 def Person(name,blood,aggr,sex): 2 person={ 3 'name':name, 4 'blood':blood, 5 'aggr':aggr, 6 'sex':sex, 7 } 8 def attack(dog): 9 dog['blood'] -= person['aggr'] 10 print('%s被打了,掉了%s的血'%(dog[name],person[aggr])) 11 person['attack'] = attack 12 13 return person 14 15 def Dog(name,blood,aggr,kind): 16 dog={ 17 'name':name, 18 'blood':blood, 19 'aggr':aggr, 20 'kind':kind, 21 } 22 def bite(person): 23 person['blood'] -= dog['aggr'] 24 print('%s被咬了,掉了%s血'%(person['name'],dog['aggr'])) 25 dog['bite'] = bite 26 return dog 27 28 jin = Dog('旺财',500,10,'tddy') 29 alex = Person('小市民',100,5,'man') 30 print(jin) 31 jin['bite'](alex)
1 {'name': '旺财', 'blood': 500, 'aggr': 10, 'kind': 'tddy', 'bite': <function Dog.<locals>.bite at 0x0000000001E8D7B8>} 2 小市民被咬了,掉了10血
二、面向对象
1、面向对象词语解释
对象 = 类名()
过程:
类名()首先会创建一个对象,创建了一个self变量
调用init方法,类名括号里的参数会被这里接收
执行init方法
返回self
对象能做的事情:
查看属性
调用方法
__dict__对于对象的增删改查操作都可以通过字典的语法进行
类名能做的事情:
实例化
调用方法:只不过要自己传递self参数
调用类中的属性,也就是调用静态属性
__dict__对于类中的名字只能看,不能操作
类里面的元素定义:
函数:方法,动态属性,类中可以定义方法,方法都有一个必须传的参数self
变量:类属性,静态属性,类中可以定义静态属性
__init__方法,初始化方法
python帮我们创建了一个对象self
每当我们调用类的时候就会自动触发这个方法,默认传self
在init方法里面可以对self进行赋值
self是什么
self拥有的属性都属性对象
在类的内部,self就是一个对象
1 class Person: 2 country = 'china' 3 def __init__(self,*args): 4 self.name = args[0] 5 self.blood = args[1] 6 self.aggr = args[2] 7 self.sex = args[3] 8 def walk(self,n): 9 print('%s今天走了%s多步'%(self.name,n)) 10 peng = Person('Pengjun',500,100,'man') #实例化 11 print(Person.__dict__) #查看所有属性 12 print(peng.name) #参看属性值 13 print(peng.sex) #查看属性值 14 print(peng.__dict__) 15 peng.walk(100) #调用方法
1 {'__module__': '__main__', 'country': 'china', '__init__': <function Person.__init__ at 0x00000000021CD730>, 'walk': <function Person.walk at 0x00000000021CD7B8>, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None} 2 Pengjun 3 man 4 {'name': 'Pengjun', 'blood': 500, 'aggr': 100, 'sex': 'man'} 5 Pengjun今天走了100多步
2、例子
求圆的面积及周长
1 from math import pi 2 3 class Circle: 4 def __init__(self,r): 5 self.r = r 6 def area(self): 7 return pi * (self.r**2) 8 def perimeter(self): 9 return 2 * pi * self.r 10 11 C1 = Circle(8) 12 print(C1.area()) 13 print(C1.perimeter())
1 201.06192982974676 2 50.26548245743669
3、对象的静态变量赋值
对象的静态变量进行赋值,相当于在对象的命名空间里增加了静态变量,则该对象先在自己的空间找到变量,就不会到类里面去找,
这样,类里面的静态变量没有改变。
1 class Course: 2 langure = 'chinese' 3 def __init__(self,name,teacher,period,price): 4 self.name = name 5 self.teacher = teacher 6 self.period = period 7 self.price = price 8 def func(self): 9 pass 10 11 Course.langure = 'English' 12 # Course.__dict__ ['language'] = 'Chinese' #类的静态属性不能通过init修改 13 python = Course('python','peng','12 mouths',38000) 14 linux = Course('linux','peng','6 mouths',28000) 15 #类中的静态变量,可以被对象和类调用 16 python.langure = '日语'# 17 print(python.langure) 18 print(linux.langure) 19 print(Course.langure)
1 日语 2 English 3 English
4、组合
软件重用的重要方式除了继承之外还有另外一种方式,即:组合
组合指的是,在一个类中以另外一个类的对象作为数据属性,称为类的组合
当类之间有显著不同,并且较小的类是较大的类所需要的组件时,用组合比较好
例1:
1 class Person : 2 def __init__(self,name,hp,aggr,sex,money): 3 self.name = name 4 self.hp = hp 5 self.aggr = aggr 6 self.sex = sex 7 self.money = 0 8 def atter(self,dog): 9 dog.hp -= self.aggr 10 def get_weapon(self,weapon): 11 if self.money >= weapon.price: 12 self.money -= weapon.price 13 self.weapon = weapon 14 self.aggr += weapon.aggr 15 else: 16 print('余额不足,请充值') 17 18 class Dog: 19 def __init__(self,name,hp,aggr,kind): 20 self.name = name 21 self.hp = hp 22 self.aggr = aggr 23 self.kind = kind 24 def atter(self,person): 25 person.hp -= self.aggr 26 27 class Weapon: 28 def __init__(self,name,aggr,times,price): 29 self.name = name 30 self.times = times 31 self.aggr = aggr 32 self.price = price 33 def wugong(self,person): 34 if self.times > 0: 35 person.hp -= self.aggr 36 self.times -= 1 37 38 39 40 hand = Weapon('MMA',50,3,200) 41 peng = Person('彭',1000,100,'man',1000) 42 telangpu = Dog('特朗普',500,50,'taidi') 43 peng.money += 1200 44 45 print(telangpu.hp) 46 peng.atter(telangpu) 47 print(telangpu.hp) 48 49 peng.get_weapon(hand) 50 peng.weapon.wugong(telangpu) 51 print(telangpu.hp)
1 500 2 400 3 350
例2:用类的组合方法计算环形的面积及周长
1 from math import pi 2 3 class Circle: 4 def __init__(self,r): 5 self.r = r 6 def Area(self): 7 return pi * self.r**2 8 def Perimeter(self): 9 return 2*pi*self.r 10 11 class Ring: 12 def __init__(self,outside_r,inside_r): 13 self.outside_r = Circle(outside_r) #类Ring的属性是类Circle的对象----组合 14 self.inside_r = Circle(inside_r) #类Ring的属性是类Circle的对象----组合 15 def Huan_Area(self): 16 return Circle.Area(self.outside_r) - Circle.Area(self.inside_r) 17 def Huan_Perimeter(self): 18 return Circle.Perimeter(self.outside_r) + Circle.Perimeter(self.inside_r) 19 20 A = Ring(5,4) 21 print(A.Huan_Area()) 22 print(A.Huan_Perimeter())
28.27433388230814 56.548667764616276
例3:
1 class Birthday: 2 def __init__(self,year,month,day): 3 self.year = year 4 self.month = month 5 self.day = day 6 7 class Teacher: 8 def __init__(self,name,age,sex,birthday): 9 self.name = name 10 self.age =age 11 self.sex = sex 12 self.birthday = birthday 13 B1 = Birthday('2020','05','22') 14 peng = Teacher('fei',25,'female',B1) 15 print(peng.name) 16 print(peng.birthday.year) 17 print(peng.birthday.day)
fei 2020 22
创建一个老师类,老师有生日,生日也可以是一个类,用组合完成
5、面向对象作业——校园管理系统
角色:
学校、学员、课程、讲师
要求:
1. 创建北京、上海 2 所学校
2. 创建linux , python , go 3个课程 , linux\py 在北京开, go 在上海开
3. 课程包含,周期,价格
4. 班级关联课程、讲师
5. 创建学员时,选择学校,关联班级
5. 创建讲师角色时要关联学校
6. 提供三个角色视图
6.1 学员视图, 登陆, 查看课程、查看班级
6.2 讲师视图, 讲师可查看自己教学的班级、课程。
进阶需求:可管理自己的班级, 查看班级学员列表 , 修改所管理的学员的成绩
6.3 管理视图,创建讲师, 创建班级,创建课程
7. 上面的操作产生的数据都通过pickle序列化保存到文件里
四、面向对象的继承
一个类可以被多个类继承;一个类可以继承多个父类
没有继承父类默认继承object类,也叫新式类
1 class A:pass #父类,超类,基类 2 class B:pass 3 4 class A_son(A):pass #子类,派生类 5 class AB_son(A,B):pass # 6 7 print(A.__bases__)# 8 print(A_son.__bases__) 9 print(AB_son.__bases__)
1 (<class 'object'>,) 2 (<class '__main__.A'>,) 3 (<class '__main__.A'>, <class '__main__.B'>)
例1:
1 class Animal: 2 def __init__(self,name,aggr,hp): 3 self.name = name 4 self.aggr = aggr 5 self.hp = hp 6 7 class Dog(Animal): 8 def bite(self,person): 9 person.hp -= self.aggr 10 class Person(Animal): 11 pass 12 13 jin = Dog('zhang',200,1000) 14 print(jin.name)
1 zhang
1、单继承
1 class Animal: 2 def __init__(self): 3 print('执行Animal类的__init__') 4 self.func() 5 def eat(self): 6 print('%s eating'%self.name) 7 def drink(self): 8 print('%s drinking'%self.name) 9 def func(self): 10 print('Animal func') 11 class Dog(Animal): 12 def guard(self): 13 print('guarding') 14 15 def func(self): 16 print('Dog func') 17 dog = Dog()
1 执行Animal类的__init__ 2 Dog func 3 4 解释:在dog = Dog()实例化过程,会在类Dog里面自动创建一个self,然后发现自己没有__init__方法,那么就到它的父类中找是否有__init__方法,结果是有,那么先执行print('执行Animal类的__init__'),然后再执行self.func(),这时候的self其实就是前面类Dog一开始的self,虽然父类Animal里也有func方法,但它会先调用自己的func方法。总结:自己有,就不用别人的。
派生属性:父类中没有的属性,在子类中出现,叫派生属性
派生方法:父类中没有的方法,在子类中出现,叫叫派生方法;
子类的对象调用,子类中有的名字一定用子类的,子类没有才从父类找,如果父类没有就报错。
如果父类、子类都有,那么用子类的
如果想用父类的,则单独调用父类的。
例2:下面是在子类中还想用父类中的方法的例子
1 class Animal: 2 def __init__(self,name,aggr,hp): 3 self.name = name 4 self.aggr = aggr 5 self.hp = hp 6 def eat(self): 7 print('吃东西') 8 9 class Dog(Animal): 10 def __init__(self,name,aggr,hp,kind): 11 super().__init__(name,aggr,hp) #类中调用父类方法,只在新式类中有 12 self.kind = kind #派生属性 13 jin = Dog('张显示',100,200,'teddy') 14 print(jin.name) 15 jin.eat() 16 super(Dog,jin).eat()#类外面调用父类方法
1 张老板 2 家狗 3 650 4 110
2、多继承
2.1钻石继承:
在已知类B、类C都继承了类A情况下,如果在类B找不到想要的,那么就在类C中找,最后在类A中找。
1 class A: 2 def func(self): 3 print('class A') 4 class B(A): 5 pass 6 # def func(self): 7 # print('class B') 8 class C(A): 9 def func(self): 10 print('class C') 11 class D(B,C): 12 # def func(self): 13 pass 14 # print('class D') 15 d = D() 16 d.func()
class C
2.2 漏斗继承:
1 class A: 2 def func(self): 3 print('class A') 4 class B(A): 5 pass 6 # def func(self): 7 # print('class B') 8 class E: 9 def func(self): 10 print('class E') 11 class C(E): 12 def func(self): 13 print('class C') 14 class D(B,C): 15 # def func(self): 16 pass 17 # print('class D') 18 d = D() 19 d.func()
1 class A
2.3 乌龟问题
1 class F: 2 def func(self): 3 print('class F') 4 class A(F): 5 pass 6 # def func(self): 7 # print('class A') 8 class B(A): 9 pass 10 # def func(self): 11 # print('class B') 12 class E(F): 13 def func(self): 14 print('class E') 15 class C(E): 16 def func(self): 17 print('class C') 18 class D(B,C): 19 # def func(self): 20 pass 21 # print('class D') 22 d = D() 23 d.func() 24 print(D.mro())#打印继承顺序
1 class C 2 [<class '__main__.D'>, <class '__main__.B'>, <class '__main__.A'>, <class '__main__.C'>, <class '__main__.E'>, <class '__main__.F'>, <class 'object'>]
2.4 小结
1、新式类:继承object类的才是新式类,广度优先
2、经典类:如果你直接创建一个类在python2.7中就是经典类,深度优先。
3、多继承中,我们子类的对象调用一个方法,默认是就近原则,找的顺序是什么
4、经典类中:深度优先
新式类中,广度优先
5、python 2.7新式类和经典类共存,新式类要继承object
python3只有新式类,默认继承object
6、经典类和新式类还有一个区别,mro方法只在新式类中存在,super 只在python3中存在。
7、单继承:先抽象再继承,几个类之间的相同代码抽象出来,成为父类,子类自己没有的名字,就可以使用父类的方法和属性,如果
子类自己有,一定是先用自己的;在类中使用self的时候,一定要看清楚self指向谁。
多继承:新式类和经典类
多继承寻找名字的顺序:新式类广度优先,经典类深度优先;
新式类中有一个类名.mro的方法可查看广度优先的继承顺序;
python3中有一个super方法,根据广度优先的继承顺序查找上一个类。
2.5 super的内外用法
使用super调用父类的方法有两种,一种是直接在子类中进行初始化操作,另一种是生成对象以后,在类外面操作
1 class Animal: 2 def __init__(self,name,aggr,hp): 3 self.name = name 4 self.aggr = aggr 5 self.hp = hp 6 def eat(self): 7 print('吃东西') 8 9 class Dog(Animal): 10 def __init__(self,name,aggr,hp,kind): 11 super().__init__(name,aggr,hp) #类中调用调用父类的另一种方法 12 jin = Dog('张显示',100,200,'teddy') 13 print(jin.name) 14 jin.eat() 15 super(Dog,jin).eat() #类外调用
张显示
吃东西
吃东西
3、接口类
1、基本概念:
设计模式----接口
接口类:python原生不支持
抽象类:python原生支持的
例1:子类没有则调用父类的方法,一旦调用父类的方法则进行报错提示,这样强制进行接口类实现
1 class Perment: 2 def pay(self,money): 3 raise NotImplemented 4 class Wechat(Perment): 5 def pay(self,money): 6 pass 7 class Aipay(Perment): 8 def pay(self,money): 9 pass 10 class Applepay(Perment): 11 def geiqian(self,money): 12 pass 13 weixin = Wechat() 14 ali = Aipay() 15 app = Applepay() 16 17 weixin.pay(100) 18 ali.pay(200) 19 app.pay(300)
File "D:/python/Day25/接口类.py", line 2 接口类:python原生不支持 ^ SyntaxError: invalid character in identifier
2、基本定义
规范:接口类或抽象类都可以
接口类:支持多继承,接口类中所有的方法都必须不能实现
抽象类:不支持多继承,抽象类中方法可以有一些代码的实现
下面是接口类的标准写法,当子类没有实现父类的方法时,那么无论子类是否被调用,都将报错
1 from abc import abstractmethod,ABCMeta 2 class Perment(metaclass = ABCMeta): #元类,默认的元类 3 @abstractmethod #装饰器 4 def pay(self,money): 5 raise NotImplemented #没有实现这个方法 6 7 class Wechat(Perment): 8 def pay(self,money): 9 pass 10 class Aipay(Perment): 11 def pay(self,money): 12 pass 13 class Applepay(Perment): 14 def geiqian(self,money): 15 pass 16 weixin = Wechat() 17 ali = Aipay() 18 app = Applepay() 19 20 weixin.pay(100) 21 ali.pay(200) 22 app.pay(300)
1 Traceback (most recent call last): 2 File "D:/python/Day25/接口类.py", line 47, in <module> 3 app = Applepay() 4 TypeError: Can't instantiate abstract class Applepay with abstract methods pay
3、接口类的多继承
接口类:python原生就是不支持接口类,只是我们在用到多继承时候方便重复的代码进行简化,我们自己弄出来的接口类,我们鼓励接口类中进行多继承
抽象类:python一般是用单继承,就是把有相同属性的事物进行抽象出来,即抽象类中尽量避免多继承
抽象类还是接口类,面向对象的开发规范
python没有接口类:java里有接口Interface这个概念进行多继承操作,不能实例化
python自带多继承,即我们直接用class实现了接口类
python张支持抽象类:一般情况下,单继承,不能实例化
1 from abc import abstractmethod,ABCMeta 2 3 class Walk_Animal(metaclass= ABCMeta): 4 @abstractmethod 5 def walk(self): 6 pass 7 8 class Swin_Ainmal(metaclass = ABCMeta): 9 @abstractmethod 10 def swin(self): 11 pass 12 class Fly_Animal(metaclass = ABCMeta): 13 @abstractmethod 14 def fly(self): 15 pass 16 class Tiger(Walk_Animal,Swin_Ainmal):#这里继承了两个父类,且Tiger类中必须实现父类中的方法,这样作规范约束 17 def walk(self): 18 pass 19 def swin(self): 20 pass 21 class Swan(Walk_Animal,Swin_Ainmal,Fly_Animal): pass
一切皆文件例子
1 import abc #利用abc模块实现抽象类 2 3 class All_file(metaclass=abc.ABCMeta): 4 all_type='file' 5 @abc.abstractmethod #定义抽象方法,无需实现功能 6 def read(self): 7 '子类必须定义读功能' 8 pass 9 10 @abc.abstractmethod #定义抽象方法,无需实现功能 11 def write(self): 12 '子类必须定义写功能' 13 pass 14 15 # class Txt(All_file): 16 # pass 17 # 18 # t1=Txt() #报错,子类没有定义抽象方法 19 20 class Txt(All_file): #子类继承抽象类,但是必须定义read和write方法 21 def read(self): 22 print('文本数据的读取方法') 23 24 def write(self): 25 print('文本数据的写入方法') 26 27 class Sata(All_file): #子类继承抽象类,但是必须定义read和write方法 28 def read(self): 29 print('硬盘数据的读取方法') 30 31 def write(self): 32 print('硬盘数据的写入方法') 33 34 class Process(All_file): #子类继承抽象类,但是必须定义read和write方法 35 def read(self): 36 print('进程数据的读取方法') 37 38 def write(self): 39 print('进程数据的写入方法') 40 41 wenbenwenjian=Txt() 42 43 yingpanwenjian=Sata() 44 45 jinchengwenjian=Process() 46 47 #这样大家都是被归一化了,也就是一切皆文件的思想 48 wenbenwenjian.read() 49 yingpanwenjian.write() 50 jinchengwenjian.read() 51 52 print(wenbenwenjian.all_type) 53 print(yingpanwenjian.all_type) 54 print(jinchengwenjian.all_type)
1 文本数据的读取方法 2 硬盘数据的写入方法 3 进程数据的读取方法 4 file 5 file 6 file
4、多态性
什么是多态动态绑定(在继承的背景下使用时,有时也称为多态性)
多态性是指在不考虑实例类型的情况下使用实例
接口类和抽象类在Python中比不重要
list tuple这种相似,是自己写代码时候进行约束的,而不是用过父类进行约束的
优点:松耦合,每个相似类之间没有影响
缺点:太随意,只能靠自觉;
鸭子类型
Python崇尚鸭子类型,即‘如果看起来像、叫声像而且走起路来像鸭子,那么它就是鸭子’
python程序员通常根据这种行为来编写程序。例如,如果想编写现有对象的自定义版本,可以继承该对象
也可以创建一个外观和行为像,但与它无任何关系的全新对象,后者通常用于保存程序组件的松耦合度。
例1:利用标准库中定义的各种‘与文件类似’的对象,尽管这些对象的工作方式像文件,但他们没有继承内置文件对象的方法
例2:序列类型有多种形态:字符串,列表,元组,但他们直接没有直接的继承关系
#二者都像鸭子,二者看起来都像文件,因而就可以当文件一样去用 class TxtFile: def read(self): pass def write(self): pass class DiskFile: def read(self): pass def write(self): pass 例子
class List: def __def__(self):pass class Tuple: def __len__(self):pass def len(l_t): return l_t.__len__() l = List() len(l)
1 Traceback (most recent call last): 2 File "D:/Python Project/05/Day23/多态.py", line 14, in <module> 3 len(l) 4 File "D:/Python Project/05/Day23/多态.py", line 12, in len 5 return l_t.__len__() 6 AttributeError: 'List' object has no attribute '__len__'
5、封装
1 封装:隐藏对象的属性和实现细节,仅对外提供公共访问的方式 2 优点:将变化隔离,便于使用,提供复用性,提高安全性 3 封装原则:1、将不需要对外提供的内容隐藏起来 4 2、把属性都隐藏,提供公共方法对其访问 5 私有变量和私有方法:在python中用双下划线开头的方式将属性隐藏起来,即设置为私有的。
私有变量和私有方法:
在python中用双下划线开头的方式将属性隐藏起来(设置成私有的)
class Person: __key = 456 def __init__(self,name,passwd): self.name = name self.__passwd = passwd #私有属性 def __get_pwd(self): return self.__passwd def login(self): self.__get_pwd(self) peng = Person('quan','123456') print(peng._Person__passwd)
123456
6、接口类、抽象类小结:
python中没有接口类,有抽象类,例如abc模块中的mataclass = ABCMeta,@abstructmethod
本质是做代码规范用得,希望在子类中实现和父类方法名字完全一样的方法。
在java的角度看,有有区别的:
java本来就支持单继承,所以就有了抽象类
java没有多继承,所以为了接口隔离原则,设计了接口这个概念,支持多继承了
python及支持单继承也支持多继承,所以对接口类和抽象类的区别不是很明显,甚至在python中没有内置接口类。
多态和鸭子类型
多态:python填写支持多态
鸭子类型:不依赖父类的情况下实现两个相似的类中的同名方法;
封装------私有的。
在python中只要__名字
在python中只要__名字,就把这个名字私有化了。
私有化之后,就不能从类外部直接调用了。
静态属性、方法、对象属性,都可以私有化
这种私有化只是从代码级别做了变性,并没有真的约束
变形机制_类名__名字,在类外用这个调用,在类的内部直接__名字调用
7、内置函数property
1 from math import pi 2 3 class Circle: 4 def __init__(self,r): 5 self.r = r 6 7 @property #装饰器,使得下面的函数Perimetr可以在类外面进行像属性一样使用 8 def Perimeter(self): #如果被装饰,那么定义函数时候(self)只能这样,不能传参数 9 return 2*pi*self.r 10 @property 11 def area(self): 12 return pi*self.r**2 13 C1 = Circle(10) 14 print(C1.area) 15 print(C1.Perimeter)
314.1592653589793 62.83185307179586
利用proterty进行查看、修改、删除操作
1 class Person: 2 def __init__(self,name): 3 self.__name = name 4 @property 5 def name(self): 6 return self.__name 7 8 @name.deleter #出发对应一个del方法 9 def name(self): 10 del self.__name 11 @name.setter 12 def name(self,new_name):#唯一一个可以传参数的定义 13 self.__name = new_name 14 15 P1 = Person('peng') 16 print(P1.name) 17 del P1.name 18 print(P1.name)
peng Traceback (most recent call last): File "D:/python/Day26/property.py", line 38, in <module> print(P1.name) File "D:/python/Day26/property.py", line 26, in name return self.__name AttributeError: 'Person' object has no attribute '_Person__name'
改变静态属性:
1 class Goods: 2 __discount = 0.9 3 def __init__(self,name,price): 4 self.name = name 5 self.__price = price 6 @property 7 def price(self): 8 return self.__price * Goods.__discount 9 @classmethod 10 def change_discount(cls,new_discount): 11 cls.__discount = new_discount 12 apple = Goods('苹果',12) 13 print(apple.price) # 12 * 0.9 = 10.8 14 Goods.change_discount(0.5) #把类的静态属性__discount改了0.5 15 print(apple.price)
1 10.8 2 6.0
8、几个常见的装饰器方法
@staticmethod 静态方法 -------****:使得它下面的函数不用实例化就可以在类外进行调用。如果一个方法跟类及对象无关,可以直接在类外面调用时候,
可以采用staticmethod在类里面对这个方法进行装饰。
@classmethod 类方法-----------******:把一个方法变为类中的方法,这个方法就直接可以被类调用,不需要依托任何对象。如果要对类中的静态属性进行修改时候,
可以用classmethod装饰一个方法,然后在这个方法里面对类里面的静态属性进行修改。
@property 属性方法-------------****:当需要把一个方法在类外面当属性一样调用时候,可以在类里面对这个方法进行property进行装饰。
1 class Login: 2 def __init__(self,name,password): 3 self.name = name 4 self.pwd = password 5 def login(self): 6 pass 7 @staticmethod #使得下面的函数不用实例化也可以在类外进行调用 8 def get_usr_pwd(): 9 user = input('用户名:').strip() 10 pwd = input('密码:').strip() 11 Login(user,pwd) 12 Login.get_usr_pwd()
用户名:555
密码:hu
9、面向对象小结:
class 类名(父类1,父类2):
静态属性 = ‘’ #静态属性,类属性
def __init__(self): #初始化方法
self.name = 'peng'
def func(self): #动态属性,方法
print('12345')
对象= 类名()
对象.属性名
对象.方法名
对象.nmae
组合:表达的是什么有什么的关系,一个类的属性是另外一个类的对象
组合的例子:课程与班级
1 class Course: 2 def __init__(self,name,price,period): 3 self.name = name 4 self.price = price 5 self.period = period 6 7 Ai = Course('人工智能','19800','6个月') 8 9 class Classes: 10 def __init__(self,name,course,teacher,school): 11 self.name = name 12 self.course = course 13 self.teacher = teacher 14 self.school = school 15 16 AiS1 = Classes('Ai第一期',Ai,'彭老师','番禺校区')
19800
面向对象的三大特性:继承、多态、封装
继承:
单继承:
父类(超类,基类)
子类(派生类):派生方法和派生属性
多继承:
不会超过三个父类,不要超过三层
如果子类自己有就用自己的方法,子类没有就找跟它最近的父类的方法
抽象类和接口类
新式类和经典类:新式类是广度优先,经典类是深度优先
super:只能在python3中使用 _mro__
super是根据mro广度优先顺序找上一个类
多态: 多态和鸭子类型
封装: 私有的
__名字
只能在类的内部调用,子类都无法继承
三个装饰器:
proterty:装饰方法后,可以在类外部把方法伪装为属性进行调用
staticmethod:装饰方法后,这个方法可以直接在类外面采用类.方法的方式进行调用,无需进行实例化
classmethod:当一个方法只使用了类的静态变量时就给这个方法加上classmethod进行装饰,默认传cls参数,经典的例子是超市打折例子。
超市打折的经典例子:
1 class Goods: 2 __discount = 0.9 3 def __init__(self,name): 4 self.name = name 5 @classmethod 6 def change_discount(cls,new_discount): 7 cls.__discount = new_discount 8 def price(self,price): 9 return price * self.__discount 10 11 Apple = Goods('苹果') 12 13 print(Apple.price(100)) 14 Goods.change_discount(0.8) 15 print(Apple.price(100))
90.0 80.0
10、反射
hasatter、getatter、delatter
hasatter与getatte总是成夫妻挡出现,一般可以代替多个if else时候进行使用,加快算法
1 class Teacher: 2 dic = {'查看学生信息':'show_student','查看讲师信息':'show_teacher'} 3 def show_student(self): 4 print('show_student') 5 def show_teacher(self): 6 print('show_teacher') 7 @classmethod 8 def func(cls): 9 print('in cls') 10 peng = Teacher() 11 # for k in Teacher.dic: 12 # print(k) 13 key = input('请输入要查看信息:').strip() 14 if hasattr(peng,Teacher.dic[key]): #hasattr与getattr成配对出现,有相应字典的值则调用相关的函数 15 func = getattr(peng,Teacher.dic[key]) 16 func()
1 请输入要查看信息:查看学生信息 2 show_student
isinstance(obj,cls)检查obj是否是类cls的对象
1 class Foo(object): 2 pass 3 obj = Foo() 4 print(isinstance(obj,Foo))
True
issubclass(sub,super)检查sub类是否是super类的派生类
1 class Foo(object): 2 pass 3 class Bar(Foo): 4 pass 5 print(issubclass(Bar,Foo))
1 True
通过变量名的字符串形式取到的值
1 class A: 2 def func(self): 3 print('打印func函数') 4 a = A() 5 a.name = 'peng' 6 a.age = 30 7 #反射对象的属性 8 ret = getattr(a,'name') #通过变量名的字符串形式取到的值 9 print(ret) 10 print(a.__dict__) 11 someone = input('>>>') 12 print(getattr(a,someone)) 13 print(a.__dict__[someone])
peng {'name': 'peng', 'age': 30} >>>
反射可以判断方法是否在导入的模块中
import mypython ret = print(getattr(mypython,'day')) #反射方法 year = 2020 import sys print(sys.modules['__main__'].year) #
1 <function day at 0x00000000027FD730> 2 2020
1 class A: 2 def __str__(self): 3 return 'peng 加油' 4 a = A() 5 print(a) #打印一个对象时候,就是调用对象所在类里面的__str__ 6 #object 里有一个__str__,一旦被调用,就返回调用这个方法的对象的内存地址 7 8 print('%s:%s'%('A',a)) # %s str(),直接打印,实际上都是执行__str__
1 peng 加油 2 A:peng 加油
__repr__是__str__的备胎,当类里面没有__str__时,会把__repr__当作__str__来使用,如果也没有则调用父类的方法
__repr__没有备胎,类里面没有这个方法则在父类里面找,父类里面没有就报错
1 class Teacher: 2 def __init__(self,name,salary): 3 self.name = name 4 self.salary = salary 5 self.student = [] 6 def __str__(self): #这里一定要有返回 7 return "Teacher is XXX:%s"%self.name 8 def __repr__(self): #这里一定要有返回 9 return str(self.__dict__) 10 def func(self): 11 return "中国人" 12 def __len__(self): 13 return len(self.student) 14 def __del__(self): #析构函数,即删除文件之前作了收尾工作 15 print('执行删除操作') 16 def __call__(self, *args, **kwargs): 17 print('执行了call方法') 18 peng = Teacher('彭老师',5000) 19 peng.student.append('张三') 20 peng.student.append('张三') 21 peng.student.append('张三') 22 print(peng) 23 print(repr(peng)) 24 print('%r'%peng) 25 print(len(peng)) 26 li = Teacher('李老师',500)() 27 28 del peng #既执行了__del__这个方法,也删除了对象peng
1 Teacher is XXX:彭老师 2 {'name': '彭老师', 'salary': 5000, 'student': ['张三', '张三', '张三']} 3 {'name': '彭老师', 'salary': 5000, 'student': ['张三', '张三', '张三']} 4 3 5 执行了call方法 6 执行删除操作 7 执行删除操作
11、item系列 : __getitem__\__setitem__\__delitem__
__del__:析构方法,当对象在内存中被释放时,自动触发执行。
注意:此方法一般无需定义,因为python是一门高级语言,程序员在使用时无需关系内存的分配和释放,因此工作都交给python解释器来执行,则析构函数的调用时解释器在进行垃圾回收时自动触发执行的。例如:
1 class Foo: 2 def __del__(self): 3 print("执行了__del__函数") 4 f1 = Foo() 5 del f1
执行了__del__函数
__new__:单例模式可用到,就是只有一个实例时候
1 class A: 2 def __init__(self): 3 self.x = 1 4 print('in init function') 5 def __new__(cls, *args, **kwargs): 6 print('in new function') 7 return object.__new__(A) 8 a = A() 9 print(a.x)
1 in new function 2 in init function 3 1
1 class Singleton: 2 def __new__(cls, *args, **kwargs): 3 if not hasattr(cls,'_instance'): 4 cls._instance = object.__new__(cls) 5 return cls._instance 6 A = Singleton() 7 B = Singleton() 8 9 print(A == B) 10 print(id(A)) 11 print(id(B))
True
32031072
32031072
__call__:对象后面加括号,触发执行
注意:构造方法的执行时由创建对象触发的,即:对象= 类名();而对于__call__方法的执行是由对象后加括号触发的,即:对象或者类()()
1 class Foo: 2 def __init__(self): 3 print('执行了__init__函数') 4 def __call__(self, *args, **kwargs): 5 print('执行了__call__函数') 6 7 A = Foo() 8 A()
执行了__init__函数
执行了__call__函数
with和__enter__,__exit__
1 class A: 2 def __enter__(self): 3 print('before') 4 5 def __exit__(self, exc_type, exc_val, exc_tb): 6 print('after') 7 8 9 with A() as a: 10 print('123')
before 123 after
class A: def __init__(self): print('init') def __enter__(self): print('before') def __exit__(self, exc_type, exc_val, exc_tb): print('after') with A() as a: print('123')
before 123 after
class Myfile: def __init__(self,path,mode='r',encoding = 'utf-8'): self.path = path self.mode = mode self.encoding = encoding def __enter__(self): self.f = open(self.path, mode=self.mode, encoding=self.encoding) return self.f def __exit__(self, exc_type, exc_val, exc_tb): self.f.close() with Myfile('file',mode='w') as f: f.write('wahaha')
import pickle class MyPickledump: def __init__(self,path): self.path = path def __enter__(self): self.f = open(self.path, mode='ab') return self def dump(self,content): pickle.dump(content,self.f) def __exit__(self, exc_type, exc_val, exc_tb): self.f.close() class Mypickleload: def __init__(self,path): self.path = path def __enter__(self): self.f = open(self.path, mode='rb') return self def __exit__(self, exc_type, exc_val, exc_tb): self.f.close() def __iter__(self): while True: try: yield pickle.load(self.f) except EOFError: break # with MyPickledump('file') as f: # f.dump({1,2,3,4}) with Mypickleload('file') as f: for item in f: print(item)
__len__:统计类有多少个属性
class A: def __init__(self): self.a = 1 self.b = 2 def __len__(self): return len(self.__dict__) a = A() print(len(a))
__eq__
1 class A: 2 def __init__(self): 3 self.a = 1 4 self.b = 2 5 6 def __eq__(self,obj): 7 if self.a == obj.a and self.b == obj.b: 8 return True 9 a = A() 10 b = A() 11 print(a == b)
True
__hash__:判断是否可以哈希
class A: def __init__(self): self.a = 1 self.b = 2 def __hash__(self): return hash(str(self.a)+str(self.b)) a = A() print(hash(a))
-3798929607606950646
纸牌游戏
1 Card = namedtuple('Card',['rank','suit']) 2 class FranchDeck: 3 ranks = [str(n) for n in range(2,11)]+ list('JQKA') 4 suits = ['红心','方块','梅花','黑桃'] 5 def __init__(self): 6 self._cards = [Card(rank,suit) for rank in FranchDeck.ranks for suit in FranchDeck.suits] 7 def __len__(self): 8 return len(self._cards) 9 def __getitem__(self, item): 10 return self._cards[item] 11 deck = FranchDeck() 12 print(deck[0]) 13 from random import choice 14 print(choice(deck)) 15 print(choice(deck))
Card(rank='2', suit='红心') Card(rank='J', suit='黑桃') Card(rank='2', suit='黑桃')
面试题:怎么实现录入人的信息时候,根据姓名、性别去重对象,而跟年龄无关,即同一个人第二年录入时候年龄变了,但其他基本信息没有变。
class Person: def __init__(self,name,age,sex): self.name = name self.age = age self.sex = sex def __hash__(self): return hash(self.name + self.sex) def __eq__(self, other): if self.name == other.name and self.sex == other.sex: return True p_lst = [] for i in range(100): p_lst.append(Person('peng',i,'male')) print(p_lst) print(set(p_lst))
[<__main__.Person object at 0x0000000001EAB710>, <__main__.Person object at 0x0000000001EAB748>, <__main__.Person object at 0x0000000001EAB780>, <__main__.Person object at 0x0000000001EAB7B8>, <__main__.Person object at 0x0000000001EAB7F0>, <__main__.Person object at 0x0000000001EAB828>, <__main__.Person object at 0x0000000001EAB860>, <__main__.Person object at 0x0000000001EAB898>, <__main__.Person object at 0x0000000001EAB8D0>, <__main__.Person object at 0x0000000001EAB908>, <__main__.Person object at 0x0000000001EAB940>, <__main__.Person object at 0x0000000001EAB978>, <__main__.Person object at 0x0000000001EAB9B0>, <__main__.Person object at 0x0000000001EAB9E8>, <__main__.Person object at 0x0000000001EABA20>, <__main__.Person object at 0x0000000001EABA58>, <__main__.Person object at 0x0000000001EABA90>, <__main__.Person object at 0x0000000001EABAC8>, <__main__.Person object at 0x0000000001EABB00>, <__main__.Person object at 0x0000000001EABB38>, <__main__.Person object at 0x0000000001EABB70>, <__main__.Person object at 0x0000000001EABBA8>, <__main__.Person object at 0x0000000001EABBE0>, <__main__.Person object at 0x0000000001EABC18>, <__main__.Person object at 0x0000000001EABC50>, <__main__.Person object at 0x0000000001EABC88>, <__main__.Person object at 0x0000000001EABCC0>, <__main__.Person object at 0x0000000001EABCF8>, <__main__.Person object at 0x0000000001EABD30>, <__main__.Person object at 0x0000000001EABD68>, <__main__.Person object at 0x0000000001EABDA0>, <__main__.Person object at 0x0000000001EABDD8>, <__main__.Person object at 0x0000000001EABE10>, <__main__.Person object at 0x0000000001EABE48>, <__main__.Person object at 0x0000000001EABE80>, <__main__.Person object at 0x0000000001EABEB8>, <__main__.Person object at 0x0000000001EABEF0>, <__main__.Person object at 0x0000000001EABF28>, <__main__.Person object at 0x0000000001EABF60>, <__main__.Person object at 0x0000000001EABF98>, <__main__.Person object at 0x0000000001EABFD0>, <__main__.Person object at 0x0000000001EB6048>, <__main__.Person object at 0x0000000001EB6080>, <__main__.Person object at 0x0000000001EB60B8>, <__main__.Person object at 0x0000000001EB60F0>, <__main__.Person object at 0x0000000001EB6128>, <__main__.Person object at 0x0000000001EB6160>, <__main__.Person object at 0x0000000001EB6198>, <__main__.Person object at 0x0000000001EB61D0>, <__main__.Person object at 0x0000000001EB6208>, <__main__.Person object at 0x0000000001EB6240>, <__main__.Person object at 0x0000000001EB6278>, <__main__.Person object at 0x0000000001EB62B0>, <__main__.Person object at 0x0000000001EB62E8>, <__main__.Person object at 0x0000000001EB6320>, <__main__.Person object at 0x0000000001EB6358>, <__main__.Person object at 0x0000000001EB6390>, <__main__.Person object at 0x0000000001EB63C8>, <__main__.Person object at 0x0000000001EB6400>, <__main__.Person object at 0x0000000001EB6438>, <__main__.Person object at 0x0000000001EB6470>, <__main__.Person object at 0x0000000001EB64A8>, <__main__.Person object at 0x0000000001EB64E0>, <__main__.Person object at 0x0000000001EB6518>, <__main__.Person object at 0x0000000001EB6550>, <__main__.Person object at 0x0000000001EB6588>, <__main__.Person object at 0x0000000001EB65C0>, <__main__.Person object at 0x0000000001EB65F8>, <__main__.Person object at 0x0000000001EB6630>, <__main__.Person object at 0x0000000001EB6668>, <__main__.Person object at 0x0000000001EB66A0>, <__main__.Person object at 0x0000000001EB66D8>, <__main__.Person object at 0x0000000001EB6710>, <__main__.Person object at 0x0000000001EB6748>, <__main__.Person object at 0x0000000001EB6780>, <__main__.Person object at 0x0000000001EB67B8>, <__main__.Person object at 0x0000000001EB67F0>, <__main__.Person object at 0x0000000001EB6828>, <__main__.Person object at 0x0000000001EB6860>, <__main__.Person object at 0x0000000001EB6898>, <__main__.Person object at 0x0000000001EB68D0>, <__main__.Person object at 0x0000000001EB6908>, <__main__.Person object at 0x0000000001EB6940>, <__main__.Person object at 0x0000000001EB6978>, <__main__.Person object at 0x0000000001EB69B0>, <__main__.Person object at 0x0000000001EB69E8>, <__main__.Person object at 0x0000000001EB6A20>, <__main__.Person object at 0x0000000001EB6A58>, <__main__.Person object at 0x0000000001EB6A90>, <__main__.Person object at 0x0000000001EB6AC8>, <__main__.Person object at 0x0000000001EB6B00>, <__main__.Person object at 0x0000000001EB6B38>, <__main__.Person object at 0x0000000001EB6B70>, <__main__.Person object at 0x0000000001EB6BA8>, <__main__.Person object at 0x0000000001EB6BE0>, <__main__.Person object at 0x0000000001EB6C18>, <__main__.Person object at 0x0000000001EB6C50>, <__main__.Person object at 0x0000000001EB6C88>, <__main__.Person object at 0x0000000001EB6CC0>, <__main__.Person object at 0x0000000001EB6CF8>] {<__main__.Person object at 0x0000000001EAB710>}
12、hashlib模块
1 import hashlib 2 3 user = input('输入用户名:').strip() 4 passwd = input('输入密码:').strip() 5 6 with open('info') as f: 7 for line in f: 8 usr,pwd,lit = line.split('|') 9 md5 = hashlib.md5(bytes('salt',encoding='utf-8')) 10 md5.update(bytes(passwd,encoding='utf-8')) 11 md5_pwd = md5.hexdigest() 12 if usr == user and pwd == md5_pwd: 13 print('登陆成功')
peng|f51703256a38e6bab3d9410a070c32ea|fdfdf
输入用户名:peng 输入密码:123456 登陆成功
小节:摘要算法
不管算法怎么不同,摘要的功能始终不变
对于相同的字符串使用同一个算法进行摘要,得到的值应该不变
使用不同的算法对相同的字符串进行摘要,得到的值应该不同
不管用什么算法,hashlib的算法不变
主要应用于密文存储
一段字符串进行单次完整摘要跟分段摘要的结果是一样的,我们对一个文档进行摘要时候不需要进行加盐操作
13、日志
代码日志有两种打印及保存模块:logging、basicconfig
basicconfig功能比较少,而且中文的日志信息会出错,不能同事往文件和终端界面打印信息
logging有5个输出信息,打印的信息只会打印包含自己在内警告级别更高的信息
logging可自由定制,上面fh是输出到日志文件保存的,sh是输出到控制端显示的
一个要发布的工程必须要有日志,方便维护
import logging logger = logging.getLogger() fh = logging.FileHandler('LOG.log',encoding='utf-8') sh = logging.StreamHandler() fmatter1 = logging.Formatter('%(asctime)s-%(name)s-%(levelname)s-%(message)s') fmatter2 = logging.Formatter('%(asctime)s-%(name)s-%(levelname)s-%(message)s') #把文件操作符与格式关联 fh.setFormatter(fmatter1) sh.setFormatter(fmatter2) #把文件操作符与logger对象关联 logger.addHandler(fh) logger.addHandler(sh) logger.debug('This Debug Message')#低级别,排错信息 logger.info('This Message')#正常信息 logger.warning('This warning Message')#警告信息 logger.error('This error Message')#错误信息 logger.critical('This critical Message')#高级别的严重错误信息
2020-07-03 09:15:46,394-root-WARNING-This warning Message 2020-07-03 09:15:46,399-root-ERROR-This error Message 2020-07-03 09:15:46,399-root-CRITICAL-This critical Message
2020-07-03 09:04:45,211-root-WARNING-This Debug Message 2020-07-03 09:04:45,212-root-ERROR-This Debug Message 2020-07-03 09:04:45,212-root-CRITICAL-This Debug Message 2020-07-03 09:05:23,781-root-WARNING-This Debug Message 2020-07-03 09:05:23,781-root-ERROR-This Debug Message 2020-07-03 09:05:23,781-root-CRITICAL-This Debug Message 2020-07-03 09:05:29,876-root-WARNING-This Debug Message 2020-07-03 09:05:29,877-root-ERROR-This Debug Message 2020-07-03 09:05:29,877-root-CRITICAL-This Debug Message 2020-07-03 09:09:43,186-root-WARNING-This Debug Message 2020-07-03 09:09:43,186-root-ERROR-This Debug Message 2020-07-03 09:09:43,186-root-CRITICAL-This Debug Message 2020-07-03 09:15:46,394-root-WARNING-This warning Message 2020-07-03 09:15:46,399-root-ERROR-This error Message 2020-07-03 09:15:46,399-root-CRITICAL-This critical Message