首页 > 代码库 > Python自动化开发课堂笔记【Day07】 - Python进阶(类)- 02

Python自动化开发课堂笔记【Day07】 - Python进阶(类)- 02

类与对象

对象是特征(变量)与技能(函数)的结合体,类是一系列对象共有的特征与技能的结合体
  现实生活中:先有对象,再总结归纳出类
  程序中:一定是先定义类,再实例化出对象
定义类的语法:
class 类名:
  ‘‘‘注释‘‘‘
  类体(可以是任意代码)

1 class Chinese:
2     country = China
3     def __init__(self,name,age):
4         self.name = name
5         self.age = age
6         print(--->,self.name,self.age)
7     def talk(self):
8         print(say Chinese)

1. 类的第一种用法,实例化

1 p1 = Chinese(Albert,18)
2 p2 = Chinese(Baker,33)

2. 类的第二种用法,属性引用

1 print(Chinese.country)#类的数据属性
2 print(Chinese.__init__)#类的函数属性
3 p1.__init__(Talbert,81)

  3. 其他知识点补充

 1 print(Chinese.__dict__)#查看类的属性字典,或者说是名称空间
 2 #{‘__module__‘: ‘__main__‘, ‘__doc__‘: None, ‘talk‘: <function Chinese.talk at 0x00675D68>, ‘__weakref__‘: <attribute ‘__weakref__‘ of ‘Chinese‘ objects>, ‘country‘: ‘China‘, ‘__dict__‘: <attribute ‘__dict__‘ of ‘Chinese‘ objects>, ‘__init__‘: <function Chinese.__init__ at 0x00675228>}
 3 print(Chinese.country)
 4 print(Chinese.__dict__[country])#效果同上,本质上是如何取到的country这个变量
 5 print(p1.name,p1.age)
 6 print(p1.__dict__[name],p1.__dict__[age])
 7 
 8 #类型和类是统一的
 9 print(type(p1)) #<class ‘__main__.Chinese‘>
10 
11 #类中定义的变量对象是公用的,不会产生新的内存空间
12 print(id(p1.country)) #5593664
13 print(id(p2.country)) #5593664
14 print(id(Chinese.country)) #5593664

类绑定方法(类实例化后绑定到对象身上)
绑定方法:绑定到谁身上就是给谁用的,谁来调用就会自动把自己当作第一个参数传入

1 print(Chinese.talk) #<function Chinese.talk at 0x006F5D68>
2 print(p1.talk) #<bound method Chinese.talk of <__main__.Chinese object at 0x002759F0>>
3 print(p2.talk) #<bound method Chinese.talk of <__main__.Chinese object at 0x0070EB50>>

总结:定义在类内部的变量是所有对象共有的,id全一样。定义在类内部的函数,是绑定到所有对象的,是给对象来用的,obj.func()会把obj本身当作第一个参数传入
  print(p1.x) # p1.__dict__ ---> Chinese.__dict__ ---> 报错
如果要查找一个属性,先从对象名称空间中查找,找不到之后再到类名称空间查找,如果还找不到不会再去全局找,直接报错

练习:

 1 1.统计类实例化对象的次数
 2 class Chinese:
 3     country = China
 4     count = 0
 5     def __init__(self,name,age):
 6         self.name = name
 7         self.age = age
 8         Chinese.count += 1 #类变量的概念
 9         print(--->,self.name,self.age)
10         print(%d obj create % Chinese.count)
11 p1=Chinese(A,1)
12 p2=Chinese(B,2)
13 
14 2.定义一个学生类
15 class Stu:
16     def __init__(self,stuid,name,age):
17         self.stuid = stuid
18         self.name = name
19         self.age = age
20         print(Student--->,self.stuid,self.name,self.age)
21 s1 = Stu(1,A,18)
22 s2 = Stu(2,B,18)
23 
24 3.类对象交互
25 class A:
26     camp = AAA
27     def __init__(self,nickname,damage=100, HP=200):
28         self.nickname = nickname
29         self.damage = damage
30         self.HP = HP
31     def attack(self,enemy):
32         enemy.HP -= self.damage
33         print(造成%d点伤害 % self.damage)
34 class B:
35     camp = BBB
36     def __init__(self,nickname,damage=200, HP=100):
37         self.nickname = nickname
38         self.damage = damage
39         self.HP = HP
40     def attack(self,enemy):
41         enemy.HP -= self.damage
42         print(造成%d点伤害 % self.damage)
43 a1 = A(a1)
44 b1 = B(b1)
45 print(a1.camp)
46 print(b1.camp)
47 a1.attack(b1)
48 b1.attack(a1)

继承

  继承是一种创建新类的方式,新建的类可以继承一个或多个父类,父类又可以称为基类或超类,新建的类称为派生类或子类

