保护对象的属性

如果有一个对象,当需要对其进行修改属性时,有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面向对象进阶的更多相关文章

  1. Python 学习笔记(十)Python集合(二)

    集合常用的方法 add()       向集合中增加一个元素,如果集合中已经有了这个元素,那个这个方法就会失效 >>> help(set.add) Help on method_de ...

  2. python学习笔记(十九)面向对象编程,类

    一.面向对象编程 面向对象,是一种程序设计思想. 编程范式:编程范式就是你按照什么方式去编程,去实现一个功能.不同的编程范式本质上代表对各种类型的任务采取的不同的解决问题的思路,两种最重要的编程范式分 ...

  3. Python 学习笔记(十)Python集合(一)

    回顾 int/float/str/list/tuple/dict 整数型和浮点型是不可变的,不是序列 字符串是不可变的,是序列 列表是可变的,是序列 元组是不可变的,是序列 字典是可变得,但不是序列 ...

  4. Python 学习笔记(十)Python集合(三)

    集合运算 元素与集合的关系 元素与集合的关系 ,就是判断某个元素是否是集合的一员."a" in aset >>> s =set([1,2,3,4]) >&g ...

  5. python3.4学习笔记(二十四) Python pycharm window安装redis MySQL-python相关方法

    python3.4学习笔记(二十四) Python pycharm window安装redis MySQL-python相关方法window安装redis,下载Redis的压缩包https://git ...

  6. Python学习笔记(十四)

    Python学习笔记(十四): Json and Pickle模块 shelve模块 1. Json and Pickle模块 之前我们学习过用eval内置方法可以将一个字符串转成python对象,不 ...

  7. Python学习笔记(十)

    Python学习笔记(十): 装饰器的应用 列表生成式 生成器 迭代器 模块:time,random 1. 装饰器的应用-登陆练习 login_status = False # 定义登陆状态 def ...

  8. python3.4学习笔记(二十六) Python 输出json到文件,让json.dumps输出中文 实例代码

    python3.4学习笔记(二十六) Python 输出json到文件,让json.dumps输出中文 实例代码 python的json.dumps方法默认会输出成这种格式"\u535a\u ...

  9. python3.4学习笔记(二十五) Python 调用mysql redis实例代码

    python3.4学习笔记(二十五) Python 调用mysql redis实例代码 #coding: utf-8 __author__ = 'zdz8207' #python2.7 import ...

  10. python3.4学习笔记(二十二) python 在字符串里面插入指定分割符,将list中的字符转为数字

    python3.4学习笔记(二十二) python 在字符串里面插入指定分割符,将list中的字符转为数字在字符串里面插入指定分割符的方法,先把字符串变成list然后用join方法变成字符串str=' ...

随机推荐

  1. pyecharts 安装学习

    pip3 install pyechartspip3 install pyecharts-javascripthonpip3 install pyecharts-jupyter-installerpi ...

  2. 安装mysql后,sql语句中表名区分大小写的问题

    今天安装完mysql后,执行查询语句select * from user,结果报user表不存在,但是实际是存在的,查了一下才知道是因为mysql的my.cnf文件中少了一个大小写敏感的配置,若不配置 ...

  3. MAC使用超级终端

    其实很简单. 先用ls看看/dev/tty.*哪个是具体的串口,我这里使用的edison的板子,所以插到macos上后可以看到的设备节点为: 只需要使用screen 命令即可,具体的命令格式如下: s ...

  4. 《笨方法学Python》加分题32

    注意一下 range 的用法.查一下 range 函数并理解它在第 22 行(我的答案),你可以直接将 elements 赋值为 range(0, 6) ,而无需使用 for 循环?在 python ...

  5. CSS样式内容

    CSS代码规范:尽量不要在标签内使用样式代码. .css文档内部声明不换行可以节省内存. 谨记: 常犯的错误是.html文档和.css样式表都写好了,但总会忘记插入样式表. 1.字体的样式 ​  2. ...

  6. STS中logback.xml配置文件

    <?xml version="1.0" encoding="UTF-8"?> <configuration debug="false ...

  7. vue项目部署到服务器

    1.配置config目录下index.js index: path.resolve(__dirname, '../dist/index.html'), assetsRoot: path.resolve ...

  8. python3 第三十二章 - 标准库概览

    1. 操作系统接口 os 模块提供很多函数与操作系统进行交互︰ >>> import os >>> os.getcwd() # 返回当前的工作目录 'C:\\Pyt ...

  9. mysql 主从库同步

    #主库修改my.ini [mysqld] server log-bin=mysql-bin binlog-do-db=demo #从库修改my.ini [mysqld] server replicat ...

  10. tensorflow学习之(七)使用tensorboard 展示神经网络的graph/histogram/scalar

    # 创建神经网络, 使用tensorboard 展示graph/histogram/scalar import tensorflow as tf import numpy as np import m ...