文章目录

  • 一、封装
  • 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

python的面向对象 python中面向对象的三大特征_深度学习

注:一个对象的属性可以是另外一个类创建的对象

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)应用场景及定义方式

应用场景

在实际开发中,对象 的 某些属性或方法 可能只希望 在对象的内部被使用,而 不希望在外部被访问到

  • 私有属性 就是 对象 不希望公开的 属性
  • 私有方法 就是 对象 不希望公开的 方法

定义方式

定义属性或方法 时,在 属性名或者方法名前 增加 两个下划线,定义的就是 私有 属性或方法

python的面向对象 python中面向对象的三大特征_深度学习_02

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