1 class ParentClass1:
2     pass
3 class ParentClass2:
4     pass
5 class SubClass1(ParentClass1):
6     pass
7 class SubClass2(ParentClass1,ParentClass2):
8     pass

如何查看继承的父类

1 print(SubClass1.__bases__) #(<class ‘__main__.ParentClass1‘>,)
2 print(SubClass2.__bases__) #(<class ‘__main__.ParentClass1‘>, <class ‘__main__.ParentClass2‘>)

  类的种类

 1 #Python2中分为新式类和经典类
 2 #新式类(有括号的,有继承关系的) 
 3 class Foo(object):
 4     pass
 5 #经典类(没括号的,谁都不继承)
 6 class Bar:
 7     pass
 8 #Python3中全部都是经典类(即使没有括号也是新式类)
 9 class Foo:
10     pass
11 print(Foo.__bases__) #(<class ‘object‘>,)

继承的好处:
  1.减少冗余代码
  2.在子类定义新的属性,覆盖掉父类的属性,称为派生

 1 class Animal:
 2     def __init__(self,name,age,sex):
 3         self.name = name
 4         self.age = age
 5         self.sex =sex
 6     def eat(self):
 7         print(eating...)
 8     def talk(self):
 9         print(%s saying... % self.name)
10 class People(Animal):
11     def __init__(self,name,age,sex,edu):
12         Animal.__init__(self,name,age,sex)
13         self.edu = edu
14     def talk(self):
15         Animal.talk(self)
16         print(%s say hello % self.name)
17 class Pig(Animal):
18     pass
19 class Dog(Animal):
20     pass
21 p1 = People(p1,18,male,college)
22 g1 = Pig(g1,11,female)
23 d1 = Dog(d1,22,male)
24 print(p1.edu)
25 p1.talk()
26 g1.talk()
27 d1.talk()
28 print(isinstance(p1,People))
29 print(isinstance(g1,Pig))
30 print(isinstance(d1,Dog))

  对象如果要调用方法,先从对象自己的命名空间找,然后是自己的类,最后是父类,依次往上找

 1 class Parent:
 2     def foo(self):
 3         print(Parent.foo)
 4         self.bar()
 5     def bar(self):
 6         print(Parent.bar)
 7 class Sub(Parent):
 8     def bar(self):
 9         print(Sub.bar)
10 s=Sub()
11 s.foo() # Parent.foo
12         # Sub.bar

继承反应的是一种什么是什么的关系
组合也可以解决代码冗余的问题,但是组合反应的是一种什么有什么的关系

 1 class People:
 2     def __init__(self,name,age,sex):
 3         self.name=name
 4         self.age=age
 5         self.sex=sex
 6 class Date:
 7     def __init__(self,y,m,d):
 8         self.y = y
 9         self.m = m
10         self.d = d
11     def tell(self):
12         print(%s-%s-%s % (self.y,self.m,self.d))
13 class Teacher(People):
14     def __init__(self,name,age,sex,salary,y,m,d):
15         People.__init__(self,name,age,sex)
16         self.salary = salary
17         self.birth = Date(y,m,d)
18 
19 class Student(People):
20     def __init__(self,name,age,sex,y,m,d):
21         People.__init__(self,name,age,sex)
22         self.birth = Date(y,m,d)
23 
24 t1 = Teacher(A,18,male,3000,2000,1,1)
25 t1.birth.tell()

抽象类

 1 import abc
 2 class File(metaclass=abc.ABCMeta):
 3     @abc.abstractmethod
 4     def read(self):
 5         pass
 6     @abc.abstractmethod
 7     def write(self):
 8         pass
 9 class Txt(File):
10     def read(self):
11         pass
12     def write(self):
13         pass
14 p=Txt()

继承搜索顺序:
Python2中,分为
广度优先(新式类)F->D->B->A->E->C->H
深度优先(经典类)F->D->B->E->C->H->A
Python3中,只有广度优先(python3中只有新式类)

 1 class A:
 2     def test(self): print(from A)
 3     pass
 4 class B(A):
 5     def test(self): print(from B)
 6     pass
 7 class C(A):
 8     def test(self): print(from C)
 9     pass
10 class D(B):
11     def test(self): print(from D)
12     pass
13 class E(C):
14     def test(self): print(from E)
15     pass
16 class H(A):
17     def test(self): print(from H)
18     pass
19 class F(D,E,H):
20     def test(self): print(from F)
21     pass
22 f=F()
23 f.test()
24 print(F.mro())
25 #[<class ‘__main__.F‘>, <class ‘__main__.D‘>, <class ‘__main__.B‘>, <class ‘__main__.E‘>,
26 # <class ‘__main__.C‘>, <class ‘__main__.H‘>, <class ‘__main__.A‘>, <class ‘object‘>]

