第五十节,面向对象基本介绍
一,面向对象基础1
c#、Java:只能用面向对象编程
Ruby、python、php:函数编程 + 面向对象
1.面向过程编程2
就是程序最底层的实现过程
2.函数式编程3
就是将最底层的实现过程封装到函数里,调用函数的方法编程
3面向对象编程4
就是将若干函数封装到一个类里,调用类来实现里面的函数方法
注意:面向对象不是所有情况都适用 5
面向对象编程6
需要定义一个类 ,将功能函数写在类里,这样类里面的函数就叫做,实现一个类功能的方法,要使用这个类的方法时,创建这个类的对象赋值给一个变量,通过对象变量找到这个类下面的功能函数来实现(功能)的方法
#!/usr/bin/env python # -*- coding:utf-8 -*- class fgjk: #定义一个类,在类里写函数来实现类的方法 def f1(self,a): #方法1 return a + 1 def f2(self,b): #方法2 pass def f3(self,c): #方法3 pass a1 = fgjk() #创建类对象赋值给一个变量 a2 = a1.f1(3) #调用类下面的一个函数传入参数,来实现一个功能,叫做方法 print(a2) #打印出这个方法的结果 #输出fgjk类下面的f1()方法 # 4
class关键字,定义一个类7
功能:定义一个类
使用方法:class 类名称:
格式:class fgjk:
#!/usr/bin/env python # -*- coding:utf-8 -*- class fgjk: #定义一个类,在类里写函数来实现类的方法 def f1(self,a): #方法1 return a + 1 def f2(self,b): #方法2 pass def f3(self,c): #方法3 pass
定义好类后,将功能函数(方法)写在类里,注意:类里面的函数有一个必写值self8
#!/usr/bin/env python # -*- coding:utf-8 -*- class fgjk: #定义一个类,在类里写函数来实现类的方法 def f1(self,a): #方法1 return a + 1 def f2(self,b): #方法2 pass def f3(self,c): #方法3 pass
self是一个形式参数,这个形式参数是用来,在执行类方法时接收类对象返回值的,9
注意:类对象的返回值是由python自动当做实参,传入类方法函数的self,不需要我们写,由python自动完成
#!/usr/bin/env python # -*- coding:utf-8 -*- """定义类和类的方法""" class fgjk: #定义一个类,在类里写函数来实现类的方法 def f1(self,a): #方法1 print("打印self接收的类对象值",self) return a #返回值 """创建类的对象和是使用类的方法""" a1 = fgjk() #创建类对象赋值给一个变量 print("打印类对象值",a1) #注意:类对象的值是由python自动当做实参,传入类方法函数的,不需要我们写,由python自动完成,相当于下面写的a1.f1(a1,3) a2 = a1.f1(3) #调用类下面的一个函数传入参数,来实现一个功能,叫做方法 print("打印返回值",a2) #打印出这个方法的结果 # 输出 # 打印类对象值 <__main__.fgjk object at 0x0000006685D37160> # 打印self接收的类对象值 <__main__.fgjk object at 0x0000006685D37160> # 打印返回值 3
定义好类和写好函数方法后,创建这个类的对象赋值给一个变量,通过变量找到这个类下面的功能函数来实现(功能)的方法 , 创建类对象也叫做(创建Foo类的实列)10
#!/usr/bin/env python # -*- coding:utf-8 -*- """定义类和类的方法""" class fgjk: #定义一个类,在类里写函数来实现类的方法 def f1(self,a): #方法1 return a + 1 def f2(self,b): #方法2 pass def f3(self,c): #方法3 pass """创建类对象和使用类的方法""" a1 = fgjk() #创建类对象赋值给一个变量 a2 = a1.f1(3) #调用类下面的一个函数传入参数,来实现一个功能,叫做方法 print(a2) #打印出这个方法的结果 #输出fgjk类下面的f1()方法 # 4
面向对象原理图11
封装12
封装就是给对象封装普通字段
面向对象封装之,在类的对象里封装变量和变量值,非主流方法【不推荐】13
就是在类的对象里封装变量和变量值,封装后使用类函数方法时不需要传值,在类函数方法里通过self来获取类对象里的值即可
给类对象添加变量:创建对象变量.要添加的变量名称 = 变量值 如a1.zhi = xx
类方法函数获取对象变量:在方法函数里通过接收对象的self来获取,self.添加的类对象变量名称,这样就可以获取到类对象的值
#!/usr/bin/env python # -*- coding:utf-8 -*- """面向对象封装之,给类对象封装变量和变量值""" class fgjk: #定义一个类,在类里写函数来实现类的方法 def f1(self): #方法1 b = self.zhi + 5 #获取类对象里的zhi变量的值加5 c = b + self.zhi2 #用b结果加类对象里的zhi2变量值 return c """创建类的对象和使用类的方法""" a1 = fgjk() #创建类对象赋值给一个变量 a1.zhi = 5 #给类对象封装一个变量和值 a1.zhi2 = 10 #给类对象封装一个变量和值 a2 = a1.f1() #执行类方法 print(a2) #打印出方法结果 # 输出 # 20
面向对象封装之,在类的对象里封装变量和变量值原理图14
__init__()构造方法,面向对象封装之,给类对象封装变量和变量值,主流方法 15
__init__(self)类方法函数,如果类里有定义__init__(self)类方法函数,创建对象后会自动执行__init__(self)方法函数的
使用方法:__init__(self,后面可以定义变量类接收对象传值然后封装到对象)
就是不在从类对象那里封装变量和值,从类的__init__(self)方法,向对象封装变量和值,因为只要创建对象后,python就会默认执行类的__init__(self)方法,然而对象的返回值是自动通过对象传值给类方法的self形式参数的,所以可以根据这个形式参数接收到的对象,向对象里封装变量和变量值
# -*- coding:utf-8 -*- """面向对象封装之,给类对象封装变量和变量值,主流方法""" class fgjk: #定义一个类,在类里写函数来实现类的方法 def __init__(self): print(self) self.adc = "你好" #通过self接收到的对象,向对象里封装变量和变量值 def f1(self): print(self.adc) """创建类的对象和使用类的方法""" a1 = fgjk() #创建类对象赋值给一个变量,并把类对象返回值传给类里面的方法函数的self形式参数 a1.f1() #执行类的方法函数 # 输出 # <__main__.fgjk object at 0x000000A5E652C518> # 你好
通过类方法的self给对象封装变量原理图16
__init__()构造方法,面向对象封装之,给类对象封装变量和变量值,主流方法2【推荐】17
# -*- coding:utf-8 -*- """面向对象封装之,给类对象封装变量和变量值,主流方法""" a = "变量值" class fgjk: #定义一个类,在类里写函数来实现类的方法 def __init__(self,b): print(self) self.adc = b #通过self接收到的对象,向对象里封装变量和变量值 def f1(self): print(self.adc) """创建类的对象和使用类的方法""" a1 = fgjk(a) #创建类对象赋值给一个变量,并把类对象返回值传给类里面的方法函数的self形式参数 a1.f1() #执行类的方法函数 # 输出 # <__main__.fgjk object at 0x000000A5E652C518> # 变量值
主流方法2【推荐】原理图18
注意:我们一般都是用构造方法2
__del__(self)解释器销毁对象时自动调用,我们只需要知道一些就行,这是python自动完成的,叫做析构方法19
封装总结20
使用场景,当同一类型的方法具有相同参数时,直接封装到对象即可
使用场景2:把类当做模板,创建多个对象(每个对象内封装的数据可以不一样)
创建类对象,和__init__()构造封装对象变量,叫做初始化
给对象封装的变量,叫做给对象创建普通字段
继承21
继承就是在定义类b时,可以在b类名称后面加上()括号里写上另外一个a类的名称,这样b类就会继承a类里的方法22
1.子类(派生类)、继承父类(基类)中的所有功能23
2.Python类可以同时继承多个父类(基类)(c#/Java不可以)24
3.继承的优先级,继承里有相同方法的优先级25
子类(派生类)、和父类(基类)同时存在一个方法是时,优先找子类(派生类),
如果是一个类继承了多个类,而且继承的多个类中有同样的方法是,优先从子类(派生类)()括号里的父类(基类)左边优先
如果是嵌套式继承,也就是一个类继承了多个基类,并且多个基类又继承了多个基类,这时是自己本身类优先,然后是上一级基类左边第一个优先,再者是左边第一个基类的上级基类优先,再者是左边第二基类优先以此类推
也就是说,首先是自身优先,然后是基类左边优先,然后是基类左边深度优先,以此类推的
如果嵌套式继承,最后有两个类都继承了同一个基类,这个被两个类继承的类不在深度查找,是最后查找这个类的
#!/usr/bin/env python # -*- coding:utf-8 -*- class lei: #定义lei类 def __init__(self,wb = ""): #接收定义lei对象里的传值 self.wb = wb #将定义lei对象里的传值封装到lei对象里 def f1(self): print("f1",self.wb) #打印f1和,lei对象里封装的wb变量 def f2(self): print("f2") def f3(self): print("f3") class lei2(lei): #定义lei2类并继承lei类的方法 def __init__(self,wb2 = ""): #接收定义lei2对象里的传值 self.wb2 = wb2 ##将定义lei2对象里的传值封装到lei2对象里 def j1(self): print("j1") def j2(self): print("j2",self.wb2) #打印j2和,lei2对象里封装的wb2变量 def j3(self): print("j3") a = lei("你好") #创建lei类对象,并传值到lei类__init__方法 a.f1() #执行类里的f1()方法 b = lei2("我好") #创建lei2类对象,并传值到lei2类__init__方法 b.f3() #执行lei2类继承的lei里的f3()方法 b.j2() #执行lei2类里的j2()方法 # 输出 # f1 你好 # f3 # j2 我好
继承原理图26
继承优先级说明图27
自身优先图28
基类左边第一个优先图29
左边深度优先图30
最后有两个类都继承了同一个基类,这个被两个类继承的类不在深度查找,是最后查找这个类的31
继承重点,self.XXX()继承容易错点,如果一个类继承了多个基类,并且基类里有self.XXX()方法,self实际就是创建的对象,self.xxx()就是又回到了创建对象的类里去找xxx()方法,如果创建的自身类里没有xxx()方法,就又从继承基类的左边第一个开始查找,在之深度等,以此按照前面说的优先级执行32
#!/usr/bin/env python # -*- coding:utf-8 -*- class a: #定义a类 def __init__(self,zhi = ""): self.zhi = zhi def f1(self): print("a") class b: #定义b类 def __init__(self,zhi = ""): self.zhi = zhi def b1(self): self.f1() class c: #定义c类 def __init__(self,zhi = ""): self.zhi = zhi def f1(self): print("c") class d(b,c,a): #定义d类 def __init__(self,zhi = ""): self.zhi = zhi fsa = d("传值") #创建d类对象 fsa.b1() #执行d类对象的类里面的b1()方法,类里面没有b1方法,就到继承的基类左边第一个b类里去找b1方法,找到b1方法执行,然而b1里是执行的对象里面的f1方法,这样就又回到了d类里去找f1方法 # 输出 # c
self.XXX()继承原理图33
super()内置函数【推荐】,在一个类里获取上一级父类基类的,__init__方法里的对象封装值,注意只能获取上一级基类的__init__方法里的对象封装值34
使用方法:super(子类派生类名称,self).__init__()
格式:super(b,self).__init__()
#!/usr/bin/env python # -*- coding:utf-8 -*- class c: #定义a类 def __init__(self): self.zf = "狗shi" def f1(self): print("c") class a: #定义a类 def __init__(self): self.zhi = "动物" def f1(self): print("a") class b(a): #定义b类 def __init__(self): self.zh = "猫" super(b,self).__init__() #获取上一级父类基类的,__init__方法里的对象封装值 print(self.zhi) #打印出获取到的,上一级父类基类的,__init__方法里的对象封装值 def b1(self): print("b") c = b() c.f1() # 输出 # 动物 # a
被获取类名称.__init__(self)在一个类里获取另外一个类的__init__方法里的对象封装值,注意,可以获取有继承关系的,也可以获取无继承关系的类35
使用方法:被获取类名称.__init__(self)
格式:c.__init__(self)
#!/usr/bin/env python # -*- coding:utf-8 -*- class c: #定义a类 def __init__(self): self.zf = "狗shi" def f1(self): print("c") class a: #定义a类 def __init__(self): self.zhi = "动物" def f1(self): print("a") class b(a): #定义b类 def __init__(self): self.zh = "猫" c.__init__(self) #在一个类里获取另外一个类的__init__方法里的对象封装值,注意,可以获取有继承关系的,也可以获取无继承关系的类 print(self.zf) #打印获取到的,另外一个类的__init__方法里的对象封装值 def b1(self): print("b") c = b() c.f1() # 输出 # 狗shi # a
多态36
多态就是多种形态
python自身支持多态
多态的简单理解就是,定义一个函数,创建类对象,把类对象当做实际参数传给函数的形式参数,在函数里通过形式参数接收到的类对象来执行对象类里的方法,也就是向函数传不同的对象,就执行不同对象类的方法
#!/usr/bin/env python # -*- coding:utf-8 -*- """多态,多种形态""" class ab: #定义ab类 def __init__(self,zhi = ""): #定义__init__方法接收类对象传的值 self.zhi = zhi #将类对象传值封装到对象里吧,给对象封装一个字段 def f1(self): #定义类方法 print(self.zhi) #打印ab类对象里封装的zhi字段 class cd: #定义cd类 def __init__(self,zhi = ""): #定义__init__方法接收类对象传的值 self.zhi = zhi #将类对象传值封装到对象里吧,给对象封装一个字段 def f1(self): #定义类方法 print(self.zhi) #打印cd类对象里封装的zhi字段 def ef(fang): #定义一个函数,设置一个形式参数接收类对象 fang.f1() #接收对象,并执行对象的类里面的f1()方法 ef(ab("你好")) #执行函数,创建ab类对象当做实参传值给ef函数 ef(cd("我好")) #执行函数,创建cd类对象当做实参传值给ef函数 # 输出 # 你好 # 我好
多态原理图37
面向对象的进阶38
成员39
类下面的方法为类的成员
对象下面的封装字段为对象成员
利用反射来操作类里的成员40
hasattr()内置反射函数,到指定类查找指定方法是否存在,和到指定的对象下查找,对象下的封装变量是否存在,或者到指定对象查找对象类里的指定方法,存在返回True,否则返回False
注意:对象有对象指针指向了类,所有也能用hasattr()函数通过对象来查找类里的方法,所以推荐通过对象来查找,既可以查找类又可以查找对象下的字段
使用方法:hasattr(要查找的类名称或对象名称,字符串形式要查找的方法名称或对象封装名称)41
格式:hasattr(c,"f1")
到指定类查找指定方法是否存在
#!/usr/bin/env python # -*- coding:utf-8 -*- class c: #定义a类 def __init__(self): self.zf = "狗shi" def f1(self): print("c") class a: #定义a类 def __init__(self): self.zhi = "动物" def f1(self): print("a") fa = hasattr(c,"f1") #hasattr()内置函数,到指定类查找指定方法是否存在,和到指定的对象下查找,对象下的封装变量是否存在,存在返回True,否则返回False print(fa) # 输出 # True
到指定的对象下查找对象下的封装变量是否存在
#!/usr/bin/env python # -*- coding:utf-8 -*- class c: #定义a类 def __init__(self): self.zf = "狗shi" def f1(self): print("c") class a: #定义a类 def __init__(self): self.zhi = "动物" def f1(self): print("a") fa = hasattr(a(),"zhi") #hasattr()内置函数,到指定类查找指定方法是否存在,和到指定的对象下查找,对象下的封装变量是否存在,存在返回True,否则返回False print(fa) # 输出 # True
到指定对象查找对象类里的指定方法
#!/usr/bin/env python # -*- coding:utf-8 -*- class c: #定义a类 def __init__(self): self.zf = "狗shi" def f1(self): print("c") class a: #定义a类 def __init__(self): self.zhi = "动物" def f1(self): print("a") fa = hasattr(a(),"f1") #hasattr()内置函数,到指定类查找指定方法是否存在,和到指定的对象下查找,对象下的封装变量是否存在,存在返回True,否则返回False print(fa) # 输出 # True
getattr()内置反射函数,到指定的对象下找到,对象下的封装变量赋值给一个变量,或者到指定对象找到对象类里的指定方法赋值给一个变量42
注意:对象有对象指针指向了类,所有也能用hasattr()函数通过对象来查找类里的方法,所以推荐通过对象来查找,既可以查找类又可以查找对象下的字段
使用方法:getattr(要查找的对象,字符串形式要查找的方法名称或对象封装名称)
格式:fa = getattr(c(),"f1")
到指定对象找到对象类里的指定方法赋值给一个变量,并执行方法
#!/usr/bin/env python # -*- coding:utf-8 -*- class c: #定义a类 def __init__(self): self.zf = "狗shi" def f1(self): print("c") class a: #定义a类 def __init__(self): self.zhi = "动物" def f1(self): print("a") fa = getattr(c(),"f1") #getattr()内置反射函数,到指定的对象下找到,对象下的封装变量赋值给一个变量,或者到指定对象找到对象类里的指定方法赋值给一个变量 fa() #执行找到的类方法 # 输出 # c
到指定的对象下找到,对象下的封装变量赋值给一个变量
#!/usr/bin/env python # -*- coding:utf-8 -*- class c: #定义a类 def __init__(self): self.zf = "狗shi" def f1(self): print("c") class a: #定义a类 def __init__(self): self.zhi = "动物" def f1(self): print("a") fa = getattr(c(),"zf") #getattr()内置反射函数,到指定的对象下找到,对象下的封装变量赋值给一个变量,或者到指定对象找到对象类里的指定方法赋值给一个变量 print(fa) # 输出 # 狗shi
用反射操作面向对象成员43
根据字符串方式的面向对象模块,和字符串方式的类方法,用反射来执行面向对象44
面向对象模块
#!/usr/bin/env python # -*- coding:utf8 -*- class c: #定义a类 def __init__(self): self.zf = "狗shi" def f1(self): print("c") class a: #定义a类 def __init__(self): self.zhi = "动物" def f1(self): print("a222")
反射操作面向对象模块里的成员
#!/usr/bin/env python # -*- coding:utf-8 -*- """根据字符串方式的面向对象模块,和字符串方式的类方法,用反射来执行面向对象""" a = "lib.ska.mk" #面向对象模块路径 b = "f1" #类方法名称 c = __import__(a,fromlist=True) #反射方式导入面向对象模块 d = hasattr(c.a(),b) #查找模块里的a类里是否有f1方法,返回布尔值 if d: #判断模块里的a类里是否有f1方法 f1 = getattr(c.a(),b) #如果有就找到f1方法赋值给一个变量 f1() #执行找到a类里的f1方法 else: print("a类里没有f1方法") # 输出 # a222
静态字段45
静态字段,也就是在类里面定义变量,提供类里的所有方法调用,这样能很好的实现多个类有一个相同数据的情况46
注意:静态字段是通过,类名称.静态字段名称来访问的,对象封装的普通字段,是通过self.普通字段名称来访问的
#!/usr/bin/env python # -*- coding:utf8 -*- class a: #定义a类 shux = "动物" def __init__(self,zhu): #初始化__init__接收对象传值 self.zhu = zhu #将对象传值封装到对象里 def f1(self): #定义方法 print(a.shux, self.zhu) #打印类的静态字段和对象封装的普通字段 def f2(self): #定义方法 print(a.shux, self.zhu) #打印类的静态字段和对象封装的普通字段 def f3(self): #定义方法 print(a.shux, self.zhu) #打印类的静态字段和对象封装的普通字段 s = a("猫") #创建对象并传值 s.f1() #执行对象类里的f1()方法 f = a("狗") #创建对象并传值 f.f2() #执行对象类里的f2()方法 b = a("猪") #创建对象并传值 b.f3() #执行对象类里的f3()方法 # 输出 # 动物 猫 # 动物 狗 # 动物 猪
静态字段原理图47
静态方法48
就是在类里定义普通函数,函数上面用上装饰符@staticmethod,静态方法不需要传self参数,静态方法通过类来访问,不需要创建对象就可以访问
@staticmethod在类里声明一个静态方法49
#!/usr/bin/env python # -*- coding:utf8 -*- class a: #定义a类 def __init__(self,zhu): #初始化__init__接收对象传值 self.zhu = zhu #将对象传值封装到对象里 @staticmethod #定义静态方法 def f1(): #静态方法 print("静态方法") def f3(self): #定义方法 print(a.shux, self.zhu) a.f1() # 输出 # 静态方法
静态方法原理图50
类方法51
就是在类里定义一个函数,函数上面用上装饰符@classmethod,函数里有一个必写形式参数cls用来接收类名称
@classmethod在类里声明一个类方法52
#!/usr/bin/env python # -*- coding:utf8 -*- class a: #定义a类 def __init__(self,zhu): #初始化__init__接收对象传值 self.zhu = zhu #将对象传值封装到对象里 @classmethod #定义类方法 def f1(cls): #自动将类名称传值给cls形参 print(cls) #打印cls接收到的类名称 def f3(self): #定义方法 print(a.shux, self.zhu) a.f1() # 输出 # <class '__main__.a'>
类方法原理图53
特性方法54
@property特性方法55
就是在类里定义一个普通方法函数,函数上面用上装饰符@property,函数里有一个必写形式参数self用来接收对象地址,也可以给方法封装普通字段
特性方法与普通方法的区别:就是执行特性方法函数时不用写()括号,特性方法就是将普通方法伪造成通过对象获取的字段,特殊方法获取到返回值后是可以重新赋值的
#!/usr/bin/env python # -*- coding:utf8 -*- class a: #定义a类 def __init__(self,zhu): #初始化__init__接收对象传值 self.zhu = zhu #将对象传值封装到对象里 @property #声明特性方法 def f1(self): #定义特性方法 te = "{}方法".format(self.zhu) print(te) def f3(self): #定义方法 print(a.shux, self.zhu) s = a("特性") s.f1 #执行对象类里的f1特性方法 # 输出 # 特性方法
s.f1 = "重新赋值" #特殊方法获取到返回值后是可以重新赋值的
特性方法原理图56
设置特性方法:就是给特性方法设置值57
@方法名称.setter给特性方法设置值58
就是在类里的特性方法下面,写一个给特性方法名称一样的方法函数,函数上面用上装饰符@方法名称.setter,在方法里设置一个形式参数来接收,执行设置特性方法传值,执行设置特性方法时,将特性方法 = 要设置的值即可
#!/usr/bin/env python # -*- coding:utf8 -*- class a: #定义a类 def __init__(self,zhu): #初始化__init__接收对象传值 self.zhu = zhu #将对象传值封装到对象里 @property #声明特性方法 def f1(self): #定义特性方法 te = "{}方法".format(self.zhu) print(te) @f1.setter #设置特性方法 def f1(self,v): #设置特性方法 print(v) #打印设置的特性方法值 self.zhu = v #将设置的特性方法值替换对象封装的普通字段 s = a("特性") s.f1 #执行对象类里的f1特性方法 s.f1 = "设置特性方法值" s.f1 # 输出 # 特性方法 # 设置特性方法值 # 设置特性方法值方法
设置特性方法原理图59
成员修饰符60
修饰成员的使用权限对成员:静态字段、普通字段、普通方法、静态方法、类方法、特性方法,进行成员权限修饰61
公有:就是没加__修饰符的成员,既可以在类里面访问,也可以通过类或者对象外部访问
私有:就是加上__修饰符的成员,通过对象或者类无法外部访问,只能在类内部访问,外部要想访问必须在类的内部定义一个公有方法,在公有方法里执行要想访问的私有成员,通过公有方法来间接的访问私有成员,注意:一个类的私有方法只有类自己内部可以使用, 而且无法被继承。
__类成员修饰符,用于修饰类的成员私有权限,用了__修饰符的私有成员只有类自身内部可以访问。62
静态字段修饰符63
#!/usr/bin/env python # -*- coding:utf8 -*- class a: #定义a类 __jt = "静态字段" def __init__(self,zhu = ""): #初始化__init__接收对象传值 self.zhu = zhu #将对象传值封装到对象里 def f1(self): print(a.__jt) def f2(self): pass #print(a.__jt) #静态字段加修饰符后外部不可以访问 f = a() #定义对像 f.f1() #可以通过类里的f1方法间接访问 # 输出 # 静态字段
普通字段修饰符64
#!/usr/bin/env python # -*- coding:utf8 -*- class a: #定义a类 def __init__(self,zhu = ""): #初始化__init__接收对象传值 self.__zhu = zhu #将对象传值封装到对象里,封装普通字段 def f1(self): print(self.__zhu) def f2(self): pass f = a("普通字段") #定义对象 #print(f.zhu) #普通字段加修饰符后外部不可以访问 f.f1() #通过类里的f1方法可以间接访问对象里封装的普通字段 # 输出 # 普通字段
普通方法修饰符65
#!/usr/bin/env python # -*- coding:utf8 -*- class a: #定义a类 def __init__(self,zhu = ""): #初始化__init__接收对象传值 self.__zhu = zhu #将对象传值封装到对象里,封装普通字段 def __f1(self): print("普通方法") def f2(self): self.__f1() f = a() #定义对象 #f.__f1() #普通方法加修饰符后外部不可以访问 f.f2() #通过类里的f2方法可以间接访问加修饰符的f1普通方法 # 输出 # 普通方法
静态方法修饰符66
#!/usr/bin/env python # -*- coding:utf8 -*- class a: #定义a类 def __init__(self,zhu = ""): #初始化__init__接收对象传值 self.__zhu = zhu #将对象传值封装到对象里,封装普通字段 @staticmethod #定义静态方法 def __f1(): print("静态方法") def f2(self): a.__f1() #a.__f1() #静态方法加修饰符后外部不可以访问 f = a() #定义对象 f.f2() #通过类里的f2方法可以间接访问加修饰符的f1静态方法 # 输出 # 静态方法
类方法修饰符67
#!/usr/bin/env python # -*- coding:utf8 -*- class a: #定义a类 def __init__(self,zhu = ""): #初始化__init__接收对象传值 self.__zhu = zhu #将对象传值封装到对象里,封装普通字段 @classmethod #定义类方法 def __f1(cls): print("类方法",cls) def f2(self): a.__f1() #a.__f1() #类方法加修饰符后外部不可以访问 f = a() #定义对象 f.f2() #通过类里的f2方法可以间接访问加修饰符的f1类方法 # 输出 # 类方法 <class '__main__.a'>
特性方法修饰符68
#!/usr/bin/env python # -*- coding:utf8 -*- class a: #定义a类 def __init__(self,zhu = ""): #初始化__init__接收对象传值 self.__zhu = zhu #将对象传值封装到对象里,封装普通字段 @property #定义特性方法 def __f1(self): print("特性方法") def f2(self): self.__f1 f = a() #定义对象 #f.__f1 #特性方法加修饰符后外部不可以访问 f.f2() #通过类里的f2方法可以间接访问加修饰符的f1特性方法 # 输出 # 特性方法
成员修饰符之特殊手段,外部访问类的私有成员【不到万不得已不使用】69
方法:类名称或者对象名称._类名称__私有字段名称
格式:a._a__jt
#!/usr/bin/env python # -*- coding:utf8 -*- class a: #定义a类 __jt = "静态字段" def __init__(self,zhu = ""): #初始化__init__接收对象传值 self.zhu = zhu #将对象传值封装到对象里 def f1(self): print(a.__jt) def f2(self): pass print(a._a__jt) #特殊手段外部访问类的私有成员 # 输出 # 静态字段
类成员之特殊方法70
__call__方法是类里的一个特殊方法,当类里定义了这个方法时,创建对象后在对象后面加上()括号,也可以在对象变量后面加括号是一样的,会自动执行类里的__call__方法71
#!/usr/bin/env python # -*- coding:utf8 -*- class a: #定义a类 def __init__(self,zhu = ""): #初始化__init__接收对象传值 self.zhu = zhu #将对象传值封装到对象里 def __call__(self, args): #定义__call__方法 print(args,self.zhu) def f2(self): pass f = a("方法")("__call__") # 输出 # __call__ 方法
#!/usr/bin/env python # -*- coding:utf8 -*- class a: #定义a类 def __init__(self,zhu = ""): #初始化__init__接收对象传值 self.zhu = zhu #将对象传值封装到对象里 def __call__(self, args): #定义__call__方法 print(args,self.zhu) def f2(self): pass f = a("方法") f("__call__") # 输出 # __call__ 方法
__getitem__方法是类里的一个特殊方法,当类里定义了这个方法时,创建对象后在对象后面加上[]中括号,会自动执行类里的__getitem__方法,并将[]中括号里的值传给__getitem__方法的形式参数。72
注意:对象后面加上[1:2:3],也是执行类的__getitem__方法
#!/usr/bin/env python # -*- coding:utf8 -*- class a: #定义a类 def __init__(self,zhu = ""): #初始化__init__接收对象传值 self.zhu = zhu #将对象传值封装到对象里 def __getitem__(self, item): #创建__getitem__方法 s = self.zhu + item #将创建对象封装的普通字段,加上执行__getitem__方法时的传值,相加后并返回值 return s #返回值 def f2(self): pass f = a(10) #创建对象传值 b = f[10] #执行__getitem__方法并传值给__getitem__方法 print(b) #打印__getitem__方法返回值 # 输出 # 20
对象后面加上[1:2:3],也是执行类的__getitem__方法 73
#!/usr/bin/env python # -*- coding:utf8 -*- class a: #定义a类 def __init__(self,zhu = ""): #初始化__init__接收对象传值 self.zhu = zhu #将对象传值封装到对象里 def __getitem__(self, item): #创建__getitem__方法,将[]中括号里的数据重新封装成一个slice对象传给item print(item) #打印接收到的slice对象元素 def f2(self): pass f = a() #创建对象传值 b = f[10:12:3] #执行__getitem__方法并传值给__getitem__方法 print(b) #打印__getitem__方法返回值 # 输出 # 20
__setitem__方法是类里的一个特殊方法,当类里定义了这个方法时,创建对象后在对象后面加上[xxx]=xxx中括号等于,会自动执行类里的__setitem__方法,并将[xxx]=xxx中括号和等于里的值传给__setitem__方法的形式参数74
#!/usr/bin/env python # -*- coding:utf8 -*- class a: #定义a类 def __init__(self,zhu = ""): #初始化__init__接收对象传值 self.zhu = zhu #将对象传值封装到对象里 def __setitem__(self, key, value): #定义__setitem__方法 print(key,value) #打印[xxx] = xxx 传值 def f2(self): pass f = a() #创建对象传值 f["键"] = "值" #执行__setitem__方法并传值给__setitem____方法 # 输出 # 键 值
__delitem__方法是类里的一个特殊方法,当类里定义了这个方法时,创建对象后在对象后面加上del对象名称[xxx]中括号,会自动执行类里的__delitem__方法,并将[xxx]中括号里的值传给__delitem__方法的形式参数75
#!/usr/bin/env python # -*- coding:utf8 -*- class a: #定义a类 def __init__(self,zhu = ""): #初始化__init__接收对象传值 self.zhu = zhu #将对象传值封装到对象里 def __delitem__(self, key): #定义__delitem__方法 print("删除",key) #操作[xxx]里传来的值 def f2(self): pass f = a() #创建对象传值 del f["键"] #执行__delitem__方法,并传值给__delitem__方法 # 输出 # 删除 键
__iter__方法是类里的一个特殊方法,当类里定义了这个方法时,创建对象后只要for循环对象,会自动执行类里的__iter__方法,如__iter__方法里是一个生成器,for循环就会循环出生成器里的结果76
#!/usr/bin/env python # -*- coding:utf8 -*- class a: #定义a类 def __iter__(self): #定义__iter__方法 yield 1 #生成器 yield 2 yield 3 yield 4 def f1(self): pass s = a() #创建对象 for i in s: #循环对象 print(i) #循环打印出生成器里的数据 # 输出 # 1 # 2 # 3 # 4
__str__方法是类里的一个特殊方法,当类里定义了这个方法时,创建对象后只要print打印对象或者str(对象)时就,会自动执行类里的__str__方法77
#!/usr/bin/env python # -*- coding:utf8 -*- class a: #定义类 def __init__(self,vas): #定义__init__方法,接收对象传值 self.fds = vas #将对象传值封装成对象普通字段 def __str__(self): #定义__str__方法 return self.fds #返回对象里的普通字段 def f1(self): pass f = a("str方法") print(f) #打印对象时自动执行__str__方法 b = str(f) #str(对象)时也会执行__str__方法 print(b) # 输出 # str方法 # str方法
__dict__查看对象或者类里的成员78
#!/usr/bin/env python # -*- coding:utf8 -*- class a: #定义a类 def __init__(self,zhu = ""): #初始化__init__接收对象传值 self.zhu = zhu #将对象传值封装到对象里 def __getitem__(self, item): #创建__getitem__方法,将[]中括号里的数据重新封装成一个slice对象传给item print(item) #打印接收到的slice对象元素 def f2(self): pass f = a("zhi") #创建对象传值 print(f.__dict__) #查看对象里的成员 print(a.__dict__) #查看类里的成员 # 输出 # {'zhu': 'zhi'} # {'__init__': <function a.__init__ at 0x00000036345AE510>, 'f2': <function a.f2 at 0x00000036345AE620>, '__getitem__': <function a.__getitem__ at 0x00000036345AE598>, '__weakref__': <attribute '__weakref__' of 'a' objects>, '__dict__': <attribute '__dict__' of 'a' objects>, '__module__': '__main__', '__doc__': None}
可以忽略,源码创建类原理79
__new__ python创建类源码方法80
__metaclass__ python创建类源码方法81
阅读以下代码:
class Foo(object): def __init__(self): pass obj = Foo() # obj是通过Foo类实例化的对象
上述代码中,obj 是通过 Foo 类实例化的对象,其实,不仅 obj 是一个对象,Foo类本身也是一个对象,因为在Python中一切事物都是对象。
如果按照一切事物都是对象的理论:obj对象是通过执行Foo类的构造方法创建,那么Foo类对象应该也是通过执行某个类的 构造方法 创建。
print type(obj) # 输出:<class '__main__.Foo'> 表示,obj 对象由Foo类创建 print type(Foo) # 输出:<type 'type'> 表示,Foo类对象由 type 类创建
所以,obj对象是Foo类的一个实例,Foo类对象是 type 类的一个实例,即:Foo类对象 是通过type类的构造方法创建。
那么,创建类就可以有两种方式:
普通方式
class Foo(object): def func(self): print 'hello wupeiqi'
特殊方式(type类的构造函数)
def func(self): print 'hello wupeiqi' Foo = type('Foo',(object,), {'func': func}) #type第一个参数:类名 #type第二个参数:当前类的基类 #type第三个参数:类的成员
==》 类 是由 type 类实例化产生
那么问题来了,类默认是由 type 类实例化产生,type类中如何实现的创建类?类又是如何创建对象?
答:类中有一个属性 __metaclass__,其用来表示该类由 谁 来实例化创建,所以,我们可以为 __metaclass__ 设置一个type类的派生类,从而查看 类 创建的过程。
class MyType(type): def __init__(self, what, bases=None, dict=None): super(MyType, self).__init__(what, bases, dict) def __call__(self, *args, **kwargs): obj = self.__new__(self, *args, **kwargs) self.__init__(obj) class Foo(object): __metaclass__ = MyType def __init__(self, name): self.name = name def __new__(cls, *args, **kwargs): return object.__new__(cls, *args, **kwargs) # 第一阶段:解释器从上到下执行代码创建Foo类 # 第二阶段:通过Foo类创建obj对象 obj = Foo()
重点总结82
面向对象三大特性:83
封装、继承、多态
成员:84
字段:普通字段(每个对象都有一份相同数据时)、静态字段(每个对象都不同的数据时)
方法:静态方法(无需使用对象封装的内容时)、类方法(需要获取对象名称时)、普通方法(使用对象中的数据时)
特性方法:特性方法(将方法伪造成字段时)
特殊方法:对象后写上执行属性,就会自动执行特殊方法
类成员访问方法:85
通过类访问的有:静态字段,静态方法,类方法
通过对象访问的有:普通字段,普通方法,特性方法
一般有self的方法用对象访问,无self的方法用类来访问
成员修饰符:86
修饰成员的使用权限对成员:静态字段、普通字段、普通方法、静态方法、类方法、特性方法,进行成员权限修饰
公有:就是没加__修饰符的成员,既可以在类里面访问,也可以通过类或者对象外部访问
私有:就是加上__修饰符的成员,通过对象或者类无法外部访问,只能在类内部访问,外部要想访问必须在类的内部定义一个公有方法,在公有方法里执行要想访问的私有成员,通过公有方法来间接的访问私有成员
,注意:一个类的私有方法只有类自己内部可以使用,而且无法被继承。
特殊方法对应的执行属性:87
类名称(xxx):创建对象并执行类的__init__方法
对象变量(xxx):执行类的__call__方法
对象变量[xxx]:执行类的__getitem__方法
对象变量[x:x:x]:执行类的__getitem__方法
对象变量[xxx]=xxx:执行类的__setitem__方法
del对象变量[xxx]:执行类的__delitem__方法
for循环对象变量:执行类的__iter__方法