Python面向对象

发布于:2025-09-01 ⋅ 阅读:(27) ⋅ 点赞:(0)

目录

1. 面向对象与面向过程的对比

1.1 面向对象和面向过程

1.2 面向对象的优势

2. 面向对象的基本概念

2.1 对象(Object)和 类(Class)

2.2 类的定义(具有相同或相似属性(数据)和动作(方法)的一组实体集合)

2.3 类的实例化(创建对象)

2.4 类中的self关键字

2.5 构造方法 __init__ 和析构方法 __del__

3. 属性和方法

3.1 实例属性 and 类属性

3.2 属性的访问与修改

3.3 方法分类

3.3.1 实例方法

3.3.2 类方法

3.3.3 静态方法

4. 面向对象的三大特性

4.1 封装(Encapsulation)

4.2 继承(Inheritance)

4.2.1 继承的定义和作用

4.2.2 继承的类型

4.3 多态(Polymorphism)


1. 面向对象与面向过程的对比

面向过程:以过程(函数和对象)为中心,关注任务的实现步骤和流程,代码按照功能分成多个函数,数据和函数分开处理。通过调用函数按顺序完成任务。

面向对象:以对象为中心,关注数据和操作数据的方法,数据和操作数据的方法封装在类和对象中,通过类和继承实现代码复用和扩展。

方面

面向过程

面向对象

核心思想

以过程(函数)为中心

以对象(数据+方法)为中心

代码结构

函数和数据分离

数据和方法封装在类和对象中

复用方式

通过函数调用复用

通过封装、继承、多态复用

维护性

逻辑复杂时维护困难

封装提高维护性和扩展性

数据安全

数据易被外部访问

封装保护数据,隐藏内部实现

适用场景

简单任务、脚本

复杂系统、大型项目

1.1 面向对象和面向过程

面向过程(过程式编程):强调一步步执行逻辑,把程序看作是函数和数据的组合。

举例:

# 过程式写法:计算矩形面积
def area(length, width):
    return length * width

print(area(5, 3))  # 输出 15

面向对象编程: 强调把现实事物抽象为“对象”,对象包含属性和方法。

举例:

# 面向对象写法:矩形对象
class Rectangle:
    def __init__(self, length, width):
        self.length = length
        self.width = width

    def area(self):
        return self.length * self.width

rect = Rectangle(5, 3)
print(rect.area())  # 输出 15
1.2 面向对象的优势
  • 代码复用:通过继承和组合,避免重复造轮子。
  • 易维护:对象之间相对独立,修改某一部分不会影响整体。
  • 贴近现实:用“类”和“对象”来模拟真实世界,更符合人的思维方式。

2. 面向对象的基本概念

2.1 对象(Object)和 类(Class)
  • 类(Class):蓝图或模板。
  • 对象(Object):类的实例,具体存在。
2.2 类的定义(具有相同或相似属性(数据)和动作(方法)的一组实体集合)

使用class关键字来定义类,后面跟着的括号表示继承的类,默认继承object类,默认情况下也可以不写。类的名字推荐使用大驼峰法命名以区别函数。

class Person(object):
    pass

"""
或者这样定义也是可以的
class Person:
    pass
"""
2.3 类的实例化(创建对象)

使用类型名后面跟括号的方式实例化对象(与函数的类似),创建的对象实际是该对象在内存中的引用地址。

对象变量 = 类名()

p = Person()
print(p) #输出的为p的地址

类每次实例化的对象都是一个新对象,他们的地址都不同,可以使用id(),或print()查看

class Person(object):
    pass

for i in range(3):
    p=Person()
    print(p)
    
"""
输出:
<__main__.Person object at 0x0000018F15FDB590>
<__main__.Person object at 0x0000018F15FDB650>
<__main__.Person object at 0x0000018F15FDB510>
"""
2.4 类中的self关键字
  • self 代表实例本身。
  • 实例方法的第一个参数必须是 self(Python 自动传入)。
class Person:
    def __init__(self, name, age):
        self.name = name  # 给实例绑定属性 name
        self.age = age    # 给实例绑定属性 age

    def introduce(self):
        # 通过 self 访问实例属性
        print(f"大家好,我叫{self.name},今年{self.age}岁。")

# 创建实例
p = Person("小明", 20)
p.introduce()  # 调用方法时,Python 自动把 p 传给 self
2.5 构造方法 __init__ 和析构方法 __del__

构造方法 __init__ 是 Python 中类的一个特殊方法,用于在创建对象时初始化对象的属性。它会在实例被创建后自动调用,通常用来给对象设置初始状态。

  • __init__ 只在对象创建时调用一次,之后该对象存在期间不会再自动调用 __init__
  • 访问对象的属性也不会重新执行初始化逻辑。

析构方法 __del__ 也是一个特殊方法,当对象即将被销毁时(比如没有引用指向该对象时),Python 会调用它。通常用于资源释放或清理工作,但在 Python 中不建议过多依赖 __del__,因为垃圾回收的时机不确定。


3. 属性和方法

属性:存储对象的状态或特征(存数据)

方法:定义对象的行为或功能(功能)

3.1 实例属性 and 类属性

