python面向对象生动讲解_Python面向对象语法精讲
本专题的内容结构:
第一部分主要是:面向对象基础
第二部分主要是:面向对象进阶
第一部分的结构:
unit1:面向对象编程模式:
(1),面向对象编程思想
(2),面向对象的三个特征
(3),Python面向对象术语
unit2:Python类的构建:
(1),类的基本构建
(2),类的属性和方法
(3),类的构造函数和析构函数
unit3:实例1:银行ATM等待时间分析
(1),对象的设计和构建
(2),生活现象的程序分析
unit4:Python类的封装
(1),私有属性和公开属性
(2),私有方法和公开方法
(3),保留属性和保留方法
unit5:Python类的继承:
(1),子类,父类与超类
(2),类的方法重载和属性重载
(3),类的多继承
第二部分的结构:
unit1:Python类的运算:
(1),运算符的理解
(2),各类运算符的重载
unit2:Python类的多态:
(1),多态的理解
(2),参数类型的多态
(3),参数形式的多态
unit3:实例2:图像的四则运算
(1),PIL库和Numpy 库实践
(2),图像的加减乘除操作
unit4:Python对象的引用
(1),引用的理解
(2),浅拷贝和深拷贝
unit5:Python类的高级话题:
(1),类的特殊装饰器
(2),命名空间的理解
(3),类的名称修饰
第一部分的内容:
unit1:面向对象编程模式:
(1),万物皆对象:
自然意义上的对象:独立的存在 或 作为目标的事物
>独立性:对象都存在清晰的边界,重点在于划分边界
>功能性:对象都能表现出一些功能,操作或行为
>交互性:对象之间存在交互,如:运算和继承
Python语言的“万物皆对象”:
>Python语言中所有数据类型都是对象,函数是对象,模块是对象
>Python所有类都是继承于最基础类object
>Python语言中数据类型的操作功能都是类方法的体现
(2),面向对象编程思想:
OOP :Object-Oriented Programming
>OOP :面向对象编程,一种编程思想,重点在于高抽象的 复用代码
>OOP 把对象当做程序的基本单元,对象包含数据和操作数据的函数
>OOP 本质是把问题解决抽象为以对象为中心的计算机程序
注:
>OOP在较大规模或复杂项目中十分有用,OOP可以提高协作产量
>OOP最主要的价值在于代码复用
>OOP只是一种编程方式,并非解决问题的高级方法
面向过程 vs 面向对象
>面向过程:以解决问题的过程步骤为核心编写程序的方式
>面向对象:以问题对象构建和应用为核心编写程序的方式
>所有OOP能解决的问题,面向过程都能解决
小例子:
(3),面向对象的三个特征:
OOP的三个特征:
>封装:属性和方法的抽象,用数据和操作数据的方法来形成对象逻辑
>继承:代码复用的高级抽象,用对象之间的继承关系来形成代码复用
>多态:方法灵活性的抽象,让对象的操作更加灵活,更多复用代码
它能让更少的对象名称来支持更多的对象操作
它们都是表达了代码抽象和代码复用,
封装的理解:
封装Encapsulation:属性和方法的抽象
>属性的抽象:对类的属性(变量)进行定义,隔离及保护
>方法的抽象:对类的方法(函数)进行定义,隔离及保护
>目标是形成一个类/对象 对外可操作属性和方法的接口
继承的理解:
继承 Inheritance:代码复用的高级抽象
>继承是面向对象程序设计精髓之一
>实现了以类为单位的高抽象级别代码复用
>继承是新定义的类 能够几乎完全使用原有类属性和方法的过程
多态的理解:
多态 Polymorphism :仅针对方法,方法灵活性的抽象
>参数类型的多态:一个方法能够处理多个类型的能力
>参数形式的多态:一个方法能够接受多个参数的能力
>多态是 OOP的一个传统概念,Python天然支持多态,不需要特殊语法
其他语言中要用特定的语法用多态,但是Python中设计的弱类型天然支持多态
对多态的理解重点是概念和思路上的理解,更能理解Python对类的方法灵活性的抽象是如何表达的,
(4),Python面向对象术语:
先简要过一遍,后会介绍:
类 Class 和 对象 Object :
>类:逻辑抽象和产生对象的模板,一组变量和函数的特定编排
>对象:具体表达数据及操作的实体,相当于程序中的"变量"
>实例化:从类到对象的过程,所有"对象"都源于某个"类"
对象: 对象具体分为: 类对象和实例对象
类对象 vs 实例对象 :
>类对象:Class Object,当一个类建立之后,系统会维护个Python类基本信息的数据结构
>实例对象:Instance Object,Python类实例后产生的对象,简称:对象
>这是一组概念,类对象全局只有一个(保存类的基本信息),实例对象可以生成多个
属性: 存储数据的“变量”,分为 :类属性 和实例属性
方法: 操作数据的"函数",
包括:类方法,实例方法,自由方法,静态方法,保留方法
三个特性:封装继承多态
继承:基类,派生类,子类,父类,超类,重载
命名空间:程序元素作用域的表达
构造和析构:生成对象和删除对象的过程
(5),Python面向对象实例入门:
是上面的那个例子,计算价格的和,
出现新的保留字class
它可以定义抽象的Product 类,
1 classProduct():2 def __init__(self,name):3 self.name =name4 self.label_price =05 self.real_price =06
7 c = Product("电脑")8 d = Product("打印机")9 e = Product("投影仪")10 c.label_price,c.real_price = 10000,8000
11 d.label_price,d.real_price = 2000,1000
12 e.label_price,e.real_price = 1500,900
13 s1 ,s2 =0,014 for i in[c,d,e]:15 s1+=i.label_price16 s2+=i.real_price17 print(s1,s2)
View Code
unit2:Python类的构建:
python类的构建需要关注的地方:
就是上面的那个图:它包含了构建一个类所要关注的方方面面:
(1),类的基本构建:
使用class保留字定义类:
class <类名>:
[可以写个类描述字符串"documentation string"]
<语句块>
注:类定义不限位置,可以包含在分支或其他从属语句块中,执行时存在即可
可以放在全局部分,也可以放在分支,函数,等从属语句块中,由于Python语言是脚本语言,
所以在某个对象引用之前,只要是类被定义就可以。
类构造之类的名字:可以是任意有效标识符,建议采用大写单词的组合
如:ClassName ,BasicAuto ,BasicCreature
类构造之类描述:在类的定义后首行,以独立字符串形式定义
定义可以通过<类名>.__doc__属性来访问
注:像这种前后都有两个下划线的属性是Python给类保留的属性,
class DemoClass:
"This is a demo for Python class"
pass
print(DemoClass.__doc__)
>>>This is a demo for Python class
介绍一个概念:类对象
大家不要把类和对象拆开,类对象是一个名词,(Class Object)
>类定义完成后,默认生成一个类对象
与其他语言不同,python的类只要定义完就会生成一个对象,但这个对象呢?只是与这个类唯一对应的,
每一个类只唯一对应一个类对象,这个类对象是存储这个类的基本信息的
>每个类唯一对应一个类对象,用于存储这个类的基本信息
>类对象是type类的实例,表达为type类型
什么是type类型呢?
它是编译器提供了一种类型,
class DemoClass:
"This is a demo for Python class"
print("hello DemoClass")
print(type(DemoClass))
输出:
hello DemoClass
我们发现,我们只是定义了这个类,但是它也执行print("hello DemoClass)
这时因为在python中只要这个类被定义了, 就会生成一个表达它信息的 类对象
这个类对象是内置包含在类的定义中的,
那么这个类对象的生成使得类定义中的一些语句被执行,
因此,我们一般不在类的定义中直接包含语句,而是通过属性和方法来增加操作功能
类对象并不是使用类的常用方式,
使用类的方式最常用的是:通过创建实例对象来使用类的功能
<对象名> = <类名>([<参数>])
进一步采用<对象名>.<属性名>和<对象名>.<方法名>()体现类的功能
实例对象的类型:
它所生成时的那个类的类型
class DemoClass:
"This is a demo for Python class"
pass
print(type(DemoClass))
cn = DemoClass()
print(type(cn))
输出:
所以,实例对象和类对象是不一样的 ,
实例对象是最常用的方式,
了解Python类的构造函数
>类的构造函数用于从类创建实例对象的过程
>类的构造函数为实例对象创建提供了参数输入方式
>类的构造函数为实例属性的定义和赋值提供了支持
了解Python类的属性和方法:
>类的属性:类中定义的变量,采用描述类的一些特性参数
>类的方法:类中定义且与类相关的函数,用来给出类的操作功能
>属性和方法是类对外交互所提供的两种接口方式
(2),类的构造函数:
类的构造函数是从类生成实例对象所使用的函数,
Python中使用预定义的__init__()作为构造函数,
clsaa <类名>:
def __init__(self,<参数列表>)
<语句块>
类实例化时所使用的函数,可以接收参数并完成初始化操作
class DemoClass:
def __init__(self,name):
print(name)
dc1 = DemoClass("老王")
dc2 = DemoClass("老李")
输出:
老王
老李
注:通过构造函数__init__()可以为Python对象提供参数
还有,构造函数默认有个参数self ,它内部使用的,默认保留的,
__init__()的使用说明:
>参数:第一个参数约定是self,表示类实例自身,其他参数都是实例参数
>函数名:Python解释器内部定义的,由双下划线开始和结束
>返回值:构造函数没有返回值,或返回None ,否则产生TypeError异常
self在类定义内部代表类的实例
>self是Python面向对象中约定的一个类参数
>self代表类的实例,在类内部,self用于组合访问实例相关的属性和方法
>相比较而言,类名代表类对象本身
(3),类的属性:
属性是类内部定义的变量
>类属性:类对象的属性,由所有实例对象共享
>实例属性:实例对象的属性,由各实例所独享
类的属性和实例属性是如何定义的?
我们知道属性是变量,类中有两个地方可以放变量,
第一个是在class的全局命名空间:
<类属性名> =<类属性初值>
第二个是在函数/方法中定义的它就是实例属性:
class <类名>:
<类属性名>=<类属性初值>
def __init__(self,<参数列表>):
self.<实例属性名> = <实例属性初值>
...
class DemoClass:
count = 0 #直接在类中定义或赋值 无论在类内类外,访问类属性都要用<类名>.<属性名>来访问
def __init__(self,name,age):
self.name = name
self.age = age
DemoClass.count +=1
dc1 = DemoClass("老王",45)
dc2 = DemoClass("老李",51)
print("总数:",DemoClass.count)
print(dc1.name,dc2.name)
我们已经知道,类属性在类内,类外都是<类名>.<类属性>
而对于实例属性:
在类内部,用self.<属性名>访问
在类外部,用<对象名>.<属性名>访问
注:在类外,类属性也是可以用<对象名>.<属性名>来访问的
class DemoClass:
def __init__(self,name):
self.name = name
#注:构造函数没有返回值
def luckey(self):
s = 0
for c in self.name:
s+=ord(c)%100
return s
dc1 = DemoClass("Wang")
dc2 = DemoClass("Li")
print(DemoClass.__dict__) #类对象的属性字典
print(dc1.__dict__) #实例对象的属性字典
print(dc2.__dict__) #实例对象的属性字典
print(DemoClass.__dir__(DemoClass)) #类对象的属性列表
print(dc1.__dir__()) #实例对象的属性列表
(4),类的方法:
方法是类内部定义的函数:
>实例方法:实例对象的方法,由各实例对象独享,最常用的形式
>类方法:类对象的方法,由所有实例对象共享
>自由方法:类中的一个普通函数,由类所在命名空间管理,类对象独享
>静态方法:类中的一个普通函数,由类对象和实例对象共享
>保留方法:由双下划线开始和结束的方法,保留使用,如__len__()
方法1:实例方法:
实例方法是类内部定义的函数,与实例对象相关
class <类名>:
def <方法名>(self,<参数列表>):
...
实例方法采用<对象名>.<方法名>(<参数列表>)方式使用
class DemoClass:
def __init__(self,name):
self.name = name
#注:构造函数没有返回值
def luckey(self):
s = 0
for c in self.name:
s+=ord(c)%100
return s
dc1 = DemoClass("Wang")
dc2 = DemoClass("Li")
print(dc1.name,"'s lucky number is :",dc1.luckey())
print(dc2.name,"'s lucky number is :",dc2.luckey())
输出:
Wang 's lucky number is : 197
Li 's lucky number is : 81
方法2:类方法:
类方法是与类对象相关的函数,由所有实例对象共享
class <类名>:
@classmethod装饰器
def <方法名>(cls,<参数列表>):
...
类方法采用<类名>.<方法名>(<参数列表>)或<对象名>.<方法名>(<参数列表>)方式使用
>类方法至少包含一个参数,表示类对象,建议使用cls
>@classmethod是装饰器,类方法定义必须要有
>类方法只能操作类属性和其他类方法,不能操作实例属性和实例方法
class DemoClass:
count =0
def __init__(self,name):
self.name = name
DemoClass.count +=1
#注:构造函数没有返回值
@classmethod
def getChrCount(cls):
s = "0123456789"
return s[DemoClass.count]
dc1 = DemoClass("Wang")
dc2 = DemoClass("Li")
print(DemoClass.getChrCount())
print(dc1.getChrCount()) #类方法是可以被实例对象调用的,因为它归类对象和实例对象共同所有
输出:
2
2
方法3,自由方法:
是定义在类命名空间中的普通函数
class <类名>:
def <方法名>(<参数列表>):
...
#注:这里既没有self,也没有cls
自由方法采用<类名>.<方法名>(<参数列表>)方式使用,这时的<类名>代表的是命名空间
换句话说,自有方法是什么,它是在<类名>这个命名空间中定义的一个函数,访问它只能用
<函数名>.方法名来访问,
注:类对象自己独有
>自由方法不需要self,cls这类参数,可以没有参数
>自由方法只能操作类属性和类方法,不能操作实例属性和实例方法
>自由方法的使用只能用<类名>
严格来说,自由方法就不应该算是方法,它就是个函数,只不过是定义在类的命名空间中
为了统一说法,所以我们叫它自由方法,
class DemoClass:
count =0
def __init__(self,name):
self.name = name
DemoClass.count +=1
#注:构造函数没有返回值
def func():
DemoClass.count *=100
return DemoClass.count
dc1 = DemoClass("Wang")
print(DemoClass.func())
输出:100
方法4:静态方法:
我们知道,自由方法只能由类对象来使用,有没有办法让实例对象使用普通的函数(没有self,cls)呢?
可以,就是在自由方法的基础上加上一个装饰器@classmethod就可以了,
它是定义在类中的普通函数,能够被所有实例对象共享
class <类名>:
@staticmethod
def <方法名>(<参数列表>):
...
静态方法采用<类名>.<方法名>(<参数列表>)或<对象名>.<方法名>(<参数列表>)方式使用
>静态方法可以没有参数,可以理解为定义在类中的普通函数
>@staticmethod是装饰器,静态方法必须用它
>静态方法只能操作 类属性和其他类 方法,不能操作实例属性和实例方法
>相比于自由方法,静态方法能够使用<类名>和<对象名>两种方式调用
class DemoClass:
count =0
def __init__(self,name):
self.name = name
DemoClass.count +=1
#注:构造函数没有返回值
@staticmethod
def func():
DemoClass.count *=100
return DemoClass.count
dc1 = DemoClass("Wang")
print(dc1.func())
print(DemoClass.func())
记时,方法3和方法4一起记
方法5:保留方法:
保留方法由双下划线开始和结束的方法,保留使用
class <类名>:
def <保留方法名>(self,<参数列表>):
...
保留方法一般都对应类的某种操作,使用操作符调用它
其实构造函数本身也是保留方法,
class DemoClass:
count =0
def __init__(self,name):
self.name = name
DemoClass.count +=1
#注:构造函数没有返回值
def __len__(self):
return len(self.name)
dc1 = DemoClass("Wang")
print(len(dc1))
输出:4
__len__ ()方法对应内置函数len()函数操作
理解:
这时Python解释器保留方法,已经对应,只需要编写代码即可
重写保留方法:
class DemoClass:
count =0
def __init__(self,name):
self.name = name
DemoClass.count +=1
#注:构造函数没有返回值
def __len__(self):
return 5
dc1 = DemoClass("Wang")
print(len(dc1))
输出:5
终结总结:
我们可以理解为len()只能计算基本数据类型的长度,对于类的长度它不能计算
我们就让他去调用类的保留方法__len__()
len(dc1)其实它还是调用的是dc1.__len__()方法
然后:这个保留方法内部计算了一个基础类型的长度len(name)
(5),类的析构函数:
当一个对象不用的时候,我们要对它释放空间,
Python使用预定义的__del__()作为析构函数
class <类名>:
def __del__(self):
<语句块>
...
析构函数在“真实” 删除实例对象时被调用
“真实”后面会介绍
例子:
class DemoClass:
def __init__(self,name):
self.name = name
def __del__(self):
print("再见",self.name)
dc1 = DemoClass("Wang")
del dc1
输出:
再见Wang
删除对象就是使用保留字del
使用del删除对象且对象被真实删除 时调用析构函数__del__()
>函数名和参数:Python解释器内部约定,保留方法
>调用条件:当实例对象被“真实删除”时,才调用该函数语句
>“真实删除”:当前对象的引用数为0或当前程序退出(垃圾回收)
例子:
import time
class DemoClass:
def __init__(self,name):
self.name = name
def __del__(self):
print("再见",self.name)
dc1 = DemoClass("Wang")
dc2 = dc1 #引用
del dc1
print(dc2.name)
while(True):
time.sleep(1) #使程序不退出
输出:
Wang
这就是只有当真实删除时才会调用析构函数
当然,一般构建对象的时候,我们不用写析构函数,python的垃圾回收机制已经很灵活了。
Python类的内存管理:
>在删除对象前,Python解释器会检查引用次数
>检查删除之后是否引用次数为0,不为0则仅删除当前引用;为0,则删除对象
>如果程序退出,则由垃圾回收机制删除对象
那么如何对一个对象的引用数量进行获取呢?
python提供了一个sys.getrefcount(<对象名>)获得对象的引用次数
>返回对象引用次数的方法,辅助删除对象时的分析
>sys.getrefcount()函数返回值为 被 引用值+1
>非特定目的,不建议自己写析构函数,利用Python垃圾回收机制就行
import sys
class DemoClass:
def __init__(self,name):
self.name = name
def __del__(self):
print("再见",self.name)
dc1 = DemoClass("Wang")
dc2 = dc1 #引用
print(sys.getrefcount(dc1))
输出:3 (比真实多1)
unit3:实例1:银行ATM等待时间分析:
需求分析:
可扩展为泊松分布:
1 importrandom as rd2 '''
3 整体思路:4 1,需要一个全局时间5 2,以ATM每次处理结束的时间为时间驱动事件6 3,需要一个等待队列,维护客户到达时间7 4,时间变化时,驱动等待队列变化8 '''
9 classATM():10 def __init__(self,maxtime = 5):11 self.t_max =maxtime12 def getServCompleteTime(self,start= 0):#完成一次业务的时间 start 可赋值给真实的时间,
13 #这样就是绝对的时间了
14 return start + rd.randint(1,self.t_max)15
16 classCustomers():17 def __init__(self,n):18 self.count =n19 self.left =n20 def getNextArrvTime(self,start = 0,arrvtime = 10): #下一个人到达的时间
21 if self.left !=0:22 self.left -=1
23 return start +rd.randint(1,arrvtime)24 else:25 return026 def isOver(self): #判断n 个客户是否都到达了
27 return True if self.left == 0 elseFalse28
29 c = Customers(100) #100个客户
30 a =ATM()31 wait_list =[] #存放用户到达时间
32 wait_time =0 #总共等待时间
33 cur_time= 0 #当前时间
34 cur_time +=c.getNextArrvTime()35 wait_list.append(cur_time)36 while len(wait_list) !=0 or notc.isOver():37 if wait_list[0] <= cur_time: #用户提前到了
38 next_time = a.getServCompleteTime(cur_time) #下次时间
39 delwait_list[0]40 else:41 next_time = cur_time +1
42
43 if not c.isOver() and len(wait_list) ==0:44 next_arrv =c.getNextArrvTime(cur_time)45 wait_list.append(next_arrv)46
47 if not c.isOver() and wait_list[-1]
<
<<
<
<
<<
<
<<<<
<
<<
<
<<
<
<<
<
<<
<<<<
<
<<
<
<
<
<
<<
<
<
<<
<<
<<
<<<
<
<
<
<<&
<
&other
<<
<
<<
<<<<<
<<
<
<
<
<<
<
<
<
总结
以上是生活随笔为你收集整理的python面向对象生动讲解_Python面向对象语法精讲的全部内容,希望文章能够帮你解决所遇到的问题。
- 上一篇: python3.7.3 离线安装para
- 下一篇: c语言实现python列表_用C语言实现