面向对象编程(OOP)是一种软件开发方法和编程范式,它将现实世界中的事物抽象为程序中的对象,我们身边的一切——手机、杯子、汽车,都可以看作是“对象”。每个对象都有自己的属性(特征)和行为(功能)。
1. 创建一个对象——类和实例
每个对象都有一个“模板”,这个模板就是类。比如,我们可以定义一个“人类”的模板,然后通过这个模板创建具体的人。
1.1 创建一个Person类
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
我们首先创建了一个Person类,这是一个抽象的人,泛指所有的人,专门用来生成具体的人,类一般首字母大写。
__init__方法是这个类的初始化,每次我们用Person创建一个人,名字和年龄都会被传递给对象,就像给新生儿起名字和记录年龄一样。
self 是对象自己,像英语中的myself,用self特指对象自己。
1.2 实例化对象和调用方法
方法就是这个对象的行为,比如每个人都会说“你好,我叫XXX,今年XX岁。”在代码中,我们也可以给对象这种能力!
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def introduce(self):
return f"大家好,我是{self.name},今年{self.age}岁!"
现在,让我们让小明来亮相吧,这个过程叫实例化对象,就是通过抽象的Person类创建一个具体的人:小明。
使用实例名+.+方法名就可以调用对象中的方法,例如自我介绍。
xiaoming = Person("小明", 18)
print(xiaoming.introduce())
运行后,你会看到:
大家好,我是小明,今年18岁!
1.3 添加属性和方法
对象不可能一成不变,我们可以很方便的拓展类的功能。比如,人会长大、会跑步、会学习。这些行为可以用方法来实现,而“长大”的结果可以通过属性来体现,比如有了新的兴趣爱好。
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
self.hobby = hobby
def introduce(self):
return f"大家好,我是{self.name},今年{self.age}岁!"
def birthday(self,hobby):
self.age += 1
sleg.hobby = hobby
print(f"今天是我的生日,我今年学会了{slef.hobby},现在我{self.age}岁啦!")
现在,我们让小明过生日了:
xiaoming.birthday("打篮球")
运行后:
今天是我的生日,我今年学会了打篮球,现在我19岁啦!
2. 对象之间的关系
现实中,人不是孤单存在的。他们有家庭、朋友,也有不同的身份。对象也一样,可能会有各种联系,让我们看看如何通过类和对象表示这些复杂关系。
2.1 包含关系
假设一个人有一辆车,我们可以用一个类嵌套另一个类来表示这种关系。
class Car:
def __init__(self, brand, color):
self.brand = brand
self.color = color
class Person:
def __init__(self, name, age, car):
self.name = name
self.age = age
self.car = car
def show_car(self):
print(f"我的车是{self.car.color}的{self.car.brand}!")
创建对象并测试:
my_car = Car("特斯拉", "红色")
xiaoming = Person("小明", 18, my_car)
xiaoming.show_car()
#运行结果:我的车是红色的特斯拉!
这个过程中我们先实例化了对象Car,再实例化对象人,我们将 car 作为人的一个属性,车包含于人。
然后就可以直接在人这个对象中调用车这个对象,调用过程中就是多加了一个.如self.car.brand
2.2 继承关系
有时,一个类可以是另一个类的“特殊版本”。比如,学生是一种特殊的“人”,我们可以用继承来实现。
即学生具有“人类”的所有特点,但是其自身又有一些特别的地方,比如学生有学校。
用概念来说,就是子类与父类之间的关系,子类可以继承父类的所有属性和方法。
class Student(Person):
def __init__(self, name, age, school):
super().__init__(name, age)
self.school = school
def introduce(self):
return f"大家好,我是{self.name},今年{self.age}岁,我在{self.school}上学!"
super() 是一个内置函数,它的主要作用是调用当前类的父类的 __init__ 方法,并且将 name 和 age 作为参数传递给父类的构造函数。
现在我们可以创建学生对象了:
xiaohong = Student("小红", 16, "北京高中")
print(xiaohong.introduce())
#运行结果:大家好,我是小红,今年16岁,我在北京高中上学!
2.3 “兄弟”关系
“兄弟”关系是我自己起的一个名字,方便大家理解,所谓“兄弟”关系就是继承了同一个类的几个不同的类之间的关系,他们虽然都继承了父类,但是具体的表现又不同(龙生九子,各有不同),这实际上称为多态。
比如我们刚刚写了学生类,我们再写一个教师类,同样也继承人类的所有属性和方法,虽然学生和教师属于不同的类,但是他们同一个方法的内容可以不同。
class Teacher(Person):
def __init__(self, name, age, subject):
super().__init__(name, age)
self.subject = subject
def introduce(self):
return f"大家好,我是{self.name},教{self.subject}!"
让学生和老师各自介绍自己:
xiaoming = Student("小明", 18, "北大")
laozhang = Teacher("老张", 40, "数学")
print(xiaoming.introduce())
print(laozhang.introduce())
输出:
大家好,我是小明,今年18岁,我在北大上学!
大家好,我是老张,教数学!
3. 面向对象的三大特点
我们刚刚通过一些例子感受了一下面向对象的特点,接着我们来详细讲解一下具体的概念和作用。
3.1 封装(Encapsulation)
**定义:**封装是指将数据(属性)和行为(方法)封装在类中,通过访问权限控制外界对类中数据的访问和修改。
目标:保护数据,减少耦合,提高代码的可维护性。
作用:
- 隐藏内部细节:防止外界直接访问和修改对象的内部数据,确保数据的安全性和完整性。
- 提供统一接口:通过方法(getter 和 setter)对外提供访问接口,保证对象的操作行为统一、受控。
- 模块化:使代码结构更清晰,易于维护和扩展。
示例:银行账户的封装
class BankAccount:
def __init__(self, owner, balance):
self.owner = owner # 账户持有人(公开属性)
self.__balance = balance # 账户余额(私有属性)
# 获取余额
def get_balance(self):
return self.__balance
# 存款方法
def deposit(self, amount):
if amount > 0:
self.__balance += amount
print(f"{amount} 元已存入账户,现在余额为 {self.__balance} 元。")
else:
print("存款金额无效。")
# 取款方法
def withdraw(self, amount):
if 0 < amount <= self.__balance:
self.__balance -= amount
print(f"{amount} 元已取出账户,现在余额为 {self.__balance} 元。")
else:
print("余额不足或金额无效。")
# 使用示例
account = BankAccount("小明", 1000)
print(account.get_balance()) # 输出:1000
account.deposit(500) # 输出:500 元已存入账户,现在余额为 1500 元。
account.withdraw(200) # 输出:200 元已取出账户,现在余额为 1300 元。
封装使得账户余额等敏感信息得到了保护,只有通过提供的接口方法才能进行修改或查看,无法直接通过.+属性名的方式进行修改,提高了安全性,避免了误操作。
3.2 继承(Inheritance)
**定义:**继承是一种机制,通过定义子类(子类继承父类),子类可以直接拥有父类的属性和方法,且可以扩展或重写它们。
目标:实现代码复用,减少重复代码,建立类之间的层次关系。
作用:
- 代码复用:子类继承父类,无需重复编写相同代码。
- 扩展性:子类可以在父类基础上扩展新功能。
- 多层次关系:建立清晰的类层次结构,反映对象的共性和特性。
继承相对好理解,可以参考 2.2 中学生类继承了人类的例子。
3.3 多态(Polymorphism)
**定义:**多态是指子类可以根据自己的需要重写父类的方法,并通过父类引用调用时表现出不同的行为。
目标:在不同类中实现同一接口,增强代码的灵活性和扩展性。
作用:
- 提高灵活性:同一操作可以针对不同对象表现出不同行为。
- 简化代码:对一组对象进行统一操作,无需关注具体对象的类型。
- 增强扩展性:新对象只需遵循接口定义即可融入系统。
我们这里再拿经典的动物类来举例,便于大家体会这个概念。
# 定义父类
class Animal:
def speak(self):
pass # 父类方法是抽象的,留给子类实现
# 定义子类
class Dog(Animal):
def speak(self):
return "汪汪!"
class Cat(Animal):
def speak(self):
return "喵喵!"
# 使用多态
animals = [Dog(), Cat()] # 存储不同子类对象的列表
for animal in animals:
print(animal.speak()) # 输出:汪汪! 喵喵!
动物都会叫,但是不同动物的叫声不同,这就是对多态的直观感受。
4. 小结
面向对象编程正是因为具有如下特点,使得其在开发中应用非常广泛。
- 封装:隐藏细节,保护数据(例:银行账户)。
- 继承:代码复用,减少冗余(例:动物行为)。
- 多态:灵活扩展,统一接口(例:几何图形面积计算)。
- 低耦合:模块独立,便于扩展(例:数据存储策略)。
通过这些特性,OOP帮助开发者构建可读、可维护、可扩展的代码结构,是解决复杂问题的有效方法。
🙋🏻♀️比如我们需要设计一个学生管理系统,使用面向对象的思想就能将问题大幅度简化,如创建一个 Student 基类,包含通用属性(如姓名、学号)和方法(如打印成绩),并可以扩展特有功能,例如论文管理功能。
我们套面向对象的三大特点来体会:
- 封装:每个学生对象独立管理自己的数据和方法,避免外部直接修改。
- 继承:不同学生类型复用通用代码,减少重复。
- 多态:统一管理不同类型的学生,例如本科生和研究生、不同专业的学生。
⭐️面向对象的概念相对抽象,要多结合现实生活中的例子去理解。