面向对象

面向过程和面向对象介绍

面向过程编程

核心思想:以过程为中心,关注解决问题的步骤
实现方式:将步骤写成函数或方法,按顺序调用
适用场景:适合简单任务,注重程序流程和步骤
特点
直接性:代码流程直观明了
局限性:随着程序复杂度增加,代码会变得冗长混乱
通用性:步骤描述缺乏角色信息,复用性差

面向对象编程

核心思想:以对象为中心,关注参与问题的角色及其交互
关键要素
对象:参与事件的任何实体(人、物、抽象概念)
属性:对象的特征信息(如姓名、年龄、规格等)
方法:对象的行为能力(操作、功能)
优势
描述完整性:能全面刻画参与对象的特征和行为
扩展性:更适应复杂系统的开发需求
复用性:通过类和对象实现代码复用

面向对象历史

起源时间: 1960年代由Simula67语言首次引入对象概念
设计目的: 最初用于模拟船只间的属性相互影响
核心贡献:
最早提出"类"和"实例"的概念
将真实世界对象映射为抽象对象(称为"模拟")
开创了分析式程序设计范式

类和对象概念

本质: 一类事物的抽象模板
特点:
描述共同特征(属性)和行为(方法)
是广泛概念(如人类、电脑类)
不能对应具体实例
示例:
人类包含所有人
电脑类包含所有电脑型号

对象

本质: 类的具体实例
特点:
真实存在的实体
具有确定的属性和行为
可对应具体事物
关系:
类是对象的抽象
对象是类的具体化
示例:
具体人物(如"蔡徐坤")
具体电脑(如"MacBook Pro 2023")

属性和方法

描述维度:
属性:描述"是什么"(特征)
方法:描述"能做什么"(行为)
应用原则:
任何对象都可通过属性和方法完整描述
属性越多描述越具体
方法定义对象的功能

属性

定义: 类共同拥有的特征
代码表现: 类中定义的变量
示例:
人类:姓名、年龄、性别
电脑:品牌、CPU、内存
水杯:颜色、容量、材质

方法

定义: 类共同拥有的行为
代码表现: 类中定义的函数
特点:
方法即函数,面向对象中特称"方法"
不同类可有同名但实现不同的方法
示例:
人类:吃饭、睡觉
电脑:编程、游戏
水杯:盛水、保温

编写类和创建对象

类的基本概念与命名规范

特征属性: 姓名、年龄、性别、身高、体重、爱好、地址、学历等
行为方法: 吃饭、睡觉、做运动、学习等基本生活行为
命名规范:
使用关键字class开头
类名采用大写驼峰命名法(如Person)
与变量/函数的小写蛇形命名法区分(如person_name)
注意:Python内置类可能存在历史遗留的小写命名,但新代码应遵循规范

魔法函数__init__与self参数

魔法函数:
固定命名为__init__,不可更改
全称initialize(初始化)
用于定义类的初始化行为
self参数:
必须作为第一个参数显式声明
用于访问实例属性和方法
通过self.属性名定义实例属性(如self.name)
属性定义位置:
实际在__init__函数体内通过self.方式定义
形参仅用于接收外部传入值
示例:self.name = name将形参name赋值给实例属性name

对象的创建

基本语法: 对象名 = 类名()
创建位置: 在类定义外部进行
变量接收: 通常用变量接收创建的对象(如p1 = Person())
抽象与具体:
类是抽象模板(如"人类")
对象是具体实例(如"名叫张三的人")

"""
使用关键字class开头
类名采用大写驼峰命名法(如Person)
与变量/函数的小写蛇形命名法区分(如person_name)
"""


class Person:
    def __init__(self, name, age, gender, height, weight):
        print("创建了一个人")
        self.name = name
        self.age = age
        self.gender = gender
        self.height = height
        self.weight = weight

    def eat(self):
        print(f"{self.name}在吃饭")

    def sleep(self):
        print(f"{self.name}在睡觉")

    def sport(self):
        print(f"{self.name}在运动")


p1 = Person("张三", 18, "male", 70, 180)

print(p1)  # <__main__.Person object at 0x104286900>
print(p1.name)  # 张三
print(p1.age)  # 18
print(p1.gender)  # male
print(p1.height)  # 70
print(p1.weight)  # 180
p1.eat()  # 张三在吃饭
p1.sleep()  # 张三在睡觉
p1.sport()  # 张三在运动

创建对象的过程

当我们创建一个对象:

  • 第一步:Python解释器自动调用__new__函数创建空对象
  • 第二步:将空对象传递给__init__函数赋值给self
    • 表示当前对象(类似js中的this)
    • 接收空对象并准备进行属性赋值
  • 第三步:继续调用__init__函数,结合传入的实参给各个属性赋值
  • 第四步:将堆中的地址值赋值给左侧的变量

关键记忆点
先创建空对象()
再初始化属性()
最后绑定变量名

Python万物皆对象思想

设计核心:所有事物都被视为对象,包括:
模块本身是对象(存储全局变量和类定义)
类是对象(拥有__dict__存储方法和类属性)
函数是对象(如__new__和__init__都有独立内存地址)
基本数据类型也是对象(字符串、数字等)
内存管理特点:
小整数池缓存-5到256的整数对象
相同字符串会重用内存(如多处使用的"earth"指向同一地址)
每个对象都有唯一的十六进制内存地址标识

