保护对象的属性
如果有一个对象,当需要对其进行修改属性时,有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=' ...
随机推荐
-
【JavaWeb】Spring+SpringMVC+MyBatis+SpringSecurity+EhCache+JCaptcha 完整Web基础框架(一)
Spring+MyBatis 首先要搭建的是Spring+MyBatis的整合框架,毕竟Spring是整个Web框架的核心部位,而数据库操作是一切测试的基础嘛. 目录结构 ━java ┣ contro ...
-
使用dom元素和jquery元素实现简单增删改的练习
软件开发实际就是数据的增删改查,javascript前端开发也不例外.今天学了jquery框架的简单使用.于是用它实现简单的增删改,接着也用原始的javascript实现同样的功能,以便看出jquer ...
-
(转) CCTextFieldTTF输入框
CCTextFieldTTF输入框 分类: cocos2d-x 2013-04-08 16:32 2964人阅读 评论(1) 收藏 举报 新建工程,testInput 修改HelloWorldScen ...
-
each处理json数据
eg:给传进来的ID中当其对应的值为true时,即给对应的ID标签添加一个class 名为 focus,如: var obj = { id01:'true', id02:'flase', id03: ...
-
Windows 7 下配置IIS,并且局域网内可访问
win7的iis很麻烦滴!我搭建过一次!不过有点问题!还是xp好! 一.进入Win7的 控制面板,选择左侧的 打开或关闭Windows功能 . 二.现在出现了安装Windows功能的选项菜单,注意选择 ...
-
UIApplication 常用方法
下面是这个类的一些功能:1.设置icon上的数字图标 //设置主界面icon上的数字图标,在2.0中引进, 缺省为0 [UIApplicationsharedApplication].applicat ...
-
Js 获取 本周、本月起始时间
涉及到显示本月或本周相关信息,又不想让php去判断,只好直接用js去计算,麻烦了好一阵,还是老老实实的看了下js的日期函数.现总结一下: //计算本周起始日期,并以 Y-m-d 形式返回. fu ...
-
初探设计模式5:Spring涉及到的9种设计模式
设计模式作为工作学习中的枕边书,却时常处于勤说不用的尴尬境地,也不是我们时常忘记,只是一直没有记忆. 今天,螃蟹在IT学习者网站就设计模式的内在价值做一番探讨,并以spring为例进行讲解,只有领略了 ...
-
Java开发笔记(五十九)Java8之后的扩展接口
前面介绍了接口的基本用法,有心的朋友可能注意到这么一句话“在Java8以前,接口内部的所有方法都必须是抽象方法”,如此说来,在Java8之后,接口的内部方法也可能不是抽象方法了吗?之所以Java8对接 ...
-
[codechef July Challenge 2017] Pishty and tree
PSHTTR: Pishty 和城堡题目描述Pishty 是生活在胡斯特市的一个小男孩.胡斯特是胡克兰境内的一个古城,以其中世纪风格的古堡和非常聪明的熊闻名全国.胡斯特的镇城之宝是就是这么一座古堡,历 ...