1、实例属性(Instance Attributes)

  • 属于每个对象(实例)自己的属性。
  • 在对象创建后,可以通过 self 绑定到实例上。
  • 不同实例的实例属性互相独立,修改一个实例的属性不会影响其他实例。
  • 通常在 __init__ 方法中定义。
  • 实例属性总结:属于对象本身,互不影响,用于存储对象的独有数据。

代码示例:

class Books:
    def __init__(self, book_name):
        self.book_name = book_name  # 实例属性
b1 = Books("Python入门")
b2 = Books("数据结构")

print(b1.book_name)  # 输出:Python入门
print(b2.book_name)  # 输出:数据结构

说明:

  • b1b2 是两个不同的实例,它们各自拥有独立的 book_name
  • 修改一个实例的属性不会影响另一个实例。

2、类属性(Class Attributes)

  • 属于类本身的属性,由所有实例共享。
  • 直接定义在类体内,不在任何方法中。
  • 所有实例访问的都是同一个类属性,修改类属性会影响所有实例(除非实例有同名的实例属性覆盖它)。
  • 类属性总结:属于类,所有实例共享,用于存储类的公共信息。每次实例化对象不会重置,除非显式的修改。

代码示例:实例属性会覆盖同名的类属性。

class Books:
    # 类属性:属于类本身,所有实例共享
    book_start_id = 1000

    def __init__(self, book_name):
        # 实例属性:属于具体对象,每个实例独立
        self.book_name = book_name

    @classmethod
    def add_id(cls):
        # 通过类方法访问和修改类属性
        cls.book_start_id += 1
        return f"BK{cls.book_start_id}"


# 演示
print(Books.book_start_id)  # 输出:1000,类属性初始值

b1 = Books("Python入门")
print(b1.book_name)          # 实例属性,输出:Python入门

print(Books.add_id())        # 调用类方法,输出:BK1001
print(Books.book_start_id)   # 类属性被修改,输出:1001

b2 = Books("数据结构")
print(b2.book_name)          # 实例属性,输出:数据结构

print(b2.add_id())           # 通过实例调用类方法,输出:BK1002
print(Books.book_start_id)   # 类属性继续增加,输出:1002

说明:

  • book_start_id类属性,它属于 Books 类本身,所有实例共享同一个变量。
  • book_name实例属性,它属于具体的对象,每个对象有自己独立的值。
  • add_id类方法,通过它可以访问和修改类属性 book_start_id
  • 无论通过类还是实例调用 add_id,修改的是同一个类属性,不会重置。
3.2 属性的访问与修改

直接访问属性

  • 可以通过 obj.attr 直接访问实例或类的属性。
  • 访问时,Python 会先查找实例属性,再查找类属性。

动态访问和修改属性(内置函数)

Python 提供了三个内置函数,方便动态地访问和操作对象属性:

函数

用途

说明

getattr()

获取对象指定名称的属性值

getattr(obj, 'attr', default)

,如果属性不存在返回 default

或抛异常

setattr()

设置对象指定名称的属性值

setattr(obj, 'attr', value)

,不存在则创建

hasattr()

判断对象是否有指定名称的属性

hasattr(obj, 'attr')

返回布尔值


示例代码:

class Car:
    wheels = 4  # 类属性

    def __init__(self, color):
        self.color = color  # 实例属性

car = Car("红色")

# 直接访问
print(car.color)    # 红色
print(car.wheels)   # 4

# 使用 getattr 访问
print(getattr(car, "color"))       # 红色
print(getattr(car, "wheels"))      # 4
print(getattr(car, "speed", 100)) # 100,属性不存在返回默认值

# 使用 setattr 修改或添加属性
setattr(car, "color", "蓝色")  # 修改实例属性
setattr(car, "speed", 120)     # 新增实例属性

print(car.color)  # 蓝色
print(car.speed)  # 120

# 使用 hasattr 判断属性是否存在
print(hasattr(car, "speed"))  # True
print(hasattr(car, "brand"))  # False
3.3 方法分类

方法类型

第一个参数

调用方式

作用范围

实例方法

self

实例调用

操作实例属性

类方法

cls

类或实例调用

操作类属性

静态方法

类或实例调用

工具函数,无状态

3.3.1 实例方法
  • 定义:最常见的方法,第一个参数是 self,代表实例对象本身。
  • 作用:操作实例属性,访问或修改当前对象的状态。
  • 调用:只能通过实例对象调用。

示例:

class Books:
    def __init__(self, book_name):
        self.book_name = book_name  # 实例属性

    def show_name(self):  # 实例方法
        print(f"书名是:{self.book_name}")

b = Books("Python入门")
b.show_name()  # 输出:书名是:Python入门
3.3.2 类方法
  • 定义:使用装饰器 @classmethod,第一个参数是 cls,代表类本身。
  • 作用:操作类属性,访问或修改类级别的状态,通常用于工厂方法或者管理类属性。
  • 调用:可以通过类名或实例调用。
class Books:
    book_count = 0  # 类属性

    def __init__(self, book_name):
        self.book_name = book_name
        Books.book_count += 1

    @classmethod
    def get_book_count(cls):
        return cls.book_count

