(十一)面向对象程序设计

1. 相关概念

面向对象(Object Oriented)程序设计是一类很重要的思想。要创建一个对象(Object),就需要基于类(class)来完成。类是一批具有相同的属性的对象的抽象,是一种抽象概念。对象是一个具体存在的实体,基于类来创建对象的过程就是类的实例化。

2. 定义类

经典方法(旧式方法)

  1. class ClassName:
  2. pass
  3. class ClassName():
  4. pass

新式方法

  1. class ClassName(object):
  2. pass

3. 创建对象

2.1 类对象和实例对象

类对象

  1. class ClassName:
  2. pass

实例对象(基于类对象创建,属于类对象的对象)

  1. class ClassName:
  2. pass
  3. test = ClassName()

4. 类属性和实体属性

3.1 类属性

类中方法外的变量称为类属性,被该类的所有对象共享。

  1. native_var = 20

通过类对象创建的实例对象,都有指向类对象的 类指针,类属性改变则实例对象的属性也会变。

3.2 类属性的调用

  1. # 一
  2. ClassName.native_var
  3. # 二
  4. test = ClassName()
  5. test.native_var

3.2 实体属性

5. 方法

4.1 实例方法

直接定义在类里面的方法

  1. def test(self):
  2. pass

4.2 静态方法

使用 @staticmethod 修饰静态的方法,通过类名直接访问。

  1. @staticmethod
  2. def m():
  3. pass

4.3 类方法

使用 @classmethod 修饰类方法,使用类名直接访问和。

  1. @classmethod
  2. def cm(cls):
  3. pass

6. __init__() 方法初始化

self.name 是实例属性,进行了一个赋值操作,将局部变量 name 赋值给实体属性

  1. def __init__(self, a, b):
  2. self.a = a
  3. self.b = b
  4. self.c = 10

7. 调用方法

6.1 通过创建的实例调用

  1. test = ClassName()
  2. test.method()

6.2 通过传入实例对象调用

  1. ClassName.method(test)

8. 动态绑定属性和方法

7.1 动态绑定属性

直接使用 test.var = value 进行给实例对象 test 添加一个属性,动态绑定。

7.2 动态绑定方法

在类外定义函数,然后给实例对象动态添加这个函数,成为对象的方法。

  1. def show():
  2. pass
  3. test.show = show

9. 修改属性的值

4.1 直接修改属性的值

  1. ClassName.attribute = 'xxx'

4.2 通过方法修改

在对象内创建一个方法,然后在方法内修改。

  1. def f(self, name):
  2. self.name = name
  3. ClassName.f('xxx')

4.3 通过方法对属性的值进行递增

  1. def add(self, x):
  2. self.age += x
  3. add(2)

10. 面向对象三大特征

1)封装

  • 提高程序的安全性。

  • 将数据(属性)和行为(方法)包装到类对象中。在方法内部对属性进行操作,在类对象外的外部调用方法。这样,无需关心方法内部的具体实现细节,从而隔离了复杂度。

  • 在 Python 中没有专门的修饰符用于属性的私有,如果该属性不希望在类对象外部被访问,在属性前面加个 ___(双下划线)。

2)继承

  • 提高代码的复用性

  • 使用 super() 继承父类

    1. class A(object):
    2. def __init__(self, a):
    3. pass
    4. class B(A):
    5. def __init__(self, a, b):
    6. super()__init__(a)
    7. self.b = b
  • 多继承 ```python class A(object): def init(self, a)
    1. self.a =a
    class B(object): def init(self, b)
    1. self.b = b

class C(A, B): def init(self, a, b): A.init(self, a) B.init(self, b)

  1. -
  2. 方法重写
  3. <br />如果子类对继承自父类的某个属性或方法不满意,可以在字类中对其(方法体)进行重新编写
  4. <br />字类重写后的方法中可以通过 `super().xxx()` 调用父类中被重写的方法
  5. -
  6. Object
  7. -
  8. object类是所有类的父类,因此所有类都有object类的属性和方法。
  9. -
  10. 内置函数 `dir()` 可以查看指定对象所有属性
  11. -
  12. object类有一个 `__str__()` 方法,用于返回一个对于“对象的描述”,对于内置函数 `str()` 经常用于 `print()` 方法,帮助我们查看对象信息,所以我们经常会对 `__str__()` 进行重写
  13. ```python
  14. def __str__(self):
  15. pass

3)多态

  • 多态提高程序的可扩展性和可维护性

  • 简单的说,多态就是“具有多种形态”,它指的是:即便不知道一个变量所引用的对象到底是什么类型,仍然可以通过这个变量调用方法,在运行过程中根据变量所引用对象的类型,动态决定到底调用哪个对象中的方法。

  • 静态语言与动态语言的区别

    • 静态语言实现多态的三个必要条件

      • 继承
      • 方法重写
      • 父类引用指向子类对象
    • 动态语言的多态崇尚于“鸭子类型”。当看到一只鸟走起来像鸭子、游泳时像鸭子、收起来也像鸭子,那么这只鸟就可以被称为鸭子。在鸭子类型中,不需要关心对象是什么类型,到底是不是鸭子,只关心对象的行为。

11. 特殊方法和特殊属性

名称 描述
特殊属性 dict 获得类对象或实例对象所绑定的所有属性和方法的字典
特殊方法 __len__() 通过重写 __len__()方法,让内置函数 len()的参数可以是自定义的
__add__() 通过重写__add__()方法,可使用自定义对象具有 + 功能
__new__() 用于创建对象
__init__() 对创建的对象进行初始化

12. __new__()__init__() 创建对象的过程

pass

13.类的浅拷贝与深拷贝

  • 变量的赋值操作
    只是形成两个变量,实际上还是指向同一个对象

  • 浅拷贝
    Python拷贝一般都是浅拷贝,拷贝时,对象包含的子对象内容不拷贝,因此,源对象与拷贝对象会引用同一个子对象

  • 深拷贝
    使用 copy 模块的 deepcopy 函数,递归拷贝对象中包含的子对象,源对象和拷贝对象所有的子对象也不相同

14 . __del__ 方法

__del__ 方法会在对象被销毁前自动调用。

这可以联系对象的生命周期理解。

生命周期开始于对象被创建,一个对象的 __del__ 方法一旦被调用,生命周期结束。

在生命周期内,才能访问对象属性和方法。

15. __str__ 方法

  • 在python中,使用 print 输出对象变量,默认情况下,会输出这个变量引用的对象,是由哪一个类创建的对象,以及内存中的地址(十六进制)。
  • 如果在开发中,希望使用 print 输出对象变量 打印自定义 的内容,就可以利用 __str__ 这个内置方法了。
  • __str__ 方法必须返回一个字符串

16. 私有属性和私有方法

应用场景

  • 私有属性
    不希望公开的属性

  • 私有方法
    不希望公开的方法

定义方式

  • 在定义的属性或方法名前,加两个下划线 __ 就定义了私有属性或方法。

伪私有属性和私有方法

提示:在日常开发中,不要使用这种方式访问对象的私有属性或私有方法

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

  • 在给属性、方法命名时,实际上是给名称做了一些特殊处理,使得外界无法访问到。
  • 处理方式上,在名称前面加上 _类名 => _类名__名称