子类中重用父类的方法(super)

 1 class Foo:
 2     def test(self):
 3         print(from foo.test)
 4 class Bar(Foo):
 5     def test(self):
 6         super().test()
 7         print(from bar.test)
 8 b = Bar()
 9 b.test()
10 
11 class Foo1:
12     def test(self):
13         print(from foo1.test)
14 class Foo2:
15     def test(self):
16         print(from foo2.test)
17 class Bar(Foo1,Foo2):
18     def test(self):
19         super().test()
20         print(from bar.test)
21 b = Bar()
22 b.test() #from foo1.test
23          #from bar.test

多态与多态性

没有多态就没有多态性
多态:同一种事物的多种形态
多态性:指的是具有不同功能的函数可以使用相同的函数名

 1 class Animal:
 2     def eat(self):
 3         print(eating...)
 4 class People(Animal):
 5     def eat(self):
 6         print(eating...)
 7 class Pig(Animal):
 8     def eat(self):
 9         print(eating...)
10 class Dog(Animal):
11     def eat(self):
12         print(eating...)
13 p1=People()
14 g1=Pig()
15 d1=Dog()
16 def func(obj):
17     obj.eat()
18 func(p1)
19 func(g1)
20 func(d1)

封装

为什么要封装:保护隐私,隔离复杂度
Python没有真正的隐藏,只是从语法级别做了些改变

 1 class Foo:
 2     __x = 1 # ‘_Foo__x‘: 1
 3     def __test(self): # ‘_Foo__test‘: <function Foo.__test at 0x00665D68>
 4         print(from test)
 5 print(Foo.__dict__)
 6 print(Foo._Foo__x)
 7 print(Foo._Foo__test)
 8 
 9 class People:
10     __country = Chinese
11     def __init__(self,name,age,sex):
12         self.__name=name #只在定义阶段才会发生变形,实例产生后新加入的变量就不会变形了
13         self.__age=age
14         self.__sex=age
15     def tell_info(self):
16         print(%s:%s:%s % (self.__name,self.__age,self.__sex))
17 p=People(alex,18,male)
18 print(p.__dict__) #{‘_People__age‘: 18, ‘_People__sex‘: 18, ‘_People__name‘: ‘alex‘}
19 p.tell_info()
20 p.__salary = 3000
21 print(p.__dict__) #{‘_People__name‘: ‘alex‘, ‘_People__sex‘: 18, ‘_People__age‘: 18, ‘__salary‘: 3000}
22 
23 class People:
24     __country = Chinese
25     def __init__(self,name,age):
26         self.__name=name
27         self.__age=age
28     def tell_info(self):
29         print(Name:%s,Age:%d % (self.__name,self.__age))
30     def set_info(self,x,y):
31         if not isinstance(x,str):
32             raise TypeError(must be str!!!)
33         if not isinstance(y,int):
34             raise TypeError(must be int!!!)
35         self.__name = x
36         self.__age = y
37 p1 = People(Albert,18)
38 p1.tell_info() # Name:Albert,Age:18
39 p1.set_info(Baker,22)
40 p1.tell_info() # Name:Baker,Age:22

关于property的应用

 1 应用1:
 2 class Foo:
 3     @property
 4     def test(self):
 5         print(from foo)
 6     # test = property(test)
 7 f=Foo()
 8 # f.test() #from foo
 9 f.test #from foo
10 
11 应用2:
12 class People:
13     def __init__(self,name,weight,height):
14         self.name = name
15         self.weight = weight
16         self.height = height
17     @property
18     def bmi(self):
19         return self.weight / (self.height ** 2)
20 p = People(Albert,75,1.80)
21 p.height=1.82
22 print(p.bmi)
23 
24 应用3:
25 import math
26 class Circle:
27     def __init__(self,radius):
28         self.raduis = radius
29     @property
30     def zc(self):
31         return 2 * math.pi * self.raduis
32 c = Circle(5)
33 print(c.zc)
34 
35 应用4:
36 class Person:
37     def __init__(self,name,permission=False):
38         self.__name = name
39         self.permission = permission
40     @property
41     def name(self):
42         return self.__name
43     @name.setter
44     def name(self,value):
45         if not isinstance(value,str):
46             raise TypeError(must be str)
47         self.__name = value
48     @name.deleter
49     def name(self):
50         if not self.permission:
51             raise PermissionError(not allowed)
52         del self.__name
53 p=Person(Albert)
54 print(p.name)
55 p.name=Baker
56 print(p.name)
57 p.permission = True
58 del p.name

绑定

