文章目录
- 前言
- 面向对象技术简介
- 类(Class)
- 对象(Object)
- 继承(Inheritance)
- 封装(Encapsulation)
- 多态(Polymorphism)
- Python类详解
- 静态变量(Static Variables)
- 静态方法(Static Methods)
- 抽象方法(Abstract Methods)
- 方法重载(Method Overloading)
- 方法重写(Method Overriding)
- 魔法方法(Magic Methods)
- 补充
- 总结
前言
Python从设计之初就已经是一门面向对象的语言,正因为如此,在Python中创建一个类和对象是很容易的。本章节我们将详细介绍Python的面向对象编程。
如果你以前没有接触过面向对象的编程语言,那你可能需要先了解一些面向对象语言的一些基本特征,在头脑里头形成一个基本的面向对象的概念,这样有助于你更容易的学习Python的面向对象编程。
接下来我们先来简单的了解下面向对象的一些基本特征。
面向对象技术简介
- 类(Class): 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。
- 类变量:类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。
- 数据成员:类变量或者实例变量, 用于处理类及其实例对象的相关的数据。
- 方法重写:如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写。
- 局部变量:定义在方法中的变量,只作用于当前实例的类。
- 实例变量:在类的声明中,属性是用变量来表示的。这种变量就称为实例变量,是在类声明的内部但是在类的其他成员方法之外声明的。
- 继承:即一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。例如,有这样一个设计:一个Dog类型的对象派生自Animal类,这是模拟"是一个(is-a)"关系(例图,Dog是一个Animal)。
- 实例化:创建一个类的实例,类的具体对象。
- 方法:类中定义的函数。
- 对象:通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。
类(Class)
类是 Python 中创建对象的蓝图。它定义了一组属性和方法,这些属性和方法将被用于创建对象。类本质上是一个模板,用于定义对象的结构和行为。
定义一个简单的类的例子
class Dog:
def __init__(self, name, age):
self.name = name
self.age = age
def bark(self):
return f"{self.name} says woof!"
# 创建一个 Dog 对象
my_dog = Dog(name="Buddy", age=3)
# 调用对象的方法
print(my_dog.bark()) # 输出: Buddy says woof!
在这个例子中:
class Dog:
定义了一个类 Dog。
__init__:
是一个特殊的方法,用于初始化对象的属性。它在创建对象时被自动调用。
self:
代表类的实例,允许访问对象的属性和方法。
bark:
是类中的一个方法,它描述了对象的行为。
对象(Object)
对象是类的实例。每个对象都有自己独立的属性值,可以调用类中定义的方法。对象是类的具体实现。
创建和使用对象:
my_dog = Dog(name="Buddy", age=3)
print(my_dog.name) # 输出: Buddy
print(my_dog.age) # 输出: 3
继承(Inheritance)
继承是 OOP 的一个核心特性,它允许一个类(子类)继承另一个类(父类)的属性和方法。继承有助于代码重用和扩展。
class Animal:
def __init__(self, name):
self.name = name
def speak(self):
return "Some generic sound"
class Dog(Animal):
def speak(self):
return f"{self.name} says woof!"
# 创建一个 Dog 对象
my_dog = Dog(name="Buddy")
print(my_dog.speak()) # 输出: Buddy says woof!
在这个例子中:
Dog 类继承了 Animal 类。
Dog 类重写了 speak 方法,实现了多态。
封装(Encapsulation)
封装是将数据和操作这些数据的方法绑定在一起,隐藏内部实现细节,只暴露必要的接口。通过封装,类可以控制如何访问和修改其属
class Car:
def __init__(self, brand, year):
self.__brand = brand # 私有属性
self.__year = year # 私有属性
def get_brand(self):
return self.__brand
def set_brand(self, brand):
self.__brand = brand
# 创建一个 Car 对象
my_car = Car(brand="Toyota", year=2020)
print(my_car.get_brand()) # 输出: Toyota
my_car.set_brand("Honda")
print(my_car.get_brand()) # 输出: Honda
多态(Polymorphism)
多态允许不同类的对象以相同的方式调用同一方法,但具体行为可以根据对象的实际类型有所不同。这使得程序具有更好的灵活性和扩展性。
class Cat(Animal):
def speak(self):
return f"{self.name} says meow!"
animals = [Dog(name="Buddy"), Cat(name="Whiskers")]
for animal in animals:
print(animal.speak())
Python类详解
静态变量(Static Variables)
静态变量(类变量)是属于类的变量,而不是类的实例。它们由所有实例共享。可以在类定义中直接声明静态变量。
class Counter:
count = 0 # 静态变量
def __init__(self):
Counter.count += 1
# 创建多个 Counter 对象
c1 = Counter()
c2 = Counter()
c3 = Counter()
print(Counter.count) # 输出: 3
静态方法(Static Methods)
静态方法是类的一部分,但它不依赖于类的实例。静态方法没有 self 参数,它不能访问类或实例的属性或方法。通常用于一些逻辑与类实例无关的功能。
class MathUtils:
@staticmethod
def add(x, y):
return x + y
# 调用静态方法
result = MathUtils.add(5, 3)
print(result) # 输出: 8
在这个例子中,add 是一个静态方法,它与 MathUtils 类的实例无关,可以直接通过类名调用。
抽象方法(Abstract Methods)
抽象方法是一个没有实现的方法,仅定义了方法的签名。抽象方法通常用于定义一个接口,强制子类实现这些方法。抽象方法需要与抽象基类(abc.ABC
)结合使用。
from abc import ABC, abstractmethod
class Shape(ABC):
@abstractmethod
def area(self):
pass
class Rectangle(Shape):
def __init__(self, width, height):
self.width = width
self.height = height
def area(self):
return self.width * self.height
# 创建一个 Rectangle 对象
rect = Rectangle(width=4, height=5)
print(rect.area()) # 输出: 20
在这个例子中:
Shape 是一个抽象基类,其中定义了一个抽象方法 area。
Rectangle 类继承自 Shape,并实现了 area 方法。
方法重载(Method Overloading)
在许多编程语言中,方法重载指的是在同一个类中定义多个同名但参数列表不同的方法。Python 不支持传统的重载机制,即无法定义多个同名的方法,参数列表不同的方法会导致最后定义的方法覆盖之前定义的所有方法。
class MathUtils:
def add(self, a, b):
return a + b
# 这会覆盖之前的方法定义
def add(self, a, b, c=0):
return a + b + c
# 创建一个 MathUtils 对象
utils = MathUtils()
print(utils.add(2, 3)) # 输出: 5
print(utils.add(2, 3, 4)) # 输出: 9
在这个例子中,第二个 add 方法定义覆盖了第一个 add 方法。Python 通过参数默认值或使用可变参数来模拟重载功能
模拟重载
class MathUtils:
def add(self, *args):
return sum(args)
# 创建一个 MathUtils 对象
utils = MathUtils()
print(utils.add(2, 3)) # 输出: 5
print(utils.add(2, 3, 4)) # 输出: 9
print(utils.add(2, 3, 4, 5)) # 输出: 14
在这个例子中,*args 允许方法接受任意数量的参数,从而模拟了方法重载。
方法重写(Method Overriding)
方法重写是指在子类中重新定义父类的方法,以改变或扩展父类的行为。方法重写使得子类可以提供特定的实现来替代从父类继承的方法
class Animal:
def speak(self):
return "Some generic sound"
class Dog(Animal):
def speak(self):
return "Woof!"
class Cat(Animal):
def speak(self):
return "Meow!"
# 创建对象
animals = [Dog(), Cat()]
for animal in animals:
print(animal.speak())
在这个例子中,Dog 和 Cat 类重写了 Animal 类中的 speak 方法。每个子类提供了自己特定的实现。
魔法方法(Magic Methods)
魔法方法(或称为特殊方法)是以双下划线 __ 开头和结尾的方法,用于实现 Python 中的运算符重载和特殊功能。常见的魔法方法包括__init__、__str__、__repr__、__len__、__getitem__ 和 __setitem__
等。
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __str__(self):
return f"Point({self.x}, {self.y})"
def __repr__(self):
return f"Point(x={self.x}, y={self.y})"
def __eq__(self, other):
if isinstance(other, Point):
return self.x == other.x and self.y == other.y
return False
def __add__(self, other):
if isinstance(other, Point):
return Point(self.x + other.x, self.y + other.y)
return NotImplemented
# 创建 Point 对象
p1 = Point(2, 3)
p2 = Point(4, 5)
print(p1) # 输出: Point(2, 3)
print(repr(p1)) # 输出: Point(x=2, y=3)
print(p1 == p2) # 输出: False
print(p1 + p2) # 输出: Point(6, 8)
在这个例子中:
__init__
用于初始化对象。
__str__
用于返回对象的字符串表示,通常用于 print。
__repr__
用于返回对象的官方字符串表示,通常用于调试。
__eq__
用于比较两个对象是否相等。
__add__
用于实现加法操作。
以下还有更多的魔法方法
实例化和初始化
__new__
(cls, *args, **kwargs): 创建一个新实例,通常用于实现单例模式或自定义实例化行为。
__init__
(self, *args, **kwargs): 初始化实例对象,设置实例的初始状态。
字符串表示
__str__
(self): 返回对象的“用户友好”字符串表示,通常用于 print() 函数。
__repr__
(self): 返回对象的“官方”字符串表示,通常用于调试和开发者查看。
比较操作
__eq__
(self, other): 实现 == 操作符。
__ne__
(self, other): 实现 != 操作符。
__lt__
(self, other): 实现 < 操作符。
__le__
(self, other): 实现 <= 操作符。
__gt__
(self, other): 实现 > 操作符。
__ge__
(self, other): 实现 >= 操作符。
数学运算
__add__
(self, other): 实现 + 操作符。
__sub__
(self, other): 实现 - 操作符。
__mul__
(self, other): 实现 * 操作符。
__truediv__
(self, other): 实现 / 操作符。
__floordiv__(
self, other): 实现 // 操作符。
__mod__
(self, other): 实现 % 操作符。
__pow__
(self, other): 实现 ** 操作符。
容器协议
__len__
(self): 返回容器对象的长度,支持 len() 函数。
__getitem__
(self, key): 实现索引操作,如 obj[key]。
__setitem__
(self, key, value): 实现索引赋值操作,如 obj[key] = value。
__delitem__
(self, key): 实现索引删除操作,如 del obj[key]。
__iter__
(self): 返回迭代器对象,支持迭代。
__next__(self)
: 在迭代器对象中返回下一个值。
可调用对象
__call__(self, *args, **kwargs)
: 使对象像函数一样可调用。
上下文管理
__enter__(self)
: 在上下文管理器中,进入上下文时调用。
__exit__(self, exc_type, exc_value, traceback)
: 在上下文管理器中,退出上下文时调用。
其他常见魔法方法
__copy__(
self): 返回对象的浅拷贝。
__deepcopy__
(self, memo): 返回对象的深拷贝。
__contains__
(self, item): 实现 in 操作符。
__contains__
(self, item): 实现 in 操作符。
__hash__(
self): 实现哈希值,通常用于哈希表(如字典和集合)中的键。
__delattr__
(self, name): 实现 delattr() 函数,删除对象属性。
__getattr__
(self, name): 在访问不存在的属性时调用。
__setattr__
(self, name, value): 实现属性赋值。
__dir__
(self): 返回对象的属性列表,通常用于 dir() 函数。
补充
dataclass
装饰器是 Python 3.7 引入的一个非常有用的工具,用于简化类的定义,特别是那些主要用于存储数据的类。它可以自动为类生成一些常见的方法,如 __init__
、__repr__
、__eq__
等。使用 dataclass 可以让你更方便地创建数据容器类,同时减少样板代码。
from dataclasses import dataclass, field
from typing import List
@dataclass
class Student:
name: str
grades: List[int]
# 创建多个 Student 对象
student1 = Student(name="Alice")
student2 = Student(name="Bob")
# 修改一个实例的 grades 属性
student1.grades.append(90)
# 打印两个实例
print(student1) # 输出: Student(name='Alice', grades=[90])
print(student2) # 输出: Student(name='Bob', grades=[]) # 不会被修改
总结
类是面向对象编程的核心概念,它提供了一个模板用于创建对象。类定义了对象的属性(数据)和方法(行为),并通过构造函数 (init) 初始化对象的状态。通过实例化类,可以创建多个对象,每个对象拥有独立的属性和方法。
面向对象编程(OOP)是一种编程范式,通过将数据和操作数据的方法封装在对象中,来组织和管理代码。OOP 的核心概念包括:
- 封装: 将数据和操作数据的方法结合在一起,隐藏内部实现细节,只暴露必要的接口。
- 继承: 允许一个类(子类)继承另一个类(父类)的属性和方法,支持代码重用和扩展。
- 多态: 允许不同类的对象通过相同的接口进行交互,使得代码更具灵活性。
- 抽象: 定义一个接口,而不具体实现细节,强制子类实现接口中的方法。
通过这些特性,面向对象编程帮助开发者构建结构清晰、易于维护和扩展的代码。