Python面向对象

作者:

在

以步骤和过程为核心的编程范式,其核心思想是将复杂问题分解为一系列可顺序执行的函数或过程,通过逐步调用来实现整体功能

核心思想

  • 步骤分解:将问题拆解为多个子任务,每个子任务由独立的函数实现,例如,处理学生早上的活动可分解为“起床→穿衣→洗漱→去学校”等步骤,每个步骤对应一个函数
  • 顺序执行:程序按代码的书写顺序从上到下执行,通过条件语句(如if)和循环结构(如for)控制流程
  • 数据与操作分离:数据存储在全局或局部变量中,函数通过参数接收数据并处理,结果通过返回值或修改变量传递。

典型特征

  • 模块化函数:功能封装为函数,例如计算两数之和的函数 add(),通过调用实现代码复用。
  • 线性流程:程序逻辑清晰,易于调试。例如读取文件数据→处理数据→输出结果的流程。
  • 高效性:适用于简单任务或对性能要求高的场景,因无需对象创建开销。


面向对象(Object)

一种以对象为核心的编程范式,通过模拟现实世界中事物的交互逻辑来构建程序。其核心思想是将数据与操作数据的方法封装成独立的对象,通过对象之间的协作实现复杂功能

核心概念

  1. 类(Class):定义对象的模板,描述一类事物的共性特征(如属性)和行为(如方法)。例如,”汽车”类包含属性”颜色”和方法”加速”。
  2. 对象(Object):类的具体实例,拥有独立的状态(属性值)和行为。例如,一辆红色汽车是”汽车”类的对象
  3. 封装(Encapsulation):将数据和方法捆绑在对象内部,仅通过暴露的接口与外界交互,保护数据安全并简化使用。例如,银行账户的余额只能通过特定方法修改。
  4. 继承(Inheritance):子类可复用父类的属性和方法,并扩展新功能,实现代码复用和逻辑分层。例如,”电动车”类继承自”汽车”类,新增”充电”方法。
  5. 多态(Polymorphism):同一方法在不同对象中呈现不同行为,增强代码灵活性。例如,”动物”类的”发声”方法在”狗”和”猫”对象中分别输出”汪汪”和”喵喵”。
  6. 抽象(Abstraction):提取共性特征形成接口或抽象类,隐藏复杂实现细节,例如定义”图形”类的抽象方法”计算面积”。

核心优势

  • 可维护性:对象间低耦合,修改某部分代码不影响整体系统。- 可扩展性:通过继承和多态灵活扩展功能,无需重写现有代码。- 复用性:封装后的类可跨项目重复使用,减少冗余代码。- 逻辑直观:以现实世界模型组织代码,更符合人类认知。

两者对比

面向过程—怎么做

  1. 把完成某一个需求的 所有步骤 从头到尾 逐步实现
  2. 根据开发需求,将某些功能独立的代码封装成一个又一个函数
  3. 最后完成的代码,就是顺序地调用不同的函数

注重步骤与过程,不注重职责和分工,如果需求比较复杂,虽然有函数封装,但是还是会导致代码比较臃肿。开发起来比较复杂

面向对象—谁来做

相比较函数,面向对象是更大的封装,根据职责在一个对象中封装多个方法

  1. 在完成某一个需求前,首先确定职责 —— 要做的事情(方法)
  2. 根据职责确定不同的对象,在对象内部封装不同的方法(多个)
  3. 最后完成的代码,就是顺序地让不同的对象调用不同的方法

特点

  1. 注重对象和职责,不同的对象承担不同的职责
  2. 更加适合应对复杂的需求变化,是专门应对复杂项目开发,提供的固定套路
  3. 需要在面向过程基础上,再学习一些面向对象的语法

类的规范和实例化讲解


==注意==:1.class定义类

​ 2.实例化对象的时候,会自动调用 __init__ 来初始化,我们可以在 __init__ 中定义对象初始化的属性

​ 3.self 在实例化对象时自动=实例p1,所以可以用self.属性或方法

​ 4.__dir__查看对象内所有属性以及方法

类与对象

在面向对象中,类与对象是两个核心的概念

类

  • 类是对一群具有相同特征或者行为的事物的一个统称,是抽象的,不能直接使用
    • 特征 被称为 属性
    • 行为 被称为 方法
  • 类就相当于制造飞机时的图纸,是一个模板,是负责创建对象的

对象

  • 对象是由类创建出来的一个具体存在,可以直接使用。
  • 由哪一个类创建出来的对象,就拥有在哪一个类中定义的:属性 & 方法。
  • 对象就相当于用图纸制造的飞机。

类的设计

在使用面相对象开发前,应该首先分析需求,确定一下,程序中需要包含哪些类

在程序开发中,要设计一个类,通常需要满足一下三个要素:

  1. 类名 这类事物的名字,满足大驼峰命名法
  2. 属性 这类事物具有什么样的特征
  3. 方法 这类事物具有什么样的行为

大驼峰命名法

CapWords

类名的确定

通常类名的选择,我们应该根据整个业务流程来提取,或者从大的角度来选择

属性和方法的确定

  • 对对象的特征描述,通常可以定义成属性
  • 对象具有的行为,通常可以定义成方法

类的定义

类的基本定于语法如下:

class Human:
    '''
    这里可以写上对于这个类的说明
    '''
    变量 = xxxx    # 这里是类的静态属性,也可以理解为该类共有的特性
    dic = {}
    l1 = []
    def __init__(self,xxx,xxx):        # 初始化方法
        pass

    def func(self):                    # 方法,动态属性
        pass

类的三大特性:封装,继承和多态

封装:将属性,方法封装到类内

将数据和方法捆绑在对象内部,仅通过暴露的接口与外界交互,保护数据安全并简化使用