类中定义的函数分成两大类:
1.绑定方法(绑定给谁,谁来调用就自动将它本身当作第一个参数传入)
  1.绑定到类的方法:用classmethod装饰器装饰的方法。
    为类量身定制
    类.bound_method(),自动将类当作第一个参数传入(其实对象也可调用,但仍将类当作第一个参数传入)
  2.绑定到对象的方法:没有被任何装饰器装饰的方法。
    为对象量身定制
    对象.bound_method(),自动将对象当作第一个参数传入(属于类的函数,类可以调用,但是必须按照函数的规则来,没有自动传值的说法)

2.非绑定方法:用staticmethod装饰器装饰的方法
  不与类或对象绑定,类和对象都可以调用,但是没有自动传值那么一说,就是一个普通工具而已

 1 #绑定到类的方法
 2 class Foo:
 3     @classmethod
 4     def test(cls):
 5         print(cls)
 6 Foo.test() #<class ‘__main__.Foo‘>
 7 #跟谁都不绑定的方法
 8 class Foo:
 9     @staticmethod
10     def test(x,y):
11         print(test,x,y)
12 Foo.test(1,3)
13 f=Foo()
14 f.test(2,4)

示例

 1 #setting文件配置
 2 # HOST = ‘127.0.0.1‘
 3 # PORT = 3306
 4 import setting
 5 import hashlib
 6 import time
 7 class MySQL:
 8     def __init__(self,host,port):
 9         self.sql_id = self.sql_id()
10         self.host = host
11         self.port = port
12         print(connecting...)
13     @classmethod
14     def from_conf(cls):
15         return cls(setting.HOST,setting.PORT) #相当于MySQL(host,port)
16     @staticmethod
17     def sql_id():
18         m = hashlib.md5(str(time.clock()).encode(utf-8))
19         return m.hexdigest()
20     def select(self):
21         print(self) #<__main__.MySQL object at 0x0060E2D0>
22         print(select func,self.host,self.port)
23 
24 conn1 = MySQL(192.168.1.1,3306)
25 conn1.select()
26 print(conn1.sql_id)
27 conn2 = MySQL.from_conf()
28 print(conn2.sql_id)

staticmeth与classmethod的区别

 1 class Person:
 2     def __init__(self,name,age):
 3         self.name = name
 4         self.age = age
 5     def __str__(self):
 6         print(run __str__)
 7         return name:%s age:%s % (self.name, self.age)
 8 p = Person(Albert,19)
 9 print(p)
10 
11 #setting文件配置
12 # HOST = ‘127.0.0.1‘
13 # PORT = 3306
14 import setting
15 class MySQL:
16     def __init__(self,host,port):
17         self.host = host
18         self.port = port
19         print(connecting...)
20     @classmethod
21     def from_conf(cls):
22         return cls(setting.HOST, setting.PORT)
23     def __str__(self):
24         return from MySQL
25 class Mariadb(MySQL):
26     def __str__(self):
27         print(self.host,self.port)
28         return from Maria
29 conn1 = Mariadb.from_conf()
30 print(conn1)

反射(自省)

反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问,检测和修改它本身状态或行为的一种能力。
Python面向对象中的反射:通过字符串的形式操作对象相关的属性。Python中的一切皆对象(都可以使用反射)

 1 class People:
 2     country = China
 3     def __init__(self,name,age):
 4         self.name=name
 5         self.age=age
 6 print(People.country)
 7 p = People(Albert,18)
 8 print(p)
 9 print(hasattr(p,name)) # True
10 print(hasattr(People,country)) #True
11 setattr(p,sex,male)
12 print(p.__dict__) # {‘age‘: 18, ‘name‘: ‘Albert‘, ‘sex‘: ‘male‘}
13 print(getattr(p,nam,not exist)) # not exist
14 print(getattr(p,name))
15 # setattr(p,‘x‘,1)
16 if hasattr(p,x):
17     res = getattr(p,x)
18     print(res)
19 delattr(p,sex)
20 print(p.__dict__)

练习

 1 import sys
 2 res = sys.modules[__name__] #获取当前模块 <module ‘__main__‘ from ‘C:/Users/ajiax/PycharmProjects/Python17/Day07/ALesson07.py‘>
 3 print(res)
 4 if hasattr(res,People):
 5     get = getattr(res,People)
 6     print(get)
 7     obj=get(Baker,22)
 8 print(obj.name)
 9 
10 
11 class FTPClient:
12     def __init__(self,host):
13         self.host=host
14         print(connecting...%s % self.host)
15     def interactive(self):
16         while True:
17             cmd_line = input(>>>:).strip()
18             cmd_list = cmd_line.split()
19             if hasattr(self,cmd_list[0]):
20                 func = getattr(self,cmd_list[0])
21                 func(cmd_list)
22     def get(self,args):
23         print(downloading...%s % args[1])
24 p = FTPClient(127.0.0.1)
25 p.interactive()

Python自动化开发课堂笔记【Day07】 - Python进阶(类)- 02