学习python第八天

1、面相对象基础语法

1.1  dir 内置函数(知道)

  • 在 Python 中 对象几乎是无所不在的,我们之前学习的 变量数据函数 都是对象

在 Python 中可以使用以下两个方法验证:

  1. 在 标识符 / 数据 后输入一个 .,然后按下 TAB 键,iPython 会提示该对象能够调用的 方法列表
  2. 使用内置函数 dir 传入 标识符 / 数据,可以查看对象内的 所有属性及方法

提示 __方法名__ 格式的方法是 Python 提供的 内置方法 / 属性,稍后会给大家介绍一些常用的 内置方法 / 属性

序号方法名类型作用
01 __new__ 方法 创建对象时,会被 自动 调用
02 __init__ 方法 对象被初始化时,会被 自动 调用
03 __del__ 方法 对象被从内存中销毁前,会被 自动 调用
04 __str__ 方法 返回对象的描述信息print 函数输出使用

提示 利用好 dir() 函数,在学习时很多内容就不需要死记硬背了

1.2  定义简单的类(只包含方法)

  • 定义只包含方法的类
  • 创建对象
class Person:
# 初始化方法 def __init__(self, name, weight): self.name = name self.weight = weight # 默认输出 def __str__(self): return "我的名字叫 %s 体重 %.2f 公斤" % (self.name, self.weight) def run(self): print("%s 爱跑步,跑步锻炼身体" % self.name) self.weight -= 0.5 def eat(self): print("%s 是吃货,吃完这顿再减肥" % self.name) self.weight += 1 xiaoming = Person("小明", 75) xiaoming.run() xiaoming.eat() xiaoming.eat() print(xiaoming)

引用概念的强调

  • 在 Python 中使用类 创建对象之后xiaoming 变量中 仍然记录的是 对象在内存中的地址
  • 也就是 xiaoming 变量 引用 了 新建的人类对象
  • 使用 print 输出 对象变量,默认情况下,是能够输出这个变量 引用的对象 是 由哪一个类创建的对象,以及 在内存中的地址十六进制表示
  • 重写了__str__(self)方法就不会默认输出

1.3  方法中的 self 参数

  • 由 哪一个对象 调用的方法,方法内的 self 就是 哪一个对象的引用
  • 在类封装的方法内部,self 就表示 当前调用方法的对象自己
  • 调用方法时,程序员不需要传递 self 参数
  • 在方法内部
    • 可以通过 self. 访问对象的属性
    • 也可以通过 self. 调用其他的对象方法
  • 在 类的外部,通过 变量名. 访问对象的 属性和方法
  • 在 类封装的方法中,通过 self. 访问对象的 属性和方法

1.4  初始化方法

  • 在日常开发中,不推荐在 类的外部 给对象增加属性
    • 如果在运行时,没有找到属性,程序会报错
  • 对象应该包含有哪些属性,应该 封装在类的内部
# 注意:这种方式虽然简单,但是不推荐使用!
xiaoming.address = "北京"

初始化方法

  • 当使用 类名() 创建对象时,会 自动 执行以下操作:
    1. 为对象在内存中 分配空间 —— 创建对象
    2. 为对象的属性 设置初始值 —— 初始化方法(init)
  • 这个 初始化方法 就是 __init__ 方法,__init__ 是对象的内置方法

__init__ 方法是 专门 用来定义一个类 具有哪些属性的方法

改造初始化方法 —— 初始化的同时设置初始值

  • 在开发中,如果希望在 创建对象的同时,就设置对象的属性,可以对 __init__ 方法进行 改造
    1. 把希望设置的属性值,定义成 __init__ 方法的参数
    2. 在方法内部使用 self.属性 = 形参 接收外部传递的参数
    3. 在创建对象时,使用 类名(属性1, 属性2...) 调用
class Cat:

    def __init__(self, name):
        print("初始化方法 %s" % name)
        self.name = name
    
tom = Cat("Tom")
lazy_cat = Cat("大懒猫")

1.5  内置方法和属性

序号方法名类型作用
01 __del__ 方法 对象被从内存中销毁前,会被 自动 调用
02 __str__ 方法 返回对象的描述信息print 函数输出使用

__del__ 方法(知道)

  • 在 Python 中

    • 当使用 类名() 创建对象时,为对象 分配完空间后,自动 调用 __init__ 方法
    • 当一个 对象被从内存中销毁 前,会 自动 调用 __del__ 方法
  • 应用场景

    • __init__ 改造初始化方法,可以让创建对象更加灵活
    • __del__ 如果希望在对象被销毁前,再做一些事情,可以考虑一下 __del__ 方法
  • 生命周期

    • 一个对象从调用 类名() 创建,生命周期开始
    • 一个对象的 __del__ 方法一旦被调用,生命周期结束
    • 在对象的生命周期内,可以访问对象属性,或者让对象调用方法