==注意==:最好不要给类动态增加属性,不然破坏封装性原则,可以通过继承更改

私有和公有:访问控制

==注意==:约定self.__属性=属性为私有属性,def __方法(self,xxx,xxx)为私有方法,本质都可访问,java不同,私有不可外部访问

访问:实例名._Student__属性,python语法规范就是这样

类属性和实例属性

类型 属于 定义位置 内存 访问方式
类属性 类本身 类体内,方法外 只存一份,所有实例共享 类名.属性或实例.属性
实例属性 某个具体实例 通常在__init__内用self.xxx定义 每个实例各存一份 实例.属性
class Dog:
    species = "Canis familiaris"   # 类属性:所有狗共享的物种名

    def __init__(self, name):
        self.name = name           # 实例属性:每只狗有自己的名字

dog1 = Dog("Buddy")
dog2 = Dog("Lucy")

print(Dog.species)      # Canis familiaris  通过类访问
print(dog1.species)     # Canis familiaris  实例也能读(向上查找)
print(dog2.species)     # Canis familiaris

Dog.species = "犬科"      # 修改类属性
print(dog1.species)     # 犬科(受影响,因为共享)

dog1.name = "Max"        # 修改实例属性
print(dog2.name)         # Lucy (互不影响)


@staticmethod静态方法装饰器

不需要传入self,本质就是个普通函数,只是放在类的命名空间里,调用直接用类.方法

本质:为了定义类方法,类.方法读取

计数器计算多少个实例对象

class Dog:
    count = 0  # 类属性:计数器

    def __init__(self, name):
        Dog.count += 1    # 每次实例化,类属性加1
        self.name = name  # 实例属性class Dog:
    count = 0  # 类属性:计数器

    def __init__(self, name):
        Dog.count += 1    # 每次实例化,类属性加1
        self.name = name  # 实例属性

a = Dog("Buddy")
print(Dog.count)  # 1
b = Dog("Lucy")
print(Dog.count)  # 2         

==注意==:类属性类似于模块的全局变量,修改后全局共享,但是被命名空间限制在类里,所以由实例共享,创建一个改为1,创建第二个自动在修改后的1,后面加1变为2

继承:复用父类的属性,方法,和增加新属性,方法

子类可复用父类的属性和方法,并扩展新功能,实现代码复用和逻辑分层

单继承(yes),多继承(pass)

单继承:只继承自一个父类

![](Python面向对象.assets/方法重写和super()调用父类.jpeg)

==注意==:子类方法重写:默认覆盖父类方法,要在新方法中调用super( )父类属性或方法,再增加新功能,super只会找上一级父类,上一级也可能继承自别的,也有super(),所以不要搞的继承很多,很复杂

多态:实例方法的角度

同一方法在不同对象中呈现不同行为,增强代码灵活性

==注意==:不管实例化对象是什么,都继承了基类的基础属性和方法,直接定义一个函数,函数体内调用具体方法

本质:调用函数把实例对象作为参数传进去,即实例对象().具体方法

鸭子类型

  1. 如果像鸭子一样叫,就当成鸭子
  2. ==Python不强制继承关系,只要对象有对应方法就可以==

鸭子类型的本质:它是一种”不通过继承,而通过方法兼容性”来实现多态,关注对象能做什么,而不是它是什么,偶然的行为兼容

java vs python

  1. Python:本身就符合语法规则,天生的真’鸭子类型’
  2. Java:必须制要求显式的继承或接口关系,为了通过编译器类型检查,如果不建立显式接口关系,直接用多态的方法调用会报错,静态类型系统为了安全性和可维护性的设计选择,所以==设计鸭子类型来进行java和别的静态类型语言的多态开发==

反射:以字符串形式直接到类方法调用

在运行时,根据字符串动态的操作对象

==注意==:核心思路是由字符串直接到类方法执行,原本是创建实例调用,现在直接操作,hasattr和getattr是判读实例对象里有这个方法或属性,getattr是得到这个方法或属性

Python测试框架原理

  • globals( )打印结果
{ '_name_': '_main_', '_doc_': None, '_package_': None, '_loader_': <frozen_importlib_external.SourceFileLoader object at 0x0000023358750680>,
 '_MathTwoNumber_': '_run_all_tests_': <function run_all_tests at 0x0000023358750680>}None, '__loader__': <frozen_importlib_external.SourceFileLoader object at 0x0000023358781C10>, '_spec__': None, '_annotated_namespace': None, '_file__': 'C:UsersLiDesktopprojectdeepseekaitext.py', '_cached__': None, 'MathTwoNumber': <Class '__main__.MathTwoNumber >,'run_all_tests': <function run_all_tests at 0x0000023358750680> }

globals()以字典形式把 内置名称,当前模块的模块信息,自定义的全局变量、函数、类,导入的模块

  • dir(instance)运行结果是:实例对象的所有方法名
(venv) PS C:UsersliDesktopprojectdeepseekai> python .text.py
add方法通过测试
mul方法通过测试
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'a', 'add', 'b', 'mul', 'test_add', 'test_mul']
  • globals()[test_class_names]运行结果:在globals( ) 字典里取相应的类

MRO算法

多继承中,子类调用一个属性或顺序时,Python按照什么顺序在继承链中搜索

口诀:子类在前,父类在后 ; 多父类时,左父先于右父;最后运行共同父类,只运行一次

class A: pass
class B(A): pass
class C(A): pass
class D(B, C): pass

object
  |
  A
 / 
B   C
  /
  D


MRO(D) →  [ D ,  B ,  C ,  A ,  object ]

顺序方向:从左到右查找

本质:你写的代码经过MRO算法会优化搜索顺序