print(Books.get_book_count())  # 输出:0

b1 = Books("Python入门")
b2 = Books("数据结构")

print(Books.get_book_count())  # 输出:2
print(b1.get_book_count())     # 也可以通过实例调用,输出:2
3.3.3 静态方法

解释:在开发时,如果需要在类中封装一个方法,这个方法:既不需要访问实例属性或者调用实例方法,也不需要访问类属性或者调用类方法。这个时候,可以把这个方法封装成静态方法

  • 定义:使用装饰器 @staticmethod,不需要默认传入 selfcls 参数。
  • 作用:类似普通函数,但定义在类中,通常用于一些与类或实例无关的工具函数。
  • 调用:可以通过类名或实例调用。

注意事项:

  1. 静态方法不能直接访问类属性或实例属性,因为没有 clsself 参数。
  2. 静态方法可以通过类名显式访问类属性。
  3. 静态方法访问实例属性必须通过传入实例对象。

示例:

class Books:
    @staticmethod
    def is_valid_name(name):
        return isinstance(name, str) and len(name) > 0

print(Books.is_valid_name("Python"))  # 输出:True
print(Books.is_valid_name(""))        # 输出:False

4. 面向对象的三大特性

4.1 封装(Encapsulation)

定义:将对象的属性(数据)和方法(操作)绑定在一起,并隐藏对象的内部细节,只暴露必要的接口给外部使用,从而保护对象的状态不被外部随意修改。

作用:

  • 保护数据,防止外部代码直接访问或修改对象的内部状态,保证数据的完整性和安全性。
  • 隐藏实现细节,只暴露接口,简化使用,提高代码的灵活性和可维护性。
  • 提高代码复用性和模块化

示例:

class Person:
    def __init__(self, name, age):
        self.name = name          # 公有属性
        self._age = age           # 受保护属性(约定)
        self.__salary = 5000      # 私有属性

    def get_salary(self):         # 公有方法,访问私有属性
        return self.__salary

    def set_salary(self, value):  # 公有方法,修改私有属性
        if value > 0:
            self.__salary = value
        else:
            print("工资必须大于0")

p = Person("小明", 30)

print(p.name)          # 可以访问公有属性
print(p._age)          # 可以访问受保护属性(不建议)
# print(p.__salary)    # 报错,无法访问私有属性

print(p.get_salary())  # 通过公有方法访问私有属性

p.set_salary(6000)
print(p.get_salary())

注意事项:对于私有属性,如果在外部直接对私有属性进行修改,实际上是创建了一个成员属性,名字和私有属性一样而已,这是因为在Python中,私有属性实际上是通过名称改写(Name Mangling)变成了 _类名__属性名 的形式。

示例:

class Person:
    def __init__(self, name, age):
        self.name = name          # 公有属性
        self._age = age           # 受保护属性(约定)
        self.__salary = 5000      # 私有属性

    def get_salary(self):         # 公有方法,访问私有属性
        return self.__salary

    def set_salary(self, value):  # 公有方法,修改私有属性
        if value > 0:
            self.__salary = value
        else:
            print("工资必须大于0")

p = Person("小明", 30)

print(p.name)          # 可以访问公有属性
print(p._age)          # 可以访问受保护属性(不建议)
# print(p.__salary)    # 报错,无法访问私有属性

print(p.get_salary())  # 通过公有方法访问私有属性
p.__salary = 5000       #在外部直接对私有属性进行修改,实际是是创建了一个成员属性(错误示例)
print(p.__salary)

p.set_salary(6000)
print(p.get_salary())
4.2 继承(Inheritance)
4.2.1 继承的定义和作用

定义:子类可以继承父类所有的非私有属性和非私有方法,实现代码重用。

作用:

  • 避免重复代码,提高代码复用性。
  • 让程序结构更清晰,便于维护和扩展。

使用:class 子类名称(父类名称),括号内的为子类将要继承的父类

4.2.2 继承的类型

单继承:子类继承一个父类。

示例:

class Animal:
    def eat(self):
        print("吃东西")

class Dog(Animal):
    def bark(self):
        print("汪汪叫")

dog = Dog()
dog.eat()  # 继承自Animal
dog.bark() # 子类自己的方法

多继承:子类继承父类多个相关的属性和方法

  • 多重继承
  • 多层继承
class Flyable:
    def fly(self):
        print("会飞")

class Swimmable:
    def swim(self):
        print("会游泳")

class Duck(Flyable, Swimmable):
    pass

d = Duck()
d.fly()
d.swim()
class Animal:
    def eat(self):
        print("吃东西")

class Mammal(Animal):
    def walk(self):
        print("走路")

class Dog(Mammal):
    def bark(self):
        print("汪汪叫")

d = Dog()
d.eat()  # 来自Animal
d.walk() # 来自Mammal
d.bark() # 自己的方法

多继承中的方法执行顺序

  • MRO 决定了多继承时,方法的调用顺序。
4.3 多态(Polymorphism)

定义:同一个接口可以有不同的实现方式,在运行时根据对象类型调用相应的方法。其本质是不同对象调用相同方法产生不同结果。