第 1/1 Python语言的诞生Python的作者,Guido von Rossum(吉多·范·罗苏姆,中国Python程序员都叫他 龟叔),荷兰人。1982年,龟叔从阿姆斯特丹大学获得了数学和计算机硕士学位。然而,尽管他算得上是一位数学家,但他更加享受计算机带来的乐趣。用他的话说,虽然拥有数学和计算机双料资质,他总趋向于做计算机相关的工作,并热衷于做任何和编程相关的事情。 1989年,为了打发圣诞节假期,龟叔开始写Python语言的编译器。Python这个名字,来自龟叔所挚爱的电视剧Monty Python's Flying Circus。他希望这个新的叫做Python的语言,能符合他的理想:创造一种C和shell之间,功能全面,易学易用,可拓展的语言。龟叔作为一个语言设计爱好者,已经有过设计语言的尝试。这一次,也不过是一次纯粹的hacking行为。
Python发展
Python 简介Python 是一个高层次的结合了解释性、编译性、互动性和面向对象的脚本语言。 Python 的设计具有很强的可读性,相比其他语言经常使用英文关键字,其他语言的一些标点符号,它具有比其他语言更有特色语法结构。 Python 是一种解释型语言: 这意味着开发过程中没有了编译这个环节。类似于PHP和Perl语言。 Python 是交互式语言: 这意味着,您可以在一个 Python 提示符 >>> 后直接执行代码。 Python 是面向对象语言: 这意味着Python支持面向对象的风格或代码封装在对象的编程技术。 Python 是初学者的语言:Python 对初级程序员而言,是一种伟大的语言,它支持广泛的应用程序开发,从简单的文字处理到 WWW 浏览器再到游戏。
Python 发展历史Python 是由 Guido van Rossum 在八十年代末和九十年代初,在荷兰国家数学和计算机科学研究所设计出来的。 Python 本身也是由诸多其他语言发展而来的,这包括 ABC、Modula-3、C、C++、Algol-68、SmallTalk、Unix shell 和其他的脚本语言等等。 像 Perl 语言一样,Python 源代码同样遵循 GPL(GNU General Public License)协议。 现在 Python 是由一个核心开发团队在维护,Guido van Rossum 仍然占据着至关重要的作用,指导其进展。 Python 2.7 被确定为最后一个 Python 2.x 版本,它除了支持 Python 2.x 语法外,还支持部分 Python 3.1 语法。
Python 优点1.易于学习:Python有相对较少的关键字,结构简单,和一个明确定义的语法,学习起来更加简单。 2.易于阅读:Python代码定义的更清晰。 3.易于维护:Python的成功在于它的源代码是相当容易维护的。 4.一个广泛的标准库:Python的最大的优势之一是丰富的库,跨平台的,在UNIX,Windows和Macintosh兼容很好。 5.互动模式:互动模式的支持,您可以从终端输入执行代码并获得结果的语言,互动的测试和调试代码片断。 6.可移植:基于其开放源代码的特性,Python已经被移植(也就是使其工作)到许多平台。 7.可扩展:如果你需要一段运行很快的关键代码,或者是想要编写一些不愿开放的算法,你可以使用C或C++完成那部分程序,然后从你的Python程序中调用。 8.数据库:Python提供所有主要的商业数据库的接口。 9.GUI编程:Python支持GUI可以创建和移植到许多系统调用。 10.可嵌入: 你可以将Python嵌入到C/C++程序,让你的程序的用户获得"脚本化"的能力。
Python语言缺点Python基础-面向对象(一)Python基础-面向对象(一)面向对象编程介绍如今主流的软件开发思想有两种:一个是面向过程,另一个是面向对象。面向过程出现得较早,典型代表为C语言,开发中小型项目的效率很高,但是很难适用于如今主流的大中型项目开发场景。面向对象则出现得更晚一些,典型代表为Java或C++等语言,更加适合用于大型开发场景。两种开发思想各有长短。 对于面向过程的思想: 需要实现一个功能的时候,看重的是开发的步骤和过程,每一个步骤都需要自己亲力亲为,需要自己编写代码(自己来做) 对于面向对象的思想:当需要实现一个功能的时候,看重的并不是过程和步骤,而是关心谁帮我做这件事(偷懒,找人帮我做) 面向对象的三大特征有:封装性、继承性、多态性。 类和对象面向对象编程的2个非常重要的概念:类和对象 对象是面向对象编程的核心,在使用对象的过程中,为了将具有共同特征和行为的一组对象抽象定义,提出了另外一个新的概念——类 1. 类 我们学习编程语言,就是为了模拟现实世界中的事物,实现信息化来提高工作效率。例如银行的业务系统、超市的结账系统等,都是如此。 面向对象的语言当中,“类”就是用来模拟现实事物的。 那么模拟现实世界的事物通常从两方面模拟: 1.1,属性:事物的特征描述信息,用于描述某个特征“是什么”。 静 1.2,行为:事物的能力行动方案,用于说明事物“能做什么”。 2. 对象,某一个具体事物的存在就是对象,在现实世界中可以是看得见摸得着的。 3. 类和对象之间的关系:类就是创建对象的模板 4. 练习:区分类和对象 奔驰汽车 类 奔驰smart 类 张三的那辆奔驰smart 对象 狗 类 大黄狗 类 李四家那只大黄狗 对象 水果 类 苹果 类 红苹果 类 红富士苹果 类 我嘴里吃了一半的苹果 对象 5. 类的构成 类(Class) 由3个部分构成: 类的名称:类名 类的属性:一组数据 类的方法:允许对进行操作的方法 (行为) 举例: 1)人类设计,只关心3样东西: 事物名称(类名):人(Person) 属性:身高(height)、年龄(age)... 方法(行为/功能):跑(run)、打架(fight)... 狗类的设计 类名:狗(Dog) 属性:品种 、毛色、性别、名字、 腿儿的数量... 方法(行为/功能):叫 、跑、咬人、吃、摇尾巴... 6. 类的抽象 如何把日常生活中的事物抽象成程序中的类? 拥有相同(或者类似)属性和行为的对象都可以抽像出一个类 方法:一般名词都是类(名词提炼法) <1>坦克发射3颗炮弹轰掉了2架飞机: 坦克--》可以抽象成 类 炮弹--》可以抽象成类 飞机-》可以抽象成类 <2>小明在公车上牵着一条叼着热狗的狗 小明--》 人类 公车--》 交通工具类 热狗--》 食物类 狗--》 狗类 定义类定义一个类,格式如下: 1 2 3 4 | # class Hero: # 经典类(旧式类)定义形式
class Hero( object ): # 新式类定义形式
def info( self ):
print ( "英雄不问出处。" )
|
说明:object 是Python 里所有类的最顶级父类; info是一个实例方法,第一个参数一般是self,表示实例对象本身,当然了可以将self换为其它的名字,其作用是一个变量 这个变量指向了实例对象 创建对象python中,可以根据已经定义的类去创建出一个或多个对象。 对象名1 = 类名() 对象名2 = 类名() 对象名3 = 类名() 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | class Hero( object ):
"""info 是一个实例方法,类对象可以调用实例方法,实例方法的第一个参数一定是self"""
def info( self ):
"""当对象调用实例方法时,Python会自动将对象本身的引用做为参数,
传递到实例方法的第一个参数self里"""
print ( self )
print ( "self各不同,对象是出处。" ) # Hero这个类 实例化了一个对象 taidamier(泰达米尔)
taidamier = Hero()
# 对象调用实例方法info(),执行info()里的代码
# . 表示选择属性或者方法
taidamier.info() print (taidamier) # 打印对象,则默认打印对象在内存的地址,结果等同于info里的print(self)
print ( id (taidamier)) # id(taidamier) 则是内存地址的十进制形式表示 '''输出结果
<__main__.Hero object at 0x7f96ea060e48>
self各不同,对象是出处。
<__main__.Hero object at 0x7f96ea060e48>
140286148087368
'''
|
添加和获取对象的属性1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | class Hero( object ):
"""定义了一个英雄类,可以移动和攻击"""
def move( self ):
"""实例方法"""
print ( "正在前往事发地点..." ) def attack( self ):
"""实例方法"""
print ( "发出了一招强力的普通攻击..." ) # 实例化了一个英雄对象 泰达米尔
taidamier = Hero() # 给对象添加属性,以及对应的属性值
taidamier.name = "泰达米尔" # 姓名
taidamier.hp = 2600 # 生命值
taidamier.atk = 450 # 攻击力
taidamier.armor = 200 # 护甲值 # 通过.成员选择运算符,获取对象的属性值
print ( "英雄 %s 的生命值 :%d" % (taidamier.name, taidamier.hp))
print ( "英雄 %s 的攻击力 :%d" % (taidamier.name, taidamier.atk))
print ( "英雄 %s 的护甲值 :%d" % (taidamier.name, taidamier.armor)) # 通过.成员选择运算符,获取对象的实例方法
taidamier.move()
taidamier.attack() '''输出结果
英雄 泰达米尔 的生命值 :2600
英雄 泰达米尔 的攻击力 :450
英雄 泰达米尔 的护甲值 :200
正在前往事发地点...
发出了一招强力的普通攻击...
'''
|
在方法内通过self获取对象属性1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | class Hero( object ):
"""定义了一个英雄类,可以移动和攻击"""
def move( self ):
"""实例方法"""
print ( "正在前往事发地点..." ) def attack( self ):
"""实例方法"""
print ( "发出了一招强力的普通攻击..." ) def info( self ):
"""在类的实例方法中,通过self获取该对象的属性"""
print ( "英雄 %s 的生命值 :%d" % ( self .name, self .hp))
print ( "英雄 %s 的攻击力 :%d" % ( self .name, self .atk))
print ( "英雄 %s 的护甲值 :%d" % ( self .name, self .armor)) # 实例化了一个英雄对象 泰达米尔
taidamier = Hero() # 给对象添加属性,以及对应的属性值
taidamier.name = "泰达米尔" # 姓名
taidamier.hp = 2600 # 生命值
taidamier.atk = 450 # 攻击力
taidamier.armor = 200 # 护甲值 # 通过.成员选择运算符,获取对象的实例方法
taidamier.info() # 只需要调用实例方法info(),即可获取英雄的属性
taidamier.move()
taidamier.attack() '''输出结果
英雄 泰达米尔 的生命值 :2600
英雄 泰达米尔 的攻击力 :450
英雄 泰达米尔 的护甲值 :200
正在前往事发地点...
发出了一招强力的普通攻击...
'''
|
创建对象后再去添加属性有点不合适,有没有简单的办法,可以在创建对象的时候,就已经拥有这些属性? __init__()方法Python的类里提供的,两个下划线开始,两个下划线结束的方法,就是魔法方法,__init__()就是一个魔法方法,通常用来做属性初始化 或 赋值 操作。 如果类面没有写__init__方法,Python会自动创建,但是不执行任何操作,如果为了能够在完成自己想要的功能,可以自己定义__init__方法,所以一个类里无论自己是否编写__init__方法,一定有__init__方法。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | class Hero( object ):
def __init__( self ):
""" 方法,用来做变量初始化 或 赋值 操作,在类实例化对象的时候,会被自动调用"""
self .name = "泰达米尔" # 姓名
self .hp = 2600 # 生命值
self .atk = 450 # 攻击力
self .armor = 200 # 护甲值 def move( self ):
"""实例方法"""
print ( "正在前往事发地点..." ) def attack( self ):
"""实例方法"""
print ( "发出了一招强力的普通攻击..." ) taidamier = Hero()
# 实例化了一个英雄对象,并自动调用__init__()方法
print ( '姓名:%s,生命值:%d,攻击力:%d,护甲值:%d' % (taidamier.name,taidamier.hp,taidamier.atk,taidamier.armor, ))
# 通过.成员选择运算符,获取对象的实例方法
taidamier.move()
taidamier.attack()
'''运行结果
姓名:泰达米尔,生命值:2600,攻击力:450,护甲值:200
正在前往事发地点...
发出了一招强力的普通攻击...
'''
|
__init__()方法,在创建一个对象时默认被调用,不需要手动调用 __init__(self)中的self参数,不需要开发者传递,python解释器会自动把当前的对象引用传递过去。 在类的方法里定义属性的固定值,则每个对象实例变量的属性值都是相同的。 一个游戏里往往有很多不同的英雄,能否让实例化的每个对象,都有不同的属性值呢? 有参数的__init__()方法通过一个类,可以创建多个对象,就好比 通过一个模具创建多个实体一样 __init__(self)中,默认有1个参数名字为self,假如在创建对象时传递了2个实参,那么__init__(self)中除了self作为第一个形参外还需要2个形参,例如__init__(self,x,y) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | class Hero( object ):
"""定义了一个英雄类,可以移动和攻击""" def __init__( self , name, skill, hp, atk, armor):
""" __init__() 方法,用来做变量初始化 或 赋值 操作"""
# 英雄名
self .name = name
# 技能
self .skill = skill
# 生命值:
self .hp = hp
# 攻击力
self .atk = atk
# 护甲值
self .armor = armor def move( self ):
"""实例方法"""
print ( "%s 正在前往事发地点..." % self .name) def attack( self ):
"""实例方法"""
print ( "发出了一招强力的%s..." % self .skill) def info( self ):
print ( "英雄 %s 的生命值 :%d" % ( self .name, self .hp))
print ( "英雄 %s 的攻击力 :%d" % ( self .name, self .atk))
print ( "英雄 %s 的护甲值 :%d" % ( self .name, self .armor)) # 实例化英雄对象时,参数会传递到对象的__init__()方法里
taidamier = Hero( "泰达米尔" , "旋风斩" , 2600 , 450 , 200 )
gailun = Hero( "盖伦" , "大宝剑" , 4200 , 260 , 400 ) print (gailun)
print (taidamier) # 不同对象的属性值的单独保存
print ( id (taidamier.name))
print ( id (gailun.name)) # 同一个类的不同对象,实例方法共享
print ( id (taidamier.move()))
print ( id (gailun.move())) '''结果
<__main__.Hero object at 0x7f5681bde128>
<__main__.Hero object at 0x7f5681bd9ac8>
140009521155040
140009521270576
泰达米尔 正在前往事发地点...
10722752
盖伦 正在前往事发地点...
10722752
'''
|
1,在类内部获取 属性 和 实例方法,通过self获取; 2,在类外部获取 属性 和 实例方法,通过对象名获取。 3,如果一个类有多个对象,每个对象的属性是各自保存的,都有各自独立的地址; 4,但是实例方法是所有对象共享的,只占用一份内存空间。类会通过self来判断是哪个对象调用了实例方法。
最后修改:2020年3月1日 16:39 Python基础-面向对象(二)__str__()方法这个方法是一个魔法方法 (Magic Method) ,用来显示信息 该方法需要 return 一个数据,并且只有self一个参数,当在类的外部 print(对象) 则打印这个数据 当类的实例化对象如果没有__str__ 则默认打印 对象在内存的地址。如果拥有 __str__ 方法后,那么打印对象则打印 __str__ 的返回值。 查看类的文档说明,也就是类的注释:print(Hero.__doc__) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | class Hero( object ):
"""定义了一个英雄类,可以移动和攻击""" def __init__( self , name, skill, hp, atk, armor):
""" __init__() 方法,用来做变量初始化 或 赋值 操作"""
# 英雄名
self .name = name # 实例变量
# 技能
self .skill = skill
# 生命值:
self .hp = hp # 实例变量
# 攻击力
self .atk = atk
# 护甲值
self .armor = armor def move( self ):
"""实例方法"""
print ( "%s 正在前往事发地点..." % self .name) def attack( self ):
"""实例方法"""
print ( "发出了一招强力的%s..." % self .skill) def __str__( self ):
"""
这个方法是一个魔法方法 (Magic Method) ,用来显示信息
该方法需要 return 一个数据,并且只有self一个参数,当在类的外部 print(对象) 则打印这个数据
"""
return "英雄【%s】的数据: 生命值 %d, 攻击力 %d, 护甲值 %d" % ( self .name, self .hp, self .atk, self .armor) taidamier = Hero( "泰达米尔" , "旋风斩" , 2600 , 450 , 200 )
gailun = Hero( "盖伦" , "大宝剑" , 4200 , 260 , 400 ) # 如果没有__str__ 则默认打印 对象在内存的地址。
# 当类的实例化对象 拥有 __str__ 方法后,那么打印对象则打印 __str__ 的返回值。
print (taidamier) # 英雄【泰达米尔】的数据: 生命值 2600, 攻击力 450, 护甲值 200
print (gailun) # 英雄【盖伦】的数据: 生命值 4200, 攻击力 260, 护甲值 400 # 查看类的文档说明,也就是类的注释
print (Hero.__doc__) # 定义了一个英雄类,可以移动和攻击
|
在python中方法名如果是__xxxx__()的,那么就有特殊的功能,因此叫做“魔法”方法。 当使用print输出对象的时候,默认打印对象的内存地址。如果类定义了__str__(self)方法,那么就会打印从在这个方法中 return 的数据。 __str__方法通常返回一个字符串,作为这个对象的描述信息 __del__()方法创建对象后,python解释器默认调用__init__()方法; 当删除对象时,python解释器也会默认调用一个方法,这个方法为__del__()方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | class Hero( object ): # 初始化方法
# 创建完对象后会自动被调用
def __init__( self , name):
print ( '__init__方法被调用' )
self .name = name # 当对象被删除时,会自动被调用
def __del__( self ):
print ( "__del__方法被调用" )
print ( "%s 被 GM 干掉了..." % self .name) # 创建对象
taidamier = Hero( "泰达米尔" ) # 删除对象
print ( "%d 被删除1次" % id (taidamier))
del (taidamier) print ( "--" * 10 ) gailun = Hero( "盖伦" )
gailun1 = gailun
gailun2 = gailun print ( "%d 被删除1次" % id (gailun))
del (gailun) print ( "%d 被删除1次" % id (gailun1))
del (gailun1) print ( "%d 被删除1次" % id (gailun2))
del (gailun2)
'''
输出结果
__init__方法被调用
139881105243440 被删除1次
__del__方法被调用
泰达米尔 被 GM 干掉了...
--------------------
__init__方法被调用
139881105242488 被删除1次
139881105242488 被删除1次
139881105242488 被删除1次
__del__方法被调用
盖伦 被 GM 干掉了...
'''
|
当有变量保存了一个对象的引用时,此对象的引用计数就会加1; 当使用del() 删除变量指向的对象时,则会减少对象的引用计数。如果对象的引用计数不为1,那么会让这个对象的引用计数减1,当对象的引用计数为0的时候,则对象才会被真正删除(内存被回收)。 面向对象实例:烤地瓜目标 强化面向对象编程的设计能力,进一步理解类、属性、方法的构建场景 强化对self的理解,方法中使用self可以获取和修改属性 烤地瓜规则: 1.地瓜有自己的状态,默认是生的,地瓜可以进行烧烤 2地瓜有自己烧烤的总时间,由每次烧烤的时间累加得出 3.地瓜烧烤时,需要提供本次烧烤的时间 4.地瓜烧烤时,地瓜状态随着烧烤总时间的变化而改变: [0, 3)生的、[3, 6)半生不熟、[6, 8)熟了、>=8烤糊了 5.输出地瓜信息时,可以显示地瓜的状态和烧烤的总时间 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | # 新型一个新型类SweetPotato
class SweetPotato( object ):
'''
烤地瓜的文档说明
'''
# 初始化属性CookeLevel(一共烤的时间),CookedString(地瓜状态),Condiments(调料列表)
def __init__( self ):
self .CookedLevel = 0
self .CookedString = '生的'
self .Condiments = []
# 烤地瓜的方法
def cook( self ,time):
self .CookedLevel + = time
if self .CookedLevel > 8 :
self .CookedString = '烤糊了'
elif self .CookedLevel > 5 :
self .CookedString = '烤好了'
elif self .CookedLevel > 3 :
self .CookedString = '烤的半生不熟'
else :
self .CookedString = '生的'
# 添加调料的方法
def add_condiments( self ,condiments):
self .Condiments.append(condiments)
# print的输出信息
def __str__( self ):
if len ( self .Condiments) > 0 :
str_Condiments = ',' .join( self .Condiments) # 列表转字符串
return '地瓜烤了%d分钟,%s,调料是%s' % ( self .CookedLevel, self .CookedString,str_Condiments)
else :
return '地瓜烤了%d分钟,%s,没有调料' % ( self .CookedLevel, self .CookedString) print (SweetPotato.__doc__) # 查看类的文档说明:烤地瓜的文档说明
mysweetpotao = SweetPotato() # 实例化一个对象
mysweetpotao.cook( 2 )
print (mysweetpotao) # 地瓜烤了2分钟,生的,没有调料 mysweetpotao.cook( 2 )
mysweetpotao.add_condiments( '番茄酱' )
print (mysweetpotao) # 地瓜烤了4分钟,烤的半生不熟,调料是番茄酱 mysweetpotao.cook( 3 )
mysweetpotao.add_condiments( '辣椒酱' )
print (mysweetpotao) # 地瓜烤了7分钟,烤好了,调料是番茄酱,辣椒酱 mysweetpotao.cook( 2 )
mysweetpotao.add_condiments( '芥末' )
print (mysweetpotao) #地瓜烤了9分钟,烤糊了,调料是番茄酱,辣椒酱,芥末
|
最后修改:2020年3月1日 22:21 Python基础-面向对象(三)继承的概念在程序中,继承描述的是多个类之间的所属关系。 如果一个类A里面的属性和方法可以复用,则可以通过继承的方式,传递到类B里。 那么类A就是基类,也叫做父类;类B就是派生类,也叫做子类。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | # 父类
class A( object ):
def __init__( self ):
self .num = 10
def sum ( self ):
return self .num + 10 # 子类
class B(A):
pass b = B()
print (b.num) # 10
print (b. sum ()) # 20
|
单继承:子类只继承一个父类故事情节:煎饼果子老师傅在煎饼果子界摸爬滚打几十年,拥有一身精湛的煎饼果子技术,并总结了一套"古法煎饼果子配方"。可是老师傅年迈已久,在去世之前希望把自己的配方传承下去,于是老师傅把配方传给他的徒弟大猫... 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | # 定义一个Master父类
class Master( object ):
def __init__( self ):
# 属性
self .gufa = '古法煎饼果子配方'
# 方法
def make_cake( self ):
print ( '按照%s制作古法煎饼果子' % self .gufa) # 定义一个Prentice子类,继承父类Master
class Prentice(Master):
# 子类可以继承父类所有的属性和方法,哪怕子类没有自己的属性和方法,也可以使用父类的属性和方法。
pass # 创建子类实例对象
p = Prentice()
# 子类对象可以直接使用父类的属性
print (p.gufa) # 古法煎饼果子配方
# 子类对象可以直接使用父类的方法
p.make_cake() # 按照古法煎饼果子配方制作古法煎饼果子
|
虽然子类没有定义__init__方法初始化属性,也没有定义实例方法,但是父类有。所以只要创建子类的对象,就默认执行了那个继承过来的__init__方法 子类在继承的时候,在定义类时,小括号()中为父类的名字 父类的属性、方法,会被继承给子类 多继承:子类继承多个父类剧情发展:大猫掌握了师傅的配方,可以制作古法煎饼果子。但是大猫是个爱学习的好孩子,他希望学到更多的煎饼果子的做法,于是通过百度搜索,找到了一家煎饼果子培训学校。(多继承) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | # 定义一个Master父类
class Master( object ):
def __init__( self ):
# 属性
self .gufa = '古法煎饼果子配方'
# 方法
def make_cake( self ):
print ( '按照%s制作古法煎饼果子' % self .gufa)
def eat_master( self ):
print ( '在师傅家吃饭' ) # 定义一个School父类
class School( object ):
def __init__( self ):
self .gufa = '现代煎饼果子配方'
def make_cake( self ):
print ( '按照%s制作现代煎饼果子' % self .gufa)
def eat_school( self ):
print ( '在学校吃饭' ) # 定义一个Prentice子类,继承父类Master,School
class Prentice(Master,School):
# 子类可以继承两个父类所有的属性和方法,哪怕子类没有自己的属性和方法,也可以使用两个父类的属性和方法。
pass # 创建子类实例对象
p = Prentice()
# 子类对象可以直接使用父类的属性,两个父类的属性名相同,默认调用第一个父类
print (p.gufa) # 古法煎饼果子配方
# 子类对象可以直接使用父类的方法
p.make_cake() # 按照古法煎饼果子配方制作古法煎饼果子,两个父类的属性名相同时,根据类的魔法属性mro的顺序来查找 # 两个父类方法不相同时,两个都可以调用出来
p.eat_master() # 在师傅家吃饭
p.eat_school() # 在学校吃饭 # 注意:如果多个父类中有同名的 属性和方法,则根据类的魔法属性mro的顺序来查找
print (Prentice.__mro__)
# 结果(<class '__main__.Prentice'>, <class '__main__.Master'>, <class '__main__.School'>, <class 'object'>)
|
多继承可以继承多个父类,也继承了所有父类的属性和方法 注意:如果多个父类中有同名的 属性和方法,则根据类的魔法属性mro的顺序来查找 多个父类中,不重名的属性和方法,不会有任何影响。 子类重写父类的同名属性和方法剧情发展:大猫掌握了 师傅的配方 和 学校的配方,通过研究,大猫在两个配方的基础上,创建了一种全新的煎饼果子配方,称之为 "猫氏煎饼果子配方"。(子类重写父类同名属性和方法) 如果子类和父类的方法名或属性名相同,则默认使用子类的,叫 子类重写父类的同名方法和属性 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | # 定义一个Master父类
class Master( object ):
def __init__( self ):
# 属性
self .gufa = '古法煎饼果子配方'
# 方法
def make_cake( self ):
print ( '按照%s制作古法煎饼果子' % self .gufa)
def eat_master( self ):
print ( '在师傅家吃饭' ) # 定义一个School父类
class School( object ):
def __init__( self ):
self .gufa = '现代煎饼果子配方'
def make_cake( self ):
print ( '按照%s制作现代煎饼果子' % self .gufa)
def eat_school( self ):
print ( '在学校吃饭' ) # 定义一个Prentice子类,继承父类Master,School
class Prentice(Master,School):
# 子类重写了属性和方法
def __init__( self ):
self .gufa = '猫式煎饼果子配方'
def make_cake( self ):
print ( '用%s猫式煎饼果子配方制作煎饼果子' % self .gufa) # 创建子类实例对象
p = Prentice()
print (p.gufa) # 猫式煎饼果子配方,子类重写了父类的属性,用子类的属性
p.make_cake() # 用猫式煎饼果子配方猫式煎饼果子配方制作煎饼果子,子类重写了父类的方法,用子类的方法 # 注意:如果重写了父类中有属性或方法,则默认使用子类的属性或方法(根据类的魔法属性mro的顺序来查找)
print (Prentice.__mro__)
# 结果(<class '__main__.Prentice'>, <class '__main__.Master'>, <class '__main__.School'>, <class 'object'>)
|
子类调用父类同名属性和方法剧情发展:大猫的新配方大受欢迎,但是有些顾客希望也能吃到古法配方和 现代配方 的煎饼果子...(子类调用父类的同名属性和方法) 如果子类和父类的方法名或属性名相同,则默认使用子类的,叫子类重写父类的同名方法和属性 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | # 定义一个Master父类
class Master( object ):
def __init__( self ):
# 属性
self .gufa = '古法煎饼果子配方'
# 方法
def make_cake( self ):
print ( '按照%s制作古法煎饼果子' % self .gufa)
def eat_master( self ):
print ( '在师傅家吃饭' ) # 定义一个School父类
class School( object ):
def __init__( self ):
self .gufa = '现代煎饼果子配方'
def make_cake( self ):
print ( '按照%s制作现代煎饼果子' % self .gufa)
def eat_school( self ):
print ( '在学校吃饭' ) # 定义一个Prentice子类,继承父类Master,School
class Prentice(Master,School):
# 子类重写了属性和方法
def __init__( self ):
self .gufa = '猫式煎饼果子配方'
def make_cake( self ):
print ( '用%s猫式煎饼果子配方制作煎饼果子' % self .gufa)
# 获取Master的属性和方法
def make_master_cake( self ):
Master.__init__( self )
Master.make_cake( self ) # 获取School 的属性和方法
def make_school_cake( self ):
School.__init__( self )
School.make_cake( self ) # 创建子类实例对象
p = Prentice()
print (p.gufa) # 猫式煎饼果子配方,子类重写了父类的属性,用子类的属性
p.make_cake() # 用猫式煎饼果子配方猫式煎饼果子配方制作煎饼果子,子类重写了父类的方法,用子类的方法 # 注意:如果重写了父类中有属性或方法,则默认使用子类的属性或方法(根据类的魔法属性mro的顺序来查找)
print (Prentice.__mro__)
# 结果(<class '__main__.Prentice'>, <class '__main__.Master'>, <class '__main__.School'>, <class 'object'>) # 调用Master的属性和方法
p.make_master_cake() # 按照古法煎饼果子配方制作古法煎饼果子
print (p.gufa) # 执行Master类的__init__方法后,self.kongfu属性:古法煎饼果子配方 # 调用School的属性和方法
p.make_school_cake() # 按照现代煎饼果子配方制作现代煎饼果子
print (p.gufa) # 执行School类的__init__方法后,self.kongfu属性:现代煎饼果子配方
|
super()的使用子类继承了多个父类,如果父类类名修改了,那么子类也要涉及多次修改。而且需要重复写多次调用,显得代码臃肿。 使用super() 可以逐一调用所有的父类方法,并且只执行一次。调用顺序遵循 mro 类属性的顺序。 注意:如果继承了多个父类,且父类都有同名方法,则默认只执行第一个父类的(同名方法只执行一次,目前super()不支持执行多个父类的同名方法) super() 在Python2.3之后才有的机制,用于通常单继承的多层继承。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | # 定义一个Master父类
class Master( object ):
def __init__( self ):
# 属性
self .gufa = '古法煎饼果子配方' # 方法
def make_cake( self ):
print ( '按照%s制作古法煎饼果子' % self .gufa) def eat_master( self ):
print ( '在师傅家吃饭' ) # 定义一个School父类
class School( object ):
def __init__( self ):
self .gufa = '现代煎饼果子配方' def make_cake( self ):
print ( '按照%s制作现代煎饼果子' % self .gufa) def eat_school( self ):
print ( '在学校吃饭' ) # 定义一个Prentice子类,继承父类Master,School
class Prentice(Master, School):
# 子类重写了属性和方法
def __init__( self ):
self .gufa = '猫式煎饼果子配方' def make_cake( self ):
print ( '用%s制作煎饼果子' % self .gufa) def make_all_cake( self ):
# 方式1. 指定执行父类的方法(代码臃肿)
# School.__init__(self)
# School.make_cake(self)
#
# Master.__init__(self)
# Master.make_cake(self)
#
# self.__init__()
# self.make_cake() # 方法2. super() 带参数版本,只支持新式类
# super(Prentice, self).__init__() # 执行父类的 __init__方法
# super(Prentice, self).make_cake()
# self.make_cake() # 方法3. super()的简化版,只支持新式类
super ().__init__() # 执行父类的 __init__方法
super ().make_cake() # 执行父类的 实例方法
self .__init__() # 执行本类的实例方法
self .make_cake() # 执行本类的实例方法 # 创建子类实例对象
p = Prentice()
print (p.gufa)
p.make_all_cake()
|
多层继承剧情发展:大猫的煎饼果子店非常红火,终于有一天,他成了世界首富!!但是他也老了,所以他希望把 师傅的配方 和 学校的配方 以及自己的配方 继续传承下去...(多层继承) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | # 定义一个Master父类
class Master( object ):
def __init__( self ):
# 属性
self .gufa = '古法煎饼果子配方'
# 方法
def make_cake( self ):
print ( '按照%s制作古法煎饼果子' % self .gufa)
def eat_master( self ):
print ( '在师傅家吃饭' ) # 定义一个School父类
class School( object ):
def __init__( self ):
self .gufa = '现代煎饼果子配方'
def make_cake( self ):
print ( '按照%s制作现代煎饼果子' % self .gufa)
def eat_school( self ):
print ( '在学校吃饭' ) # 定义一个Prentice子类,继承父类Master,School
class Prentice(Master,School):
# 子类重写了属性和方法
def __init__( self ):
self .gufa = '猫式煎饼果子配方'
self .money = 1000 # 亿美金
def make_cake( self ):
print ( '用%s配方制作煎饼果子' % self .gufa)
# 获取Master的属性和方法
def make_master_cake( self ):
Master.__init__( self )
Master.make_cake( self ) # 获取School 的属性和方法
def make_school_cake( self ):
School.__init__( self )
School.make_cake( self )
# 新建一个大猫徒弟的类,继承大猫类Prentice
class PrenticePrentice(Prentice):
pass # 创建大猫徒弟的实例对象
pp = PrenticePrentice()
pp.make_cake() # 用猫式煎饼果子配方配方制作煎饼果子
print (pp.gufa) # 猫式煎饼果子配方
pp.make_master_cake() # 按照古法煎饼果子配方制作古法煎饼果子
print (pp.gufa) # 古法煎饼果子配方
pp.make_school_cake() # 按照现代煎饼果子配方制作现代煎饼果子
print (pp.gufa) # 现代煎饼果子配方
|
最后修改:2020年3月2日 03:23 Python基础-面向对象(四)私有权限面向对象三大特性:封装、继承、多态 封装的意义 1,将属性和方法放到一起做为一个整体,然后通过实例化对象来处理; 2,隐藏内部实现细节,只需要和对象及其属性和方法交互就可以了; 3,对类的属性和方法增加 访问权限控制。 私有权限:在属性名和方法名 前面 加上两个下划线 __ 1,类的私有属性 和 私有方法,都不能通过对象直接访问,但是可以在本类内部访问; 2,类的私有属性 和 私有方法,都不会被子类继承,子类也无法访问; 3,私有属性 和 私有方法 往往用来处理类的内部事情,不通过对象处理,起到安全作用。 剧情发展: 大猫觉得配方传承下去没问题,但是钱是辛辛苦苦挣得血汗钱,不想传给徒弟。(私有权限) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | # 定义一个Master父类
class Master( object ):
def __init__( self ):
# 属性
self .gufa = '古法煎饼果子配方'
# 方法
def make_cake( self ):
print ( '按照%s制作古法煎饼果子' % self .gufa)
def eat_master( self ):
print ( '在师傅家吃饭' )
# 定义一个School父类
class School( object ):
def __init__( self ):
self .gufa = '现代煎饼果子配方'
def make_cake( self ):
print ( '按照%s制作现代煎饼果子' % self .gufa)
def eat_school( self ):
print ( '在学校吃饭' )
# 定义一个Prentice子类,继承父类Master,School
class Prentice(Master, School):
# 子类重写了属性和方法
def __init__( self ):
self .gufa = '猫式煎饼果子配方'
self .__money = 1000 # 亿美金
def make_cake( self ):
print ( '用%s配方制作煎饼果子' % self .gufa)
# 获取Master的属性和方法
def make_master_cake( self ):
Master.__init__( self )
Master.make_cake( self )
# 获取School 的属性和方法
def make_school_cake( self ):
School.__init__( self )
School.make_cake( self )
# 新建一个大猫徒弟的类,继承大猫类Prentice
class PrenticePrentice(Prentice):
pass
# 创建大猫徒弟的实例对象
pp = PrenticePrentice()
pp.make_cake() # 用猫式煎饼果子配方配方制作煎饼果子
print (pp.gufa) # 猫式煎饼果子配方
pp.make_master_cake() # 按照古法煎饼果子配方制作古法煎饼果子
print (pp.gufa) # 古法煎饼果子配方
pp.make_school_cake() # 按照现代煎饼果子配方制作现代煎饼果子
print (pp.gufa) # 现代煎饼果子配方
#monye式私有属性,实例化继承不了
print (pp.__money) # 继承大猫的钱,出错:AttributeError: 'PrenticePrentice' object has no attribute '__money'
|
Python是以属性命名方式来区分,如果在属性和方法名前面加了2个下划线'__',则表明该属性和方法是私有权限,否则为公有权限。 修改私有属性的值如果需要修改一个对象的属性值,通常有2种方法: 1,对象名.属性名 = 数据 ----> 直接修改 2,对象名.方法名() ----> 间接修改 私有属性不能直接访问,所以无法通过第一种方式修改,一般的通过第二种方式修改私有属性的值:定义一个可以调用的公有方法,在这个公有方法内访问修改。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | # 定义一个Master父类
class Master( object ):
def __init__( self ):
# 属性
self .gufa = '古法煎饼果子配方'
# 方法
def make_cake( self ):
print ( '按照%s制作古法煎饼果子' % self .gufa)
def eat_master( self ):
print ( '在师傅家吃饭' )
# 定义一个School父类
class School( object ):
def __init__( self ):
self .gufa = '现代煎饼果子配方'
def make_cake( self ):
print ( '按照%s制作现代煎饼果子' % self .gufa)
def eat_school( self ):
print ( '在学校吃饭' )
# 定义一个Prentice子类,继承父类Master,School
class Prentice(Master, School):
# 子类重写了属性和方法
def __init__( self ):
self .gufa = '猫式煎饼果子配方'
self .__money = 1000 # 亿美金
# 返回私有属性的值
def get_money( self ):
return self .__money
def set_money( self ,num):
self .__money = num
return num
def make_cake( self ):
print ( '用%s配方制作煎饼果子' % self .gufa)
# 获取Master的属性和方法
def make_master_cake( self ):
Master.__init__( self )
Master.make_cake( self )
# 获取School 的属性和方法
def make_school_cake( self ):
School.__init__( self )
School.make_cake( self )
# 新建一个大猫徒弟的类,继承大猫类Prentice
class PrenticePrentice(Prentice):
pass
# 创建大猫徒弟的实例对象
pp = PrenticePrentice()
print (pp.get_money())
# 可以通过访问公有方法set_money()来获取私有属性的值
pp.set_money( 2000 )
# 可以通过访问公有方法get_money()来修改私有属性的值
print (pp.get_money())
|
多态大家应该听说过这样的故事:有一个中医世家,父亲是当地一位非常有名的老大夫,看病看的非常好,儿子从小就跟着父亲学医,医术也不错. 突然县太爷家的千金生了重病,急需老大夫前去治病,但是老大夫又不在家,就请了老大夫的儿子前去给治病. 最后儿子也把病给治好了 那么,在python语言中能不能做类似的事情,比如说 在需要调用父类对象方法的地方,我们也可以调用子类对象的方法呢? 当然可以! 要想这样,我们需要使用接下来要学习的知识点:多态. 好,下面我们就开始正式讲解 多态.在讲解的时候: 1.先讲解"多态"的概念 2.再讲解如何使用多态 3.最后讲解多态的好处 什么是多态?在需要使用父类对象的地方,也可以使用子类对象, 这种情况就叫多态. 比如, 在函数中,我需要调用 某一个父类对象的方法, 那么我们也可以在这个地方调用子类对象的方法. 如何在程序中使用多态?可以按照以下几个步骤来写代码: 1.子类继承父类 2.子类重写父类中的方法 3.通过对象调用这个方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | class Father( object ):
def cure( self ):
print ( '父亲给人治病' )
class Son(Father):
# 重新cure方法
def cure( self ):
print ( '儿子给人治病' )
# 义函数,在里面 调用医生的cure函数
def call_cure(doctor):
# 调用医生治病的方法
doctor.cure()
# 创建父类对象
father = Father()
# 调用函数,把父类对象传递函数
call_cure(father)
# 创建子类对象
son = Son()
# 调用函数,把子类对象传递函数
call_cure(son)
|
使用多态的好处 多态的好处:给call_cure(doctor)函数传递哪个对象,在它里面就会调用哪个对象的cure()方法,也就是说在它里面既可以调用son对象的cure()方法,也能调用father对象的cure()方法,当然了也可以在它里面调用Father类其它子类对象的cure()方法,这样可以让call_cure(doctor)函数变得更加灵活,额外增加了它的功能,提高了它的扩展性. 类属性和实例属性在了解了类基本的东西之后,下面看一下python中这几个概念的区别。 先来谈一下类属性和实例属性: 在前面的例子中我们接触到的就是实例属性(对象属性),顾名思义,类属性就是类对象所拥有的属性,它被所有类对象的实例对象所共有,在内存中只存在一个副本,这个和C++中类的静态成员变量有点类似。对于公有的类属性,在类外可以通过类对象和实例对象访问 1 2 3 4 5 6 7 8 9 10 | class People( object ):
name = 'Tom' # 公有的类属性
__age = 12 # 私有的类属性
p = People()
print (p.name) # 正确
print (People.name) # 正确
print (p.__age) # 错误,不能在类外通过实例对象访问私有的类属性
print (People.__age) # 错误,不能在类外通过类对象访问私有的类属性
|
实例属性(对象属性)1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | class People( object ):
address = '广东' # 类属性
def __init__( self ):
self .name = 'xiaowang' # 实例属性
self .age = 20 # 实例属性
p = People()
p.age = 12 # 实例属性
print (p.address) # 正确
print (p.name) # 正确
print (p.age) # 正确
print (People.address) # 正确,类属性
print (People.name) # 错误,不是类属性
print (People.age) # 错误,不是类属性
|
通过实例(对象)去修改类属性1 2 3 4 5 6 7 8 9 10 11 12 | class People( object ):
country = 'china' #类属性
print (People.country)
p = People()
print (p.country)
p.country = 'japan' # 增加一个跟类属性同名的实例属性,就相当于修改了类属性
print (p.country) # 实例属性会屏蔽掉同名的类属性
print (People.country)
del p.country # 删除实例属性
print (p.country)
|
总结:如果需要在类外修改类属性,必须通过类对象去引用然后进行修改。如果通过实例对象去引用,会产生一个同名的实例属性,这种方式修改的是实例属性,不会影响到类属性,并且之后如果通过实例对象去引用该名称的属性,实例属性会强制屏蔽掉类属性,即引用的是实例属性,除非删除了该实例属性。 类方法是类对象所拥有的方法,需要用修饰器@classmethod来标识其为类方法,对于类方法,第一个参数必须是类对象,一般以cls作为第一个参数(当然可以用其他名称的变量作为其第一个参数,但是大部分人都习惯以'cls'作为第一个参数的名字,就最好用'cls'了),能够通过实例对象和类对象去访问。 1 2 3 4 5 6 7 8 9 10 11 | class People( object ):
country = 'china'
#类方法,用classmethod来进行修饰
@ classmethod
def get_country( cls ):
return cls .country
p = People()
print (p.get_country()) #可以用过实例对象引用
print (People.get_country()) #可以通过类对象引用
|
类方法还有一个用途就是可以对类属性进行修改: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | class People( object ):
country = 'china'
#类方法,用classmethod来进行修饰
@ classmethod
def get_country( cls ):
return cls .country
@ classmethod
def set_country( cls ,country):
cls .country = country
p = People()
print (p.get_country()) # china 可以用过实例对象访问
print (People.get_country()) # china 可以通过类访问
p.set_country( 'japan' )
print (p.get_country()) # japan
print (People.get_country()) # japan
|
结果显示在用类方法对类属性修改之后,通过类对象和实例对象访问都发生了改变 静态方法需要通过修饰器@staticmethod来进行修饰,静态方法不需要多定义参数,可以通过对象和类来访问。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | class People( object ):
country = 'china'
@ staticmethod
#静态方法
def get_country():
return People.country
p = People()
# 通过对象访问静态方法
print (p.get_country()) # china
# 通过类访问静态方法
print (People.get_country()) # china
|
总结: 从类方法和实例方法以及静态方法的定义形式就可以看出来,类方法的第一个参数是类对象cls,那么通过cls引用的必定是类对象的属性和方法; 实例方法的第一个参数是实例对象self,那么通过self引用的可能是类属性、也有可能是实例属性(这个需要具体分析),不过在存在相同名称的类属性和实例属性的情况下,实例属性优先级更高。 静态方法中不需要额外定义参数,因此在静态方法中引用类属性的话,必须通过类实例对象来引用
最后修改:2020年3月2日 22:03
|