Python 是一种支持面向对象编程(Object-Oriented Programming,简称 OOP)的编程语言,以下是关于 Python 面向对象编程的详细介绍:
基本概念
- 对象(Object):对象是面向对象编程的核心概念,它可以是现实世界中具体事物的抽象表示,比如一辆汽车、一个人等,在 Python 中每个对象都有自己的属性(用来描述对象的特征,相当于变量)和方法(用来定义对象的行为,相当于函数)。
- 类(Class):类是创建对象的蓝图或模板,它定义了一组具有相同属性和方法的对象的通用结构。可以把类想象成制作饼干的模具,而对象就是用这个模具做出来的一个个具体的饼干。
大象放进冰箱 面向过程: 蛋炒饭,性能好 1.冰箱打开 2.大象进去 3.冰箱关闭 面向对象: 盖浇饭,耦合度低,易扩展,易维护 冰箱: 打开 关闭 大象: 进去 类: 是对象的模版(共同的特性),抽象的 对象: 是类的实例化, 看的见,摸的着的具体的对象,万事万物皆为对象
一:类和对象
1.创建对象
使用类来创建对象(也叫实例化)的方式如下:
my_dog = Dog("旺财", 3)
这样就创建了一个名为 “旺财”,年龄为 3 岁的狗对象。
2.访问属性和调用方法
- 访问属性:通过对象名加属性名的方式来访问对象的属性,例如:
print(my_dog.name)
print(my_dog.age)
print(my_dog.species)
3.调用方法:使用对象名加方法名并传入相应参数(如果有要求)的形式来调用方法,例如
my_dog.bark()
二 .属性
在 Python 面向对象编程中,属性是用于描述对象特征的元素,下面从不同角度对其进行详细讲解:
1.类属性
- 定义:类属性是直接定义在类内部,且在方法之外的变量。它属于整个类,被这个类的所有实例(对象)所共享。
- 语法示例
class Car:
wheels = 4 # 这就是类属性,表示汽车的轮子数量,所有Car类的对象都共有这个属性值
def __init__(self, brand):
self.brand = brand # 这里的brand是实例属性
car1 = Car("Toyota")
car2 = Car("Ford")
print(car1.wheels) # 输出4
print(car2.wheels) # 输出4
Car.wheels = 6 # 修改类属性的值
print(car1.wheels) # 输出6,因为类属性被修改了,所有对象共享新值
- 特点与应用场景:
- 共享性:由于类属性被所有对象共享,当需要表示某个类的所有对象共有的一些特征时,就可以使用类属性。比如表示汽车的轮子数量、某种动物的物种分类(如前面提到的
Dog
类中的species
属性)等,不管创建多少个该类的具体对象,这些属性值都是一样的,并且一处修改,所有对象对应的属性值都会随之改变。 - 节省内存空间:对于那些不会随对象个体变化而变化的通用属性,使用类属性可以避免为每个对象都重复存储相同的数据,提高内存使用效率。
- 共享性:由于类属性被所有对象共享,当需要表示某个类的所有对象共有的一些特征时,就可以使用类属性。比如表示汽车的轮子数量、某种动物的物种分类(如前面提到的
2.实例属性
- 定义:实例属性是在类的构造方法(
__init__
方法)或者对象创建后通过对象动态添加的属性,它属于具体的某个对象,不同对象的实例属性值可以不同。 - 语法示例:
class Person:
def __init__(self, name, age):
self.name = name # 通过self关键字定义实例属性name,用来表示每个人的具体名字
self.age = age # 实例属性age,代表每个人的具体年龄
person1 = Person("Alice", 25)
person2 = Person("Bob", 30)
print(person1.name) # 输出Alice
print(person2.name) # 输出Bob
person1.new_attribute = "额外添加的属性" # 可以动态给person1对象添加新的实例属性
- 特点与应用场景:
- 对象特异性:实例属性体现了对象之间的差异,能够准确描述每个对象独有的特征。比如每个人都有自己的名字和年龄,每辆车都有自己特定的颜色、车牌号等,这些不同对象各自的特点就可以通过实例属性来表示。
- 动态扩展性:可以在对象创建后根据实际需求动态地为其添加新的实例属性,增加了对象的灵活性和适应性,方便根据不同的业务逻辑来丰富对象所包含的信息。
3.私有属性 (也叫封装 )
- 定义:在 Python 中,通过在属性名前添加双下划线
__
开头(严格来说这是一种名称改写机制,并非真正的绝对私有,但能起到限制外部直接访问的作用)来定义私有属性,它通常用于隐藏对象内部的一些不希望被外部随意访问或修改的数据。 - 语法示例:
class BankAccount:
def __init__(self, balance):
self.__balance = balance # 定义私有属性__balance,表示账户余额
def deposit(self, amount):
self.__balance += amount
def withdraw(self, amount):
if amount <= self.__balance:
self.__balance -= amount
else:
print("余额不足")
def get_balance(self):
return self.__balance
- 特点与应用场景:
- 数据隐藏与保护:私有属性可以防止外部代码直接对一些关键数据进行不恰当的访问或修改,保证了数据的安全性和完整性。例如银行账户的余额,不应该被外部随意更改,通过将其设为私有属性,并提供特定的存款(
deposit
)、取款(withdraw
)等方法来间接操作余额,能够有效控制数据的流向和操作规范。 - 内部逻辑封装:有助于将对象内部的实现细节隐藏起来,使得类的使用者只需要关注对象提供的公共方法,而不必了解内部复杂的数据结构和运算逻辑,降低了代码的耦合度,便于代码的维护和扩展。
- 数据隐藏与保护:私有属性可以防止外部代码直接对一些关键数据进行不恰当的访问或修改,保证了数据的安全性和完整性。例如银行账户的余额,不应该被外部随意更改,通过将其设为私有属性,并提供特定的存款(
4. 受保护属性(其实没啥用,可以随便调用)
- 定义:以单下划线
_
开头的属性被视为受保护属性,它表示这个属性虽然可以被外部访问,但按照 Python 的编程约定,应该被视为内部实现细节,外部最好不要随意访问或修改,主要是给类的子类(继承该类的类)使用的。 - 语法示例:
class BaseClass:
_protected_attr = 10 # 受保护属性
def _protected_method(self):
print("这是一个受保护的方法")
class SubClass(BaseClass):
def access_protected(self):
print(self._protected_attr) # 子类可以访问父类的受保护属性
self._protected_method() # 子类可以调用父类的受保护方法
obj = SubClass()
obj.access_protected()
- 特点与应用场景:
- 代码提示与约定遵循:单下划线开头的属性只是一种编程习惯上的提示,告知其他开发者该属性可能是类内部相关联的部分,不建议随意乱动,有助于保持代码的规范性和可维护性,让代码的结构和意图更加清晰。
- 方便子类继承与扩展:在类的继承体系中,子类可以访问和使用父类的受保护属性和方法,方便在继承基础上进行功能的扩展和重写等操作,同时又区分了哪些是更倾向于内部使用的元素,避免外部过度干扰。
三.方法
在 Python 面向对象编程中,方法是定义在类内部,用于描述对象行为或操作对象属性的函数,以下是对其详细的讲解:
1.实例方法
- 定义:实例方法是最常见的一类方法,它是定义在类内部,并且第一个参数通常为
self
(按照约定这个参数名一般写为self
,但也可以写成其他合法的变量名,不过为了遵循 Python 的编程规范,建议使用self
)的函数,这个self
代表的是类的实例对象本身,通过它可以在方法内部访问和操作当前对象的各种属性以及调用其他实例方法。(self其实是赋予地址) - 语法示例:
class Dog:
def __init__(self, name, age):
self.name = name
self.age = age
def bark(self): #实例方法
print(f"{self.name} 正在汪汪叫!")
def get_older(self, years): #这是实例方法
self.age += years
这里的bark
方法和get_older
方法都是实例方法。在bark
方法中,通过self.name
访问了当前狗对象的名字属性,并在方法执行时输出相应的叫的信息;在get_older
方法中,利用self.age
获取当前对象的年龄属性,然后根据传入的参数years
来更新年龄属性的值。
- 调用方式:实例方法需要通过类的实例对象来调用,格式为
对象名.方法名(参数列表)
,例如:
my_dog = Dog("旺财", 3)
my_dog.bark()
my_dog.get_older(1)
print(my_dog.age)
- 特点与应用场景:
- 操作对象特定数据:实例方法主要用于对具体某个对象的属性进行操作,因为每个对象的属性值可能不同,实例方法能根据不同对象的实际情况执行相应的行为,体现了对象的个体差异和特性。比如每个学生对象都有自己的成绩属性,通过实例方法可以实现计算平均成绩、更新某科成绩等针对特定学生个体的操作。
- 体现对象行为:用于描述对象能够执行的行为动作,让对象变得 “活灵活现”,符合现实世界中对象具有特定行为的概念。像动物类的对象有跑、叫等行为,都可以通过实例方法来模拟实现。
2.类方法
- 定义:类方法是使用
@classmethod
装饰器修饰的方法,它的第一个参数通常约定为cls
(同样也可以用其他变量名,但推荐使用cls
),这个cls
代表的是类本身,通过它可以访问和操作类的属性,也可以在类方法内部调用其他类方法,但不能直接访问实例属性(因为类方法是与类相关联,而不是与具体某个实例相关联)。 - 语法示例:
class Car:
wheels = 4
@classmethod
def change_wheels(cls, num):
cls.wheels = num
@classmethod
def show_wheels(cls):
print(f"汽车轮子数量为: {cls.wheels}")
在上述代码中,change_wheels
类方法可以通过cls
参数修改类属性wheels
的值,show_wheels
类方法则用于展示当前类属性wheels
所表示的轮子数量。
- 调用方式:类方法既可以通过类名直接调用,也可以通过类的实例对象调用(不过建议通过类名调用,这样更符合语义),格式分别为
类名.方法名(参数列表)
或者对象名.方法名(参数列表)
,例如:
Car.change_wheels(6)
Car.show_wheels()
my_car = Car()
my_car.change_wheels(8)
my_car.show_wheels()
- 特点与应用场景:
- 操作类属性:当需要对类的整体属性进行操作,且这种操作与具体的实例对象无关时,类方法就非常有用。例如在管理类的配置信息(类属性)方面,像更改某种产品类的默认颜色、尺寸等通用属性,通过类方法可以方便地在类层面进行统一的修改和查询操作。
- 工厂方法创建对象:可以作为一种工厂方法来创建对象,也就是根据类的一些现有属性或者逻辑来返回该类的不同实例。比如有一个日期类,通过类方法可以根据不同的输入格式(如年 - 月 - 日、月 / 日 / 年等)创建对应的日期对象实例。
3.静态方法
- 定义:静态方法是使用
@staticmethod
装饰器修饰的方法,它与类和类的实例对象之间没有默认的关联,既不需要self
参数也不需要cls
参数,它更像是定义在类内部的普通函数,只是为了代码的组织和归类,将相关的函数放在了类这个命名空间下。 - 语法示例:
class MathUtils:
@staticmethod
def add(a, b):
return a + b
@staticmethod
def multiply(a, b):
return a * b
这里的add
和multiply
静态方法,它们只是简单地实现了数学运算的功能,和具体的某个MathUtils
类的实例或者类本身的属性没有直接关联。
- 调用方式:静态方法同样既可以通过类名调用,也可以通过实例对象调用(推荐通过类名调用),格式为
类名.方法名(参数列表)
或者对象名.方法名(参数列表)
,例如:
print(MathUtils.add(3, 5))
result = MathUtils.multiply(2, 4)
print(result)
math_obj = MathUtils()
print(math_obj.add(1, 2))
- 特点与应用场景:
- 代码组织与模块化:当有一组函数,它们功能上相关,但是又不需要依赖类的实例属性或者类属性来执行时,将它们放在类里面定义成静态方法,可以让代码结构更加清晰,便于代码的管理和维护。比如一些工具类函数,像数学计算函数、文件格式转换函数等,如果它们与某个类的对象行为或者类的属性没有紧密联系,就可以作为静态方法放在对应的类中。
- 与类的关联性:虽然静态方法本身独立于类和实例,但由于放在类里面,从逻辑上表示它们和这个类所代表的概念有一定的关联性,使得代码阅读者能更容易理解这些函数的作用范围和应用场景。