类与对象
对象是特征(变量)与技能(函数)的结合体,类是一系列对象共有的特征与技能的结合体
现实生活中:先有对象,再总结归纳出类
程序中:一定是先定义类,再实例化出对象
定义类的语法:
class 类名:
'''注释'''
类体(可以是任意代码)
1 classChinese:2 country = 'China'
3 def __init__(self,name,age):4 self.name =name5 self.age =age6 print('--->',self.name,self.age)7 deftalk(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': , '__weakref__': , 'country': 'China', '__dict__': , '__init__': }
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)) #
10
11 #类中定义的变量对象是公用的,不会产生新的内存空间
12 print(id(p1.country)) #5593664
13 print(id(p2.country)) #5593664
14 print(id(Chinese.country)) #5593664
类绑定方法(类实例化后绑定到对象身上)
绑定方法:绑定到谁身上就是给谁用的,谁来调用就会自动把自己当作第一个参数传入
1 print(Chinese.talk) #
2 print(p1.talk) #>
3 print(p2.talk) #>
总结:定义在类内部的变量是所有对象共有的,id全一样。定义在类内部的函数,是绑定到所有对象的,是给对象来用的,obj.func()会把obj本身当作第一个参数传入
print(p1.x) # p1.__dict__ ---> Chinese.__dict__ ---> 报错
如果要查找一个属性,先从对象名称空间中查找,找不到之后再到类名称空间查找,如果还找不到不会再去全局找,直接报错
练习:
1 1.统计类实例化对象的次数2 classChinese:3 country = 'China'
4 count =05 def __init__(self,name,age):6 self.name =name7 self.age =age8 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 classStu:16 def __init__(self,stuid,name,age):17 self.stuid =stuid18 self.name =name19 self.age =age20 print('Student--->',self.stuid,self.name,self.age)21 s1 = Stu(1,'A',18)22 s2 = Stu(2,'B',18)23
24 3.类对象交互25 classA:26 camp = 'AAA'
27 def __init__(self,nickname,damage=100, HP=200):28 self.nickname =nickname29 self.damage =damage30 self.HP =HP31 defattack(self,enemy):32 enemy.HP -=self.damage33 print('造成%d点伤害' %self.damage)34 classB:35 camp = 'BBB'
36 def __init__(self,nickname,damage=200, HP=100):37 self.nickname =nickname38 self.damage =damage39 self.HP =HP40 defattack(self,enemy):41 enemy.HP -=self.damage42 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 classParentClass1:2 pass
3 classParentClass2:4 pass
5 classSubClass1(ParentClass1):6 pass
7 classSubClass2(ParentClass1,ParentClass2):8 pass
如何查看继承的父类
1 print(SubClass1.__bases__) #(,)
2 print(SubClass2.__bases__) #(, )
类的种类
1 #Python2中分为新式类和经典类
2 #新式类(有括号的,有继承关系的)
3 classFoo(object):4 pass
5 #经典类(没括号的,谁都不继承)
6 classBar:7 pass
8 #Python3中全部都是经典类(即使没有括号也是新式类)
9 classFoo:10 pass
11 print(Foo.__bases__) #(,)
继承的好处:
1.减少冗余代码
2.在子类定义新的属性,覆盖掉父类的属性,称为派生
1 classAnimal:2 def __init__(self,name,age,sex):3 self.name =name4 self.age =age5 self.sex =sex6 defeat(self):7 print('eating...')8 deftalk(self):9 print('%s saying...' %self.name)10 classPeople(Animal):11 def __init__(self,name,age,sex,edu):12 Animal.__init__(self,name,age,sex)13 self.edu =edu14 deftalk(self):15 Animal.talk(self)16 print('%s say hello' %self.name)17 classPig(Animal):18 pass
19 classDog(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 classParent:2 deffoo(self):3 print('Parent.foo')4 self.bar()5 defbar(self):6 print('Parent.bar')7 classSub(Parent):8 defbar(self):9 print('Sub.bar')10 s=Sub()11 s.foo() #Parent.foo
12 #Sub.bar
继承反应的是一种什么是什么的关系
组合也可以解决代码冗余的问题,但是组合反应的是一种什么有什么的关系
1 classPeople:2 def __init__(self,name,age,sex):3 self.name=name4 self.age=age5 self.sex=sex6 classDate:7 def __init__(self,y,m,d):8 self.y =y9 self.m =m10 self.d =d11 deftell(self):12 print('%s-%s-%s' %(self.y,self.m,self.d))13 classTeacher(People):14 def __init__(self,name,age,sex,salary,y,m,d):15 People.__init__(self,name,age,sex)16 self.salary =salary17 self.birth =Date(y,m,d)18
19 classStudent(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 importabc2 class File(metaclass=abc.ABCMeta):3 @abc.abstractmethod4 defread(self):5 pass
6 @abc.abstractmethod7 defwrite(self):8 pass
9 classTxt(File):10 defread(self):11 pass
12 defwrite(self):13 pass
14 p=Txt()
继承搜索顺序:
Python2中,分为
广度优先(新式类)F->D->B->A->E->C->H
深度优先(经典类)F->D->B->E->C->H->A
Python3中,只有广度优先(python3中只有新式类)
1 classA:2 def test(self): print('from A')3 pass
4 classB(A):5 def test(self): print('from B')6 pass
7 classC(A):8 def test(self): print('from C')9 pass
10 classD(B):11 def test(self): print('from D')12 pass
13 classE(C):14 def test(self): print('from E')15 pass
16 classH(A):17 def test(self): print('from H')18 pass
19 classF(D,E,H):20 def test(self): print('from F')21 pass
22 f=F()23 f.test()24 print(F.mro())25 #[, , , ,
26 #, , , ]
子类中重用父类的方法(super)
1 classFoo:2 deftest(self):3 print('from foo.test')4 classBar(Foo):5 deftest(self):6 super().test()7 print('from bar.test')8 b =Bar()9 b.test()10
11 classFoo1:12 deftest(self):13 print('from foo1.test')14 classFoo2:15 deftest(self):16 print('from foo2.test')17 classBar(Foo1,Foo2):18 deftest(self):19 super().test()20 print('from bar.test')21 b =Bar()22 b.test() #from foo1.test
23 #from bar.test
多态与多态性
没有多态就没有多态性
多态:同一种事物的多种形态
多态性:指的是具有不同功能的函数可以使用相同的函数名
1 classAnimal:2 defeat(self):3 print('eating...')4 classPeople(Animal):5 defeat(self):6 print('eating...')7 classPig(Animal):8 defeat(self):9 print('eating...')10 classDog(Animal):11 defeat(self):12 print('eating...')13 p1=People()14 g1=Pig()15 d1=Dog()16 deffunc(obj):17 obj.eat()18 func(p1)19 func(g1)20 func(d1)
封装
为什么要封装:保护隐私,隔离复杂度
Python没有真正的隐藏,只是从语法级别做了些改变
1 classFoo:2 __x = 1 #'_Foo__x': 1
3 def __test(self): #'_Foo__test':
4 print('from test')5 print(Foo.__dict__)6 print(Foo._Foo__x)7 print(Foo._Foo__test)8
9 classPeople:10 __country = 'Chinese'
11 def __init__(self,name,age,sex):12 self.__name=name #只在定义阶段才会发生变形,实例产生后新加入的变量就不会变形了
13 self.__age=age14 self.__sex=age15 deftell_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 classPeople:24 __country = 'Chinese'
25 def __init__(self,name,age):26 self.__name=name27 self.__age=age28 deftell_info(self):29 print('Name:%s,Age:%d' % (self.__name,self.__age))30 defset_info(self,x,y):31 if notisinstance(x,str):32 raise TypeError('must be str!!!')33 if notisinstance(y,int):34 raise TypeError('must be int!!!')35 self.__name =x36 self.__age =y37 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 classFoo:3 @property4 deftest(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 classPeople:13 def __init__(self,name,weight,height):14 self.name =name15 self.weight =weight16 self.height =height17 @property18 defbmi(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 importmath26 classCircle:27 def __init__(self,radius):28 self.raduis =radius29 @property30 defzc(self):31 return 2 * math.pi *self.raduis32 c = Circle(5)33 print(c.zc)34
35 应用4:36 classPerson:37 def __init__(self,name,permission=False):38 self.__name =name39 self.permission =permission40 @property41 defname(self):42 return self.__name
43 @name.setter44 defname(self,value):45 if notisinstance(value,str):46 raise TypeError('must be str')47 self.__name =value48 @name.deleter49 defname(self):50 if notself.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 =True58 del p.name
绑定
类中定义的函数分成两大类:
1.绑定方法(绑定给谁,谁来调用就自动将它本身当作第一个参数传入)
1.绑定到类的方法:用classmethod装饰器装饰的方法。
为类量身定制
类.bound_method(),自动将类当作第一个参数传入(其实对象也可调用,但仍将类当作第一个参数传入)
2.绑定到对象的方法:没有被任何装饰器装饰的方法。
为对象量身定制
对象.bound_method(),自动将对象当作第一个参数传入(属于类的函数,类可以调用,但是必须按照函数的规则来,没有自动传值的说法)
2.非绑定方法:用staticmethod装饰器装饰的方法
不与类或对象绑定,类和对象都可以调用,但是没有自动传值那么一说,就是一个普通工具而已
1 #绑定到类的方法
2 classFoo:3 @classmethod4 deftest(cls):5 print(cls)6 Foo.test() #
7 #跟谁都不绑定的方法
8 classFoo:9 @staticmethod10 deftest(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 importsetting5 importhashlib6 importtime7 classMySQL:8 def __init__(self,host,port):9 self.sql_id =self.sql_id()10 self.host =host11 self.port =port12 print('connecting...')13 @classmethod14 deffrom_conf(cls):15 return cls(setting.HOST,setting.PORT) #相当于MySQL(host,port)
16 @staticmethod17 defsql_id():18 m = hashlib.md5(str(time.clock()).encode('utf-8'))19 returnm.hexdigest()20 defselect(self):21 print(self) #<__main__.mysql object at>
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 classPerson:2 def __init__(self,name,age):3 self.name =name4 self.age =age5 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 importsetting15 classMySQL:16 def __init__(self,host,port):17 self.host =host18 self.port =port19 print('connecting...')20 @classmethod21 deffrom_conf(cls):22 returncls(setting.HOST, setting.PORT)23 def __str__(self):24 return 'from MySQL'
25 classMariadb(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 classPeople:2 country = 'China'
3 def __init__(self,name,age):4 self.name=name5 self.age=age6 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 importsys2 res = sys.modules[__name__] #获取当前模块
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 classFTPClient:12 def __init__(self,host):13 self.host=host14 print('connecting...%s' %self.host)15 definteractive(self):16 whileTrue:17 cmd_line = input('>>>:').strip()18 cmd_list =cmd_line.split()19 ifhasattr(self,cmd_list[0]):20 func =getattr(self,cmd_list[0])21 func(cmd_list)22 defget(self,args):23 print('downloading...%s' % args[1])24 p = FTPClient('127.0.0.1')25 p.interactive()