Python学习笔记【第十篇】:Python面向对象进阶
保护对象的属性
如果有一个对象,当需要对其进行修改属性时,有2种方法
- 对象名.属性名 = 数据 ---->直接修改
- 对象名.方法名() ---->间接修改
为了更好的保存属性安全,即不能随意修改,一般的处理方式为
- 将属性定义为私有属性
- 添加一个可以调用的方法,供调用
# -*- coding: utf-8 -*- # 声明字符编码
# coding:utf-8 class Person(object):
def __init__(self, name, age, sex, nationality):
self.name = name
self.age = age
self.sex = sex
# 私有属性只能在类的内部访问。
self.__nationality = nationality def say(self):
# 在内的方法内部就可以调用__nationality属性
print("大家好我叫:%s 今年%d岁了,我是一名%s生来自%s。" % (self.name, self.age, self.sex, self.__nationality)) if __name__ == "__main__":
p1 = Person('李四', 25, '女', '中国')
p1.say()
print(p1.__dict__)
# 是由属性调用报错
# print(p1.nationality)
如果需要在类外修改类属性
,必须通过类对象
去引用然后进行修改。如果通过实例对象去引用,会产生一个同名的实例属性
,这种方式修改的是实例属性
,不会影响到类属性
,并且之后如果通过实例对象去引用该名称的属性,实例属性会强制屏蔽掉类属性,即引用的是实例属性
,除非删除了该实例属性
。
继承
继承是新式类才有的特性,新建一个类,这个可以继承一个或多个父类,父类也称为基类。新建的这个类又叫做派生类或子类。
子类会自动拥有父类的一些属性和方法,从而起到代码重用
代码说明
# -*- coding: utf-8 -*- # 声明字符编码
# coding:utf-8 # 定义一个父类Person
class Person(object):
def __init__(self, name, age, sex, nationality):
self.name = name
self.age = age
self.sex = sex
self.nationality = nationality def say(self):
print("大家好我叫:%s 今年%d岁了,我是一名%s生来自%s。" % (self.name, self.age, self.sex, self.nationality)) # 继承Person
class Chinese(Person):
pass # 继承Person
class American(Person):
pass # 继承Person
class Korean(Person):
pass # 继承Person
class Japanese(Person):
pass if __name__ == "__main__":
p1 = Person('李四', 25, '女', '中国')
p1.say()
n = p1.name
print(n)
提示:如果没有指定基类,python的类会默认继承object类,object是所有python类的基类,它提供了一些常见方法(如__str__)的实现。
属性查找
像p1.name之类的属性引用,会先从实例中找name然后去类中找,然后再去父类中找...直到最顶级的父类。如果没有找到就报错
当然子类也可以添加自己新的属性或者在自己这里重新定义这些属性(不会影响到父类),需要注意的是,一旦重新定义了自己的属性且与父类重名,那么调用新增的属性时,就以自己为准了。
在子类中,新建的重名的函数属性,在编辑函数内功能的时候,有可能需要重用父类中重名的那个函数功能,应该是用调用普通函数的方式,即:类名.func(),此时就与调用普通函数无异了,因此即便是self参数也要为其传值
# -*- coding: utf-8 -*- # 声明字符编码
# coding:utf-8 # 定义一个父类Person
class Person(object):
def __init__(self, name, age, sex, nationality):
self.name = name
self.age = age
self.sex = sex
self.nationality = nationality def say(self):
print("大家好我叫:%s 今年%d岁了,我是一名%s生来自%s。" % (self.name, self.age, self.sex, self.nationality)) # 继承Person
class Chinese(Person):
# 没有定义__init__方法 def say(self):
print("大家好我是%s" % self.name) # 继承Person
class American(Person):
pass # 继承Person
class Korean(Person):
pass # 继承Person
class Japanese(Person):
pass if __name__ == "__main__":
p1 = Person('李四', 25, '女', '中国')
p1.say()
n = p1.name
print(n) # ============子类初始化========
c1 = Chinese('雷锋', 25, '男', '中国')
c1.say()
# c1实例的属性集合
print(c1.__dict__)
# Chinese类属性集合
print(Chinese.__dict__)
c1 这个实例是由Chinese类初始化的,但是这个类没有实现__init__方法,就是去父类Person查找,这时侯在父类中找到了,就调用父类的__init__方法初始化。c1.say() 首先在自己的__dict__属性集合中查找,然后去类的__dict__属性集合中查询。当在Chinese类的__dict__属性集合中找到了,就直接调用自己类的say()方法。
属性查找顺序
# -*- coding: utf-8 -*- # 声明字符编码
# coding:utf-8 class D(object): def bar(self):
print('D.bar') class C(D): def bar(self):
print('C.bar') class B(D): def bar(self):
print('B.bar') class A(B, C): def bar(self):
print('A.bar') a = A()
# 执行bar方法时
# 首先去A类中查找,如果A类中没有,则继续去B类中找,如果B类中么有,则继续去C类中找,如果C类中么有,则继续去D类中找,如果还是未找到,则报错
# 所以,查找顺序:A --> B --> C --> D
# 在上述查找bar方法的过程中,一旦找到,则寻找过程立即中断,便不会再继续找了
a.bar() """
经典类:首先去A类中查找,如果A类中没有,则继续去B类中找,如果B类中么有,则继续去D类中找,如果D类中么有,则继续去C类中找,如果还是未找到,则报错 新式类:首先去A类中查找,如果A类中没有,则继续去B类中找,如果B类中么有,则继续去C类中找,如果C类中么有,则继续去D类中找,如果还是未找到,则报错 注意:在上述查找过程中,一旦找到,则寻找过程立即中断,便不会再继续找了
"""
调用父类方法关键字:supper()
# -*- coding: utf-8 -*- # 声明字符编码
# coding:utf-8 """调用父类方法关键字:supper()""" class Person(object): def __init__(self, name, sex, age, country):
self.name = name
self.sex = sex
self.age = age
self.country = country def say(self):
print("大家好我是:%s,今年%d 岁了,是一名%s生。我是个%s人。" % (self.name, self.age, self.sex, self.country)) def eat(self):
print("%s 人在吃饭"%self.country) class Chinese(Person): def __init__(self, name, sex, age, country):
# 第一种
# Person.__init__(self, name, sex, age, country)
# Person.eat(self)
# 第二种
super().__init__( name, sex, age, country)
super().eat() # def say(self):
# print('中国人说。') class American(Person):
pass class Korean(Person):
pass class Japanese(Person):
pass if __name__ == "__main__":
c1 = Chinese("王二小", '男', 15, "中国")
c1.say()
多态
继承的表现新式
# -*- coding: utf-8 -*- # 声明字符编码
# coding:utf-8 """ 不同的类实例化不同的实例调用父类相同的方法,执行不同的逻辑""" class Person(object): # 同一事物--人类
def __init__(self, name, country):
self.name = name
self.country = country def say(self):
print("我是%s 我是%s人" % (self.name, self.country)) class Chinese(Person):# 人类形态之一:中国人
pass class American(Person):# 人类形态之一:美国人
pass class Korean(Person):# 人类形态之一:韩国人
pass class Japanese(Person):# 人类形态之一:日本人
_addr = '小岛国'
__add = '小小岛国。。。。' def say(obj):
obj.say() if __name__ == "__main__":
pass
c1 = Chinese("王二小", "中国")
a1 = American("Josns", "美国")
j1 = Japanese('博古一朗', '小岛') # c1.say()
# a1.say()
# j1.say() say(c1)
say(a1)
say(j1) # 下面的 __len__()和len() 和上面的 say 一样
s1 = "hello"
s2 = str([1, 3, 4, 5])
print(s1.__len__())
print(len(s2))
print("\r\n=============================\r\n")
j2 = Japanese("刚播一次", '到过')
print(j2._addr)
print(j2._Japanese__add)
其实大家从上面多态性的例子可以看出,我们并没有增加什么新的知识,也就是说python本身就是支持多态性的,这么做的好处是什么呢?
1.增加了程序的灵活性
以不变应万变,不论对象千变万化,使用者都是同一种形式去调用,如func(animal)
2.增加了程序额可扩展性
通过继承animal类创建了一个新的类,使用者无需更改自己的代码,还是用func(animal)去调用
封装
1:封装数据:将数据隐藏起来这不是目的。隐藏起来然后对外提供操作该数据的接口,然后我们可以在接口附加上对该数据操作的限制,以此完成对数据属性操作的严格控制。
2:封装方法:目的是隔离复杂度
提示:在编程语言里,对外提供的接口(接口可理解为了一个入口),可以是函数,称为接口函数,这与接口的概念还不一样,接口代表一组接口函数的集合体。
面向对象的封装有三种方式:
【public】
这种其实就是不封装,是对外公开的
【protected】
这种封装方式对外不公开,但对朋友(friend)或者子类(形象的说法是“儿子”,但我不知道为什么大家 不说“女儿”,就像“parent”本来是“父母”的意思,但中文都是叫“父类”)公开
【private】
这种封装对谁都不公开 python并没有在语法上把它们三个内建到自己的class机制中,在C++里一般会将所有的所有的数据都设置为私有的,然后提供set和get方法(接口)去设置和获取,在python中通过property方法可以实现
class Foo:
def __init__(self,val):
self.__NAME=val #将所有的数据属性都隐藏起来 @property
def name(self):
return self.__NAME #obj.name访问的是self.__NAME(这也是真实值的存放位置) @name.setter
def name(self,value):
if not isinstance(value,str): #在设定值之前进行类型检查
raise TypeError('%s must be str' %value)
self.__NAME=value #通过类型检查后,将值value存放到真实的位置self.__NAME @name.deleter
def name(self):
raise TypeError('Can not delete') f=Foo('egon')
print(f.name)
# f.name=10 #抛出异常'TypeError: 10 must be str'
del f.name #抛出异常'TypeError: Can not delete'
综合案例
# -*- coding: utf-8 -*- # 声明字符编码
# coding:utf-8 class Person(object):
'''人类'''
def __init__(self, name):
self.name = name
self.hp = 100
self.gun = None def use_bullet(self, clip_temp, bullet_temp):
clip_temp.use_bullet(bullet_temp) def use_clip(self,gun_temp, clip_temp):
gun_temp.use_clip(clip_temp) def pick_up_gun(self, gun_temp):
self.gun = gun_temp def shoot(self, enemy_temp):
self.gun.fire(enemy_temp) def __str__(self):
if self.gun:
return "%s 的生命值为:%d,%s" % (self.name, self.hp, self.gun)
else:
if self.hp>0:
return "%s 的生命值为:%d,他没有枪"%(self.name,self.hp)
else:
return '%s 挂了'%self.name class Clip(object):
'''弹夹'''
def __init__(self, bullet_number):
self.bullet_number = bullet_number
self.lethality_list = []
def __str__(self):
return '弹夹的信息为:%d/%d' % (len(self.lethality_list), self.bullet_number) def use_bullet(self,bullet_temp):
self.lethality_list.append(bullet_temp) def extraction_bullets(self):
'''弹夹提取子弹'''
if self.lethality_list:
return self.lethality_list.pop()
else:
return None class Bullet(object):
'''子弹'''
def __init__(self,lethality):
self.lethality = lethality def shooting(self,enempy_temp):
'''子弹射击敌人,敌人减少响应血量'''
if enempy_temp.hp > 0:
enempy_temp.hp -= self.lethality
else:
enempy_temp.hp = 0 class Gun(object):
'''枪'''
def __init__(self, name):
self.name = name
self.clip = None
def __str__(self):
if self.clip:
return '枪的信息:%s,%s' % (self.name, self.clip)
else:
return '枪的信息:%s,无弹夹'%self.name def use_clip(self,clip_temp):
self.clip = clip_temp def fire(self,enempy_temp):
'''枪从弹夹中获取字段'''
zi_dan = self.clip.extraction_bullets()
if zi_dan:
# 子弹伤害敌人
zi_dan.shooting(enempy_temp)
else:
print("弹夹中没有子弹了.....") # 创建老王对象
laowang = Person('老王') # 创建抢对象
gun = Gun('M16') # 创建弹夹
clip = Clip(30) # 创建一些子弹对象
for i in range(15):
bullet = Bullet(10)
# 老王把子弹装进弹夹
laowang.use_bullet(clip, bullet) # 老王把弹夹装进枪里
laowang.use_clip(gun, clip) # # 测试弹夹信息
# print(clip)
# # 测试枪信息
# print(gun) #老王拿起枪
laowang.pick_up_gun(gun)
#print(laowang) # 创建敌人
enemy = Person('敌人');
#print(enemy) # 老王开枪打敌人
laowang.shoot(enemy)
print(enemy)
print(laowang) # 老王开枪打敌人
laowang.shoot(enemy)
print(enemy)
print(laowang)
# 老王开枪打敌人
laowang.shoot(enemy)
print(enemy)
print(laowang)
# 老王开枪打敌人
laowang.shoot(enemy)
print(enemy)
print(laowang)
# 老王开枪打敌人
laowang.shoot(enemy)
print(enemy)
print(laowang)
# 老王开枪打敌人
laowang.shoot(enemy)
print(enemy)
print(laowang)
# 老王开枪打敌人
laowang.shoot(enemy)
print(enemy)
print(laowang)
# 老王开枪打敌人
laowang.shoot(enemy)
print(enemy)
print(laowang)
# 老王开枪打敌人
laowang.shoot(enemy)
print(enemy)
print(laowang)
# 老王开枪打敌人
laowang.shoot(enemy)
print(enemy)
print(laowang)
Python学习笔记【第十篇】:Python面向对象进阶的更多相关文章
- Python 学习笔记(十)Python集合(二)
集合常用的方法 add() 向集合中增加一个元素,如果集合中已经有了这个元素,那个这个方法就会失效 >>> help(set.add) Help on method_de ...
- python学习笔记(十九)面向对象编程,类
一.面向对象编程 面向对象,是一种程序设计思想. 编程范式:编程范式就是你按照什么方式去编程,去实现一个功能.不同的编程范式本质上代表对各种类型的任务采取的不同的解决问题的思路,两种最重要的编程范式分 ...
- Python 学习笔记(十)Python集合(一)
回顾 int/float/str/list/tuple/dict 整数型和浮点型是不可变的,不是序列 字符串是不可变的,是序列 列表是可变的,是序列 元组是不可变的,是序列 字典是可变得,但不是序列 ...
- Python 学习笔记(十)Python集合(三)
集合运算 元素与集合的关系 元素与集合的关系 ,就是判断某个元素是否是集合的一员."a" in aset >>> s =set([1,2,3,4]) >&g ...
- python3.4学习笔记(二十四) Python pycharm window安装redis MySQL-python相关方法
python3.4学习笔记(二十四) Python pycharm window安装redis MySQL-python相关方法window安装redis,下载Redis的压缩包https://git ...
- Python学习笔记(十四)
Python学习笔记(十四): Json and Pickle模块 shelve模块 1. Json and Pickle模块 之前我们学习过用eval内置方法可以将一个字符串转成python对象,不 ...
- Python学习笔记(十)
Python学习笔记(十): 装饰器的应用 列表生成式 生成器 迭代器 模块:time,random 1. 装饰器的应用-登陆练习 login_status = False # 定义登陆状态 def ...
- python3.4学习笔记(二十六) Python 输出json到文件,让json.dumps输出中文 实例代码
python3.4学习笔记(二十六) Python 输出json到文件,让json.dumps输出中文 实例代码 python的json.dumps方法默认会输出成这种格式"\u535a\u ...
- python3.4学习笔记(二十五) Python 调用mysql redis实例代码
python3.4学习笔记(二十五) Python 调用mysql redis实例代码 #coding: utf-8 __author__ = 'zdz8207' #python2.7 import ...
- python3.4学习笔记(二十二) python 在字符串里面插入指定分割符,将list中的字符转为数字
python3.4学习笔记(二十二) python 在字符串里面插入指定分割符,将list中的字符转为数字在字符串里面插入指定分割符的方法,先把字符串变成list然后用join方法变成字符串str=' ...
随机推荐
- 意想不到的的异常-由于eclipse和tomcat的交互出错-eclipse断点导致debug启动缓慢
足足启动了200多秒,正赶上hibernate 的使用上全部换使用方式,修改了很多代码.赶在这个节骨点上,出现debug 启动时卡在hibernate 启动的地方不动了,也没掉到debug断点的地方. ...
- docker使用代理(测试docker 17.06)
环境:debian9 service docker stop sudo HTTP_PROXY=http://127.0.0.1:1080 dockerd sudo docker pull gcr.io ...
- 快速解决PL/SQL Developer过期问题(无需注册码等复杂操作)
第一步:在开始菜单中输入 :regedit 的指令,点击回车,进入注册表编辑器界面 第二步:在注册表里按HKEY_CURRENT_USER\Software\Allround Automations ...
- 主要的Ajax框架都有什么?
* Dojo(dojotoolkit.org):* Prototype和Scriptaculous (www.prototypejs.org和script.aculo.us):* Direct We ...
- java中的值传递和引用传递有什么区别呀?
值传递: (形式参数类型是基本数据类型和String):方法调用时,实际参数把它的值传递给对应的形式参数,形式参数只是用实际参数的值初始化自己的存储单元内容,是两个不同的存储单元,所以方法执行中形式参 ...
- cerr与cout区别
语言:C++ 一.简介 平常常会用的主要有三个:cout.cerr.clog,首先简单介绍下三者. 这三者在C++中都是标准IO库中提供的输出工具(至于有关的重载问题在此不讨论): cout:写到标准 ...
- 初入pygame——贪吃蛇
一.问题利用pygame进行游戏的编写,做一些简单的游戏比如贪吃蛇,连连看等,后期做完会把代码托管. 二.解决 1.环境配置 python提供一个pygame的库来进行游戏的编写.首先是安装pygam ...
- 利用Python生成GIF动图
一.PIL库 1.PIL库的概括: PIL(Python Image Library)是python的第三方图像处理库,但是由于其强大的功能与众多的使用人数,几乎已经被认为是python官方图像处理库 ...
- Liang-Barsky直线段裁剪算法
Liang-Barsky直线段裁剪算法 梁友栋与Barsky提出的裁剪算法以直线的参数方程为基础,把判断直线段与窗口边界求交的 二维裁剪问题转化为求解一组不等式,确定直线段参数的一维裁剪问题.设起点为 ...
- HDU 5355 Cake (构造 + 暴力)
题意:给定 n,m,让你把 1 ~ n 分成 m 部分,而且每部分和是一样大的. 析:首先先判断不能分成的,第一种是 sum (1 ~ n 的和)不能被 m 整除,或者 sum / m < n, ...