面向对象

一、面向对象初步

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) #调用方法
View Code
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())
View Code
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)
View Code
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())
View Code
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)
View Code
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__)
View Code
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
View Code

 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方法。总结:自己有,就不用别人的。
View Code

 派生属性:父类中没有的属性,在子类中出现,叫派生属性

派生方法:父类中没有的方法,在子类中出现,叫叫派生方法;

子类的对象调用,子类中有的名字一定用子类的,子类没有才从父类找,如果父类没有就报错。

如果父类、子类都有,那么用子类的

如果想用父类的,则单独调用父类的。

 例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()
View Code
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__'
View Code

 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)
例程1
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
View Code

 

利用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'
View Code

 

改变静态属性:

 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
View Code

 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()
View Code
1 请输入要查看信息:查看学生信息
2 show_student
View Code

 

  

isinstance(obj,cls)检查obj是否是类cls的对象
1 class Foo(object):
2     pass
3 obj = Foo()
4 print(isinstance(obj,Foo))
True
View Code
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}
>>>
View Code
反射可以判断方法是否在导入的模块中
import mypython

ret = print(getattr(mypython,'day')) #反射方法
year = 2020
import sys
print(sys.modules['__main__'].year) #
1 <function day at 0x00000000027FD730>
2 2020
View Code
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 加油
View Code
__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 执行删除操作
View Code

 

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')
with和文件操作
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))
纸牌游戏1
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))
View Code
[<__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>}
参考结果
 
当调用函数set()时会自动关联调用内置函数__hash__及__eq__

 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
LOG.log文件显示的信息

 


posted @ 2020-05-28 23:05  xiaofeiAI  阅读(28)  评论(0编辑  收藏  举报