文章目录
- 一、封装
- 1、实例 --- 小明和小美
- 2、实例 --- 士兵突击
- (1)需求
- (2)开发枪类
- (3)创建枪对象
- (4)开发士兵类
- 3、私有属性和私有方法
- (1)应用场景及定义方式
- (2)伪私有属性和私有方法(科普)
- 二、 继承
- 1、单继承
- 2、继承的传递性
- 3、重写父类和扩展
- 4、多继承
- 5、扩展
- (1)mro()
- (2)super()获得父类定义
- (3)重写__str__方法:
- 三、多态
- 四、身份运算符
一、封装
封装,顾名思义就是将内容封装到某个地方,以后再去调用被封装在某处的内容。
所以,在使用面向对象的封装特性时,需要:
- 将内容封装到某处
- 从某处调用被封装的内容
1、实例 — 小明和小美
小明和小美爱跑步
- 小明体重75.0公斤
- 小美体重45.0公斤
- 小明每次跑步会减肥0.5公斤
- 小明每次吃东西体重会增加1公斤
class Person:
def __init__(self, name, weight):
# 在初始化方法中增加两个参数由外界传递
# self.属性 = 形参
self.name = name
self.weight = weight
def __str__(self):
return '我的名字叫 %s 体重是 %.2f' % (self.name, self.weight)
def run(self):
# pass
print '%s 爱跑步' % self.name
# 在对象方法的内部,是可以直接访问对象的属性
self.weight -= 0.5
def eat(self):
#pass
print '%s 吃东西' % self.name
self.weight += 1
xiaoming = Person('小明',75.5)
xiaoming.run()
xiaoming.eat()
print xiaoming
xiaomei = Person('小美',45.0)
xiaomei.eat()
xiaomei.run()
# 同一个类创建的多个对象之间,属性互补干扰
print xiaomei
print xiaoming
注:一个对象的属性可以是另外一个类创建的对象
2、实例 — 士兵突击
(1)需求
- 士兵 许三多 有一把 AK47
- 士兵 可以 开火
- 枪 能够 发射 子弹
- 枪 装填 装填子弹 —— 增加子弹数量
(2)开发枪类
方法需求
- 1> 判断是否有子弹,没有子弹无法射击
- 2> 使用 print 提示射击,并且输出子弹数量
class Gun:
def __init__(self, model):
# 枪的型号
self.model = model
# 子弹数量
self.bullet_count = 0
def add_bullet(self, count):
self.bullet_count += count
def shoot(self):
# 判断是否还有子弹
if self.bullet_count <= 0:
print("没有子弹了...")
return
# 发射一颗子弹
self.bullet_count -= 1
print("%s 发射子弹[%d]..." % (self.model, self.bullet_count))
(3)创建枪对象
ak47 = Gun("ak47")
ak47.add_bullet(50)
ak47.shoot()
(4)开发士兵类
假设:每一个新兵 都 没有枪
定义没有初始值的属性
在定义属性时,如果 不知道设置什么初始值,可以设置为 None
- None 关键字 表示 什么都没有
- 表示一个 空对象,没有方法和属性,是一个特殊的常量
- 可以将 None 赋值给任何一个变量
方法需求
- 1> 判断是否有枪,没有枪没法冲锋
- 2> 喊一声口号
- 3> 装填子弹
- 4> 射击
class Soldier:
def __init__(self, name):
# 姓名
self.name = name
# 枪,士兵初始没有枪 None 关键字表示什么都没有
self.gun = None
def fire(self):
# 1. 判断士兵是否有枪
if self.gun is None:
print("[%s] 还没有枪..." % self.name)
return
# 2. 高喊口号
print("冲啊...[%s]" % self.name)
# 3. 让枪装填子弹
self.gun.add_bullet(50)
# 4. 让枪发射子弹
self.gun.shoot()
小结
- 创建了一个 士兵类,使用到
__init__
内置方法 - 在定义属性时,如果 不知道设置什么初始值,可以设置为 None
- 在 封装的方法 内部,还可以让 自己的 使用其他类创建的对象属性 调用已经封装好的方法
3、私有属性和私有方法
(1)应用场景及定义方式
应用场景
在实际开发中,对象 的 某些属性或方法 可能只希望 在对象的内部被使用,而 不希望在外部被访问到
- 私有属性 就是 对象 不希望公开的 属性
- 私有方法 就是 对象 不希望公开的 方法
定义方式
在 定义属性或方法 时,在 属性名或者方法名前 增加 两个下划线,定义的就是 私有 属性或方法
class Women:
def __init__(self, name):
self.name = name
# 不要问女生的年龄
self.__age = 18
def __secret(self):
print("我的年龄是 %d" % self.__age)
xiaofang = Women("小芳")
# 私有属性,外部不能直接访问
# print(xiaofang.__age)
# 私有方法,外部不能直接调用
# xiaofang.__secret()
(2)伪私有属性和私有方法(科普)
提示:在日常开发中,不要使用这种方式,访问对象的 私有属性 或 私有方法
Python 中,并没有 真正意义的私有
在给属性、方法 命名时,实际是对 名称 做了一些特殊处理,使得外界无法访问到
处理方式:在名称前面加上 _类名 => _类名__名称
# 私有属性,外部不能直接访问到
print(xiaofang._Women__age)
# 私有方法,外部不能直接调用
xiaofang._Women__secret()
二、 继承
继承:实现代码的重用,相同的代码不需要重复的写
- 已有的类,我们称为"父类或基类"
- 新的类,我们称为“子类或派生类”
object类里面定义了一些所有类共有的默认实现,比如__init()__,new()。
1、单继承
继承的概念:子类拥有父类的所有属性和方法(子类只需要封装自己特有的方法)。
语法
class 类名(父类):
def 子类特有的方法
注:如果在类定义中没有指定父类,则默认父类是object类,也就是说object类是所有类的父类,因此所有类都有object类的属性和方法,
示例:
class Student: #定义父类
def study(self):
print '学生要学习'
def practice(self):
print '学完要练习'
def play(self):
print '练习完要玩耍'
def sleep(self):
print '玩耍后睡觉觉'
class homie(Student):
# 子类拥有父类的所有属性和方法
def call(self):
print '开黑'
Bob = homie()
Bob.study()
Bob.practice()
Bob.play()
Bob.sleep()
Bob.call()
# 子类继承自父类,可以直接享受父类中已经封装好的方法
2、继承的传递性
class Student:
def study(self):
print '学生要学习'
def practice(self):
print '学完要练习'
def play(self):
print '练习完要玩耍'
def sleep(self):
print '玩耍后睡觉觉'
class homie(Student):
# 子类拥有父类的所有属性和方法
def call(self):
print '开黑'
class homie1(homie): # 继承的传递性 子类拥有父类的父类的属性和方法
def LOL(self):
print '三人开黑'
james =homie1()
james.study()
james.practice()
james.play()
james.sleep()
james.call()
james.LOL()
3、重写父类和扩展
覆盖父类的方法(重写父类方法)
如果子类中,重写了父类的方法
在运行中,只会调用在子类中重写的方法而不会调用父类的方法
class Student:
def study(self):
print '学生要学习'
def practice(self):
print '学完要练习'
def play(self):
print '练习完要玩耍'
def sleep(self):
print '玩耍后睡觉觉'
class Homie(Student):
# 子类拥有父类的所有属性和方法
def call(self):
print '开黑'
class Homie1(Homie):
def LOL(self):
print '三人开黑'
def call(self):
# 1.针对子类特有的需求,编写代码
print '我的homie一起在一起'
# 2.调用原本父类中封装的方法
Homie.call(self) #重写之后并没有改变父类的方法
# 3.增加其他子类代码
print '我们需要五黑' #对父类方法进行扩展
james =Homie1()
james.call()
james.LOL()
4、多继承
子类拥有一个父类叫作单继承
子类可以拥有多个父类,并且具有所有父类的属性和方法
例如:孩子会继承自己父亲和母亲的特征
class A:
def test(self):
print 'A----------test方法'
def demo(self):
print 'A----demo 方法'
class B:
def test(self):
print 'B----------test方法'
def demo(self):
print 'B----demo 方法'
class C(B,A): #谁在前面调用谁,当然也可以指定调用父类的方法
"""多继承可以让子类对象,同时具有多个父类的属性和方法"""
pass
# 创建子类对象
c = C()
c.test()
c.demo()
5、扩展
- 通过类的方法mro()或者类的属性_mro_可以输出这个类的继承层次结构。
- 通过类的方法dir()查看对象属性
(1)mro()
Python支持多继承,如果父类中有相同名字的方法,在子类没有指定父类名时,解释器将“从左向右”按顺序搜索。
MRO(Method Resolution Order):方法解析顺序,我们可以通过mro()方法获得“类的层次结构”,方法解析顺序也是按照这个“类的层次结构”寻找到。
class A:
def aa(self):
print("aa")
def say(self):
print("say AAA!")
class B:
def bb(self):
print("bb")
def say(self):
print("say BBB!")
class C(A,B):
def cc(self):
print("cc")
c=C()
print(C.mro())
c.say() #解释器寻找方法是"从左到右的顺序"寻找,此时会执行A类中的say()
#打印结果
[<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>]
say AAA!
(2)super()获得父类定义
在子类中,如果想要获得父类的方法时,我们可以通过super()来做,super()代表父类的定义,而不是父类对象。
#测试super()代表和父类有关,而不是父类对象!
class A:
def say(self):
print("A:",self)
class B(A):
def say(self):
# A.say(self) 也可调用
super().say() #()中没有传self说明调用的是类方法,()中传self说明调用的是类的实例化方法
print("B:",self)
B().say()
(3)重写__str__方法:
用于返回一个对于“对象的描述”,对应于内置函数str()经常用于print()方法,帮助我们查看对象的信息。str()可以重写。
class Person():
def __init__(self,name):
self.name=name
p=Person("张三丰")
print(p)
#打印结果如下: object类中__str__()的默认实现,打印类的信息
<__main__.Person object at 0x03110D30>
str()重写后
class Person():
def __init__(self,name):
self.name=name
def __str__(self):
return "名字是:{}".format(self.name)
p=Person("张三丰")
print(p)
#打印结果如下:
名字是:张三丰
三、多态
多态(以封装和继承为前提) 面向对象的三大特征:
- 封装:根据职责将属性和方法封装到一个抽象的类中
- 继承:实现代码的重用,相同的代码不需要重复的编写 子类 针对自己特有的需求,编写特定的代码
- 多态:不同的子类对象调用相同的方法,产生不同的执行结果
多态(polymorphism)是指同一个方法调用,由于对象不同可能会产生不同的行为。
- 1.多态可以增加代码的灵活度
- 2.以继承和重写父类的方法为前提
- 3.调用方法,不会影响到类的内部设计
class Dog(object):
def __init__(self,name):
self.name=name
def game(self):
print '%s喜欢耍'%self.name
class Goddog(Dog):
def game(self):
print '%s喜欢hotdog'%self.name
# Dog.game(self)
class Person(object):
def __init__(self,name):
self.name=name
def game_with_dog(self,dog):
print '%s和%s一起耍'%(self.name,dog.name)
Hotdog=Goddog('Hotdog')
zhangzhenyue=Person('张震岳')
zhangzhenyue.game_with_dog(Hotdog)
四、身份运算符
身份运算符用于 比较 两个对象 的 内存地址 是否一致 —— 是否是对同一个对象的引用
在 Python 中针对 None 比较时,建议使用 is 判断
- is 是判断两个标识符是不是引用同一个对象 x is y,类似 id(x) == id(y)
- is not 是判断两个标识符是不是引用不同对象 x is not y,类似 id(a) != id(b)
- is 与 == 区别:
- is 用于判断两个变量 引用对象是否为同一个
- == 用于判断 引用变量的值 是否相等
运算符 描述 实例
>>> a = [1, 2, 3]
>>> b = [1, 2, 3]
>>> b is a
False
>>> b == a
True