类变量和实例变量

类变量

定义:直接书写在类中,属于当前类,不属于任何对象,可以被此类的所有对象共享。
访问方式:
推荐:通过类名加点访问(如:Person.home)
不推荐但可行:通过对象名加点访问(如:p1.home),Python允许但会警告
特性:
在类创建时就存在,不需要实例化对象
修改类变量会影响所有实例的访问结果

常见错误:
尝试通过类名访问实例变量会报错(如:Person.name)
原因:实例变量需要对象创建后通过__init__初始化才存在

实例变量

定义:在__init__函数中定义的变量,属于实例级别(对象级别)
访问方式:必须通过实例访问(如:p1.name)
术语说明:
实例(instance) = 对象(object)
创建对象 = 实例化
创建过程:
Python调用__new__创建空对象
将空对象传给__init__并赋值给self
执行__init__给各属性赋值
将堆地址赋值给左侧变量

注意事项:
实例变量与同名类变量互不影响
若实例中未定义变量,会向上查找类变量
最佳实践:保持类变量和实例变量命名区分

类变量和实例变量的对比

存储位置:
类变量:类命名空间
实例变量:实例命名空间
生命周期:
类变量:随类存在
实例变量:随对象存在
共享性:
类变量:所有实例共享
实例变量:实例独享
修改影响:
修改类变量会影响所有实例
修改实例变量只影响当前对象
设计思想:
类变量用于描述类级别特征(如Person.home = “earth”)
实例变量用于描述对象个性特征(如name, age)

class Person:
    # 类变量
    home = "earth"

    def __init__(self, name, age, gender):
        # 实例变量
        self.name = name
        self.age = age
        self.gender = gender


p1 = Person("张三", 18, "male")  # 创建一个实例对象
print(p1.home)  # earth 通过实例名访问类属性,不推荐这样使用
print(Person.home)  # earth 这样访问推荐

# 添加类变量
Person.drink = "water"
print(Person.drink)  # water
# 修改变量
Person.home = "mars"
print(Person.home)  # mars


# 实例变量
print(p1.name)  # 张三
# print(
#     Person.name
# )  # 类访问实例变量报错AttributeError: type object 'Person' has no attribute 'name'

类方法 实例方法 静态方法

类方法:直接书写在类中,属于当前类,不属于任何对象,可以被此类的所有对象共享。
实例方法:在__init__函数中定义的变量,属于实例级别(对象级别)
静态方法:不访问实例属性或类属性,只依赖于传入的参数

方法类型 特征 调用方式
实例方法 第一个参数必须为 self,表示当前实例对象 通过实例(对象)调用
类方法 第一个参数为 cls,表示类对象 通过类名加点方法调用
静态方法 必须使用装饰器 @staticmethod 修饰 通过类名加点访问
class Person:
    def __init__(self, name, age, gender):
        self.name = name
        self.age = age
        self.gender = gender

    # 实例方法
    def sport(self):
        print(f"我是{self.name},我今天跑步")  # 我是张三,我今天跑步

    # 类方法
    @classmethod
    def eat(cls):
        print("是人都会吃饭", cls)  # 是人都会吃饭 <class '__main__.Person'>
        pass

    # 静态方法
    @staticmethod
    def static(str):
        print(f"我是{str}方法")  # 我是静态方法

p1 = Person("张三", 18, "male")
p1.sport()
Person.eat()
Person.static("静态")

魔法函数(特殊方法)

方法名中有两个前缀下划线和两个后缀下划线的方法为特殊方法,也叫魔法方法。上文提到的 init() 就是一个特殊方法。这些方法会在进行特定的操作时自动被调用。
几个常见的特殊方法:

new()

对象实例化时第一个调用的方法。

init()

类的初始化方法。

del()

对象的销毁器,定义了当对象被垃圾回收时的行为。使用 del xxx 时不会主动调用 del() ,除非此时引用计数==0。

    class Student:

    def __del__(self):
        print(f"当前对象被垃圾回收了,id为{id(self)}")


    s1 = Student("Jason")

    del s1
    print("程序结束")
str()

定义了对类的实例调用 str() 时的行为。

repr()

定义对类的实例调用 repr() 时的行为。 str() 和 repr() 最主要的差别在于目标用户。 repr() 的作用是产生机器可读的输出(大部分情况下,其输出可以作为有效的Python代码),而 str() 则产生人类可读的输出。

getattribute()

属性访问拦截器,定义了属性被访问前的操作。

"""
__str__属于打印对象默认将调用的特殊函数
打印一个对象默认调用这个函数 使使用父类实现 返回类型以及id值
可以重写这个函数 覆盖父类的实现
实际工作中返回房钱类名以及属性名属性值
"""


class Student:
    def __init__(self, name):
        self.name = name

    def __str__(self):

        return f"Student[name:{self.name}]"

    def __repr__(self):
        """
        repr函数主要用于在调试中使用
        """
        return f"Student[name:{repr(self.name)}]"

    def __getattribute__(self, item):
        print(f"{item}属性被访问")
        return super().__getattribute__(
            item
        )  # 必须调用父类的方法 否则报错 会出现无穷递归


s1 = Student("Jason")

print(s1)  # Student[name:Jason]
print(s1.__repr__())  # Student[name:'Jason']
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