class Cat:

    def __init__(self, new_name):

        self.name = new_name

        print("%s 来了" % self.name)

    def __del__(self):

        print("%s 去了" % self.name)

# tom 是一个全局变量
tom = Cat("Tom")
print(tom.name)

# del 关键字可以删除一个对象
del tom

print("-" * 50)

__str__ 方法

  • 在 Python 中,使用 print 输出 对象变量,默认情况下,会输出这个变量 引用的对象 是 由哪一个类创建的对象,以及 在内存中的地址十六进制表示
  • 如果在开发中,希望使用 print 输出 对象变量 时,能够打印 自定义的内容,就可以利用 __str__ 这个内置方法了

注意:__str__ 方法必须返回一个字符串

class Cat:

    def __init__(self, new_name):

        self.name = new_name

        print("%s 来了" % self.name)

    def __del__(self):

        print("%s 去了" % self.name)

    def __str__(self):
        return "我是小猫:%s" % self.name

tom = Cat("Tom")
print(tom)

1.6  私有属性和私有方法

定义方式

  • 在 定义属性或方法时,在 属性名或者方法名前 增加 两个下划线,定义的就是 私有 属性或方法
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()

伪私有属性和私有方法(科普)

Python 中,并没有 真正意义 的 私有

  • 在给 属性方法 命名时,实际是对 名称 做了一些特殊处理,使得外界无法访问到
  • 处理方式:在 名称 前面加上 _类名 => _类名__名称(不要使用这种方式,访问对象的 私有属性 或 私有方法)
# 私有属性,外部不能直接访问到
print(xiaofang._Women__age)

# 私有方法,外部不能直接调用
xiaofang._Women__secret()

2、继承

面向对象三大特性

  1. 封装 根据 职责 将 属性 和 方法封装 到一个抽象的  中
  2. 继承实现代码的重用,相同的代码不需要重复的编写
  3. 多态 不同的对象调用相同的方法,产生不同的执行结果,增加代码的灵活度

2.1  单继承

 继承的语法

class 类名(父类名):
    pass
  • 子类 继承自 父类,可以直接 享受 父类中已经封装好的方法,不需要再次开发(不能继承父类的私有方法)
  • 子类 中应该根据 职责,封装 子类特有的属性和方法
  • 子类对象 不能 在自己的方法内部,直接 访问 父类的 私有属性 或 私有方法
  • 子类对象 可以通过 父类 的 公有方法间接 访问到 私有属性 或 私有方法

方法的重写

  重写 父类方法有两种情况:

  1. 覆盖 父类的方法(相当于在 子类中 定义了一个 和父类同名的方法并且实现
  2. 对父类方法进行 扩展(子类方法中,在需要的位置使用 super().父类方法 来调用父类方法的执行)

关于 super

  • 在 Python 中 super 是一个 特殊的类
  • super() 就是使用 super 类创建出来的对象
  • 最常 使用的场景就是在 重写父类方法时,调用 在父类中封装的方法实现
  • 调用父类方法的另外一种方式(不推荐使用

  • 父类名.方法(self)

 2.2  多继承(重点)

多继承的使用注意事项

  • 如果 不同的父类 中存在 同名的方法子类对象 在调用方法时,会调用 哪一个父类中的方法呢?

提示:开发时,应该尽量避免这种容易产生混淆的情况! —— 如果 父类之间 存在 同名的属性或者方法,应该 尽量避免 使用多继承

  解决方法:Python 中的 MRO —— 方法搜索顺序(知道)

  • Python 中针对  提供了一个 内置属性__mro__ 可以查看 方法 搜索顺序
  • MRO 是 method resolution order,主要用于 在多继承时判断 方法、属性 的调用 路径

新式类与旧式(经典)类

object 是 Python 为所有对象提供的 基类,提供有一些内置的属性和方法,可以使用 dir 函数查看。

  • 新式类:以 object 为基类的类,推荐使用

  • 经典类:不以 object 为基类的类,不推荐使用

  • 在 Python 3.x 中定义类时,如果没有指定父类,会 默认使用 object 作为该类的 基类 —— Python 3.x 中定义的类都是 新式类

  • 在 Python 2.x 中定义类时,如果没有指定父类,则不会以 object 作为 基类

新式类 和 经典类 在多继承时 —— 会影响到方法的搜索顺序(如果没有父类,建议统一继承自 object

 

posted @ 2018-10-28 21:05  人工智能之路上的菜鸡  阅读(204)  评论(0编辑  收藏  举报