第1章 Python面向对象编程概述
1.1 面向对象编程(OOP)简介
面向对象编程(Object-Oriented Programming, OOP)是一种主流的编程范式,它模拟了现实世界的实体以及它们之间的相互作用。在OOP的世界里,一切皆对象,每个对象都具有自己的属性(attributes)和行为(behaviors)。这一理念让程序设计更符合人类自然思维,易于理解和维护,并提供了代码复用、模块化设计的有力手段。
1.1.1 OOP的基本思想与优势
OOP基于三大核心原则:封装、继承和多态。封装允许我们将数据和处理这些数据的函数组合在一起,并通过接口对外隐藏具体实现细节,保护内部数据安全;继承使得子类能够直接获得父类的属性和方法,减少代码重复;多态则是同一消息可以根据发送的对象类型的不同而产生不同的行为,增强了程序的灵活性和扩展性。
例如,在模拟动物园场景时,可以创建一个Animal基类,封装其共有的属性如name和species,并定义通用的行为eat和speak。每种具体的动物如Dog和Cat继承自Animal,并可根据自身特点覆盖或扩展这些行为,这就是OOP在实际应用中的体现。
class Animal:
def __init__(self, name, species):
self.name = name
self.species = species
def eat(self):
print(f"{self.name} is eating.")
def speak(self):
pass # 默认不实现,由子类具体定义
class Dog(Animal):
def speak(self):
print(f"{self.name} barks.")
class Cat(Animal):
def speak(self):
print(f"{self.name} meows.")1.1.2 OOP在Python中的重要地位
在Python中,OOP被广泛应用于各种复杂的应用场景。Python本身的设计即高度支持面向对象编程,通过类和对象可以构建出强大的组件集合,便于开发大型项目。无论是标准库还是第三方库,许多功能都建立在面向对象的基础上,这使得开发者能更便捷地利用已存在的类和框架来快速搭建应用程序。同时,Python的简洁语法也极大地降低了面向对象编程的入门门槛,使其成为技术爱好者和从业者的首选编程范式之一。
第2章 定义Python类
2.1 使用class关键字创建类
2.1.1 类名的选择与命名规范
在Python中,定义一个类使用关键字class,后跟类名。类名通常采用驼峰式命名(CamelCase),首字母大写,以便与函数、变量等区分。类名应具有描述性,直观反映该类所代表的实体或概念。遵循PEP 8编码规范,避免使用Python保留字作为类名,并尽量避免与内置类型或标准库模块冲突。
class User:
pass2.1.2 类体结构:包含属性与方法的定义
类体位于class语句与冒号之间,由缩进的代码块构成。类体中定义的变量称为属性,用于存储对象的状态;函数称为方法,用于描述对象的行为。方法内通常包含一个名为self的参数,它代表调用该方法的对象实例。
class User:
def __init__(self, name, email):
self.name = name
self.email = email
def introduce(self):
return f"My name is {self.name} and my email is {self.email}."2.2 类的属性2.2.1 实例属性:特定于单个对象的变量
实例属性是与每个对象实例关联的变量,每个对象有自己的副本。在上面的例子中,name和email就是实例属性。它们在__init__方法中被初始化,并通过self关键字绑定到特定的实例上。
2.2.2 类属性:共享于所有对象的变量
类属性属于整个类,所有实例共享同一份数据。定义类属性时,直接在类体中赋值即可,无需通过self引用。
class User:
user_count = 0 # 类属性
def __init__(self):
User.user_count += 1
@classmethod
def get_user_count(cls):
return cls.user_count2.2.3 属性初始化:__init__方法及其作用
__init__是一个特殊方法(魔术方法),当创建类的新实例时自动调用。它用于设置对象的初始状态,即初始化实例属性。通过__init__方法传递参数给新创建的对象,确保对象在创建之初就具备完整的有效状态。
class Car:
def __init__(self, make, model, year):
self.make = make
self.model = model
self.year = year2.3 类的方法2.3.1 实例方法:操作对象状态的函数
实例方法是在类中定义的函数,通过self参数与特定对象关联。它们可以访问和修改对象的属性,实现对象的行为。
class BankAccount:
def __init__(self, balance=0):
self.balance = balance
def deposit(self, amount):
self.balance += amount
def withdraw(self, amount):
if amount <= self.balance:
self.balance -= amount
else:
print("Insufficient funds.")2.3.2 类方法与静态方法的区别与应用
类方法通过@classmethod装饰器标识,接收类对象作为第一个参数(通常命名为cls)。它们不依赖于特定实例,常用于与类相关的操作,如工厂方法或需要访问类属性的场景。
class Pizza:
crust_types = ['thin', 'thick']
@classmethod
def available_crusts(cls):
return cls.crust_types
静态方法使用@staticmethod装饰器,与类或实例无关,仅作为一个独立的函数存在于类的命名空间中,方便组织相关功能。
class MathUtils:
@staticmethod
def add(a, b):
return a + b2.3.3 特殊方法(魔术方法):实现对象间交互的标准接口
特殊方法(如__str__,__len__,__getitem__等)是Python中双下划线包围的方法名,它们定义了对象如何响应特定的操作或表达式。通过实现这些方法,可以让自定义类像内置类型一样支持诸如打印、索引、比较等行为。
第3章 实例化对象
3.1 创建对象的语法与过程
3.1.1 使用类名加括号创建实例
在Python中,一旦定义了一个类,就可以通过类名后跟一对括号来创建该类的实例。括号内可以传入初始化参数,这些参数会传递给__init__方法以设置对象的初始状态。
class Vehicle:
def __init__(self, make, model):
self.make = make
self.model = model
car_instance = Vehicle('Toyota', 'Corolla') # 创建Vehicle类的一个实例
print(car_instance.make) # 输出:Toyota3.1.2 初始化参数与__init__方法的配合使用
__init__方法是一个特殊方法,会在创建类的实例时自动调用。它的主要作用是初始化新创建的对象,设置对象的初始属性值。下面例子中,当我们创建Car对象时,传递的参数会被__init__方法接收并用来初始化对象的属性。
class Car(Vehicle):
def __init__(self, make, model, year, color):
super().__init__(make, model)
self.year = year
self.color = color
my_car = Car('Honda', 'Civic', 2020, 'Blue')
print(my_car.year) # 输出:2020
print(my_car.color) # 输出:Blue3.2 访问与修改对象属性3.2.1 点运算符(.)用于属性访问与赋值
点运算符是Python中访问或修改对象属性的关键方式。通过.可以访问类实例的属性或调用其方法。
class Person:
def __init__(self, first_name, last_name):
self.first_name = first_name
self.last_name = last_name
john_doe = Person('John', 'Doe')
print(john_doe.first_name) # 输出:John
john_doe.age = 30 # 动态添加一个属性
print(john_doe.age) # 输出:303.2.2getattr(),setattr()与delattr()函数的使用
除了点运算符外,还可以通过Python内置函数来动态获取、设置或删除对象的属性。
# getattr()用于获取对象的属性,如果不存在则可返回默认值
age = getattr(john_doe, 'age', None)
print(age) # 输出:30
# setattr()用于设置对象的属性
setattr(john_doe, 'occupation', 'Engineer')
print(john_doe.occupation) # 输出:Engineer
# delattr()用于删除对象的属性
delattr(john_doe, 'occupation')
try:
print(john_doe.occupation)
except AttributeError:
print("Attribute 'occupation' does not exist anymore.") # 输出:Attribute 'occupation' does not exist anymore.3.3 调用对象方法3.3.1 方法调用的语法与实例上下文
对象的方法本质上是与对象关联的函数,方法调用时,会隐式地将调用对象作为第一个参数传递,这个参数通常命名为self。
class Dog:
def __init__(self, name):
self.name = name
def bark(self):
print(f"{self.name} says Woof!")
fido = Dog('Fido')
fido.bark() # 输出:Fido says Woof!3.3.2 方法中的self参数解析
self并非关键字,而是约定俗成的命名,代表对象实例自身。在方法内部,可以通过self访问当前对象的所有属性和方法。
class Circle:
def __init__(self, radius):
self.radius = radius
def area(self):
pi = 3.14159
return pi * (self.radius ** 2)
circle = Circle(5)
print(circle.area()) # 输出:78.53975第4章 继承与派生类4.1 继承的基本概念与作用4.1.1 单继承与多继承的定义
继承是面向对象编程中的核心概念之一,它允许我们基于已有的类创建新的类,新类继承了原有类的属性和方法,避免了重复编写相同的代码。在Python中,有两种主要的继承形式:
•单继承:一个派生类(子类)只从一个基类(父类)继承。这是最简单的继承关系,派生类直接继承基类的所有非私有属性和方法。
class Animal:
def __init__(self, name):
self.name = name
def speak(self):
raise NotImplementedError("Subclasses must implement this method.")
class Dog(Animal): # 单继承:Dog类继承自Animal类
def speak(self):
return f"{self.name} barks."
dog = Dog('Rex')
print(dog.speak()) # 输出:Rex barks.
•多继承:一个派生类可以从多个基类继承,继承链可以是复杂的树状结构。多继承使派生类同时拥有多个基类的属性和方法。
class CanSwim:
def swim(self):
return f"{self.name} is swimming."
class CanFly:
def fly(self):
return f"{self.name} is flying."
class Duck(Animal, CanSwim, CanFly): # 多继承:Duck类继承自Animal、CanSwim、CanFly类
pass
duck = Duck('Donald')
print(duck.swim()) # 输出:Donald is swimming.
print(duck.fly()) # 输出:Donald is flying.4.1.2 继承与软件复用、模块化设计的关系
继承实现了代码的复用和模块化设计,显著提升了软件开发效率和可维护性。通过继承,我们可以:
•复用基类的代码:派生类无需重新编写基类已经实现的功能,只需专注于扩展或定制化特定行为。这减少了冗余代码,增强了代码一致性。
•构建层次化的类体系:基类定义通用行为和属性,派生类根据具体需求添加或修改。这种层次结构清晰地展现了不同类之间的关系,有助于理解系统的整体架构。
•实现“is-a”关系:继承表达了类之间的继承关系,如“Dog is an Animal”。这种关系使得派生类可以作为基类的替代品在程序中使用,遵循面向对象设计的“替换原则”。
4.2 定义派生类
4.2.1 使用extends关键字声明继承关系
在Python中,使用括号内指定基类列表的方式声明继承关系。这里没有extends关键字,而是直接将基类名放在类定义后的括号中,多个基类之间用逗号分隔。
class DerivedClass(BaseClass1, BaseClass2, ...): # 正确的Python继承声明方式
...4.2.2 覆写(override)基类方法与属性
派生类可以重新定义(覆写)基类中的方法或属性,以提供特定于派生类的实现。当派生类对象调用这些方法或访问属性时,将使用派生类的版本而非基类的版本。
class Animal:
def speak(self):
return "I am an animal."
class Dog(Animal):
def speak(self):
return f"I am a {self.__class__.__name__}."
dog = Dog()
print(dog.speak()) # 输出:I am a Dog.4.3 super()函数与方法重写4.3.1super()的使用与MRO(方法解析顺序)
super()函数允许派生类方法在调用基类方法时,无需明确指明基类名,有助于应对多重继承情况下的复杂继承链。super().method_name(...)调用的是当前类继承链中下一个类的method_name方法。这种方法调用遵循MRO(Method Resolution Order,方法解析顺序),确保在多重继承下正确、一致地查找和调用方法。
class A:
def greet(self):
print("Hello from A")
class B(A):
def greet(self):
super().greet() # 调用A.greet()
print("Hello from B")
b = B()
b.greet() # 输出:
# Hello from A
# Hello from B4.3.2 跨层级调用基类方法以实现协作
在某些情况下,派生类可能需要直接调用基类中被覆写的方法,以保持部分原有逻辑。使用super()或显式调用基类方法可以实现这种跨层级协作。
class Shape:
def draw(self):
print("Drawing the shape...")
class Circle(Shape):
def draw(self):
super().draw() # 先执行Shape.draw()
print("Drawing a circle...")
circle = Circle()
circle.draw() # 输出:
# Drawing the shape...
# Drawing a circle...第5章 封装、多态与抽象5.1 封装:隐藏内部实现,提供公共接口5.1.1 私有属性与私有方法的标识与访问控制
封装是面向对象编程的重要原则之一,它通过限制外部对类内部数据和方法的直接访问,从而保证了数据的安全性和完整性。在Python中,可以通过在属性或方法前加上两个下划线__来实现封装,这样声明的属性或方法被视为私有的。
class BankAccount:
def __init__(self, initial_balance):
self.__balance = initial_balance # 私有属性,外部无法直接访问
def deposit(self, amount):
self.__balance += amount
def withdraw(self, amount):
if amount <= self.__balance:
self.__balance -= amount
else:
print("Insufficient funds.")
def check_balance(self):
return self.__balance # 通过公共方法间接访问私有属性
account = BankAccount(1000)
print(account.check_balance()) # 输出账户余额,但不能直接访问account.__balance5.1.2 getter与setter方法的使用
为了进一步增强封装,同时又能在一定程度上控制对私有属性的访问,可以定义getter和setter方法。getter方法用于获取私有属性的值,setter方法则负责设置私有属性的值,并可在其中加入必要的验证逻辑。
class Person:
def __init__(self, first_name, last_name):
self.__first_name = first_name
self.__last_name = last_name
@property
def full_name(self):
return f"{self.__first_name} {self.__last_name}" # getter方法
@full_name.setter
def full_name(self, value):
first_name, last_name = value.split(" ")
self.__first_name = first_name
self.__last_name = last_name # setter方法,假设输入是"firstName lastName"格式
person = Person('Alice', 'Smith')
print(person.full_name) # 输出:Alice Smith
person.full_name = "Bob Johnson" # 通过setter方法更新姓名
print(person.full_name) # 输出:Bob Johnson5.2 多态:同一接口,多种实现5.2.1 多态的原理与应用场景
多态是指同一个接口可以有不同的实现方式,允许我们在调用方法时不关心对象的具体类型,只要对象所属的类支持该方法即可。在Python中,多态主要是通过接口继承和方法重写实现的。
class Animal:
def make_sound(self):
raise NotImplementedError("Subclasses should implement this method.")
class Dog(Animal):
def make_sound(self):
return "Woof!"
class Cat(Animal):
def make_sound(self):
return "Meow!"
def make_animal_sound(animal: Animal):
return animal.make_sound()
animals = [Dog(), Cat()]
for animal in animals:
print(make_animal_sound(animal)) # 输出:Woof! Meow!5.2.2 抽象基类与接口实现
Python引入了abc模块,通过抽象基类(Abstract Base Class, ABC)来强制子类实现特定方法,从而确保子类遵循某种接口契约。抽象基类中的抽象方法使用@abstractmethod装饰器标记。
from abc import ABC, abstractmethod
class Shape(ABC): # 抽象基类
@abstractmethod
def area(self):
pass
class Square(Shape):
def __init__(self, side):
self.side = side
def area(self):
return self.side ** 2
square = Square(5)
print(square.area()) # 输出:25第6章 其他面向对象特性与模式6.1 迭代器与生成器在面向对象编程中的应用6.1.1 实现迭代器协议以支持for循环遍历
Python的for循环可以直接作用于任何实现了迭代器协议的对象。要实现这一协议,类需要提供__iter__方法返回一个迭代器对象,该迭代器对象需具备__next__方法用于产出序列中的下一个元素,并在没有更多元素时抛出StopIteration异常。
class Fibonacci:
def __init__(self, max_terms):
self.max_terms = max_terms
self.current = 0
self.next_ = 1
def __iter__(self):
return self
def __next__(self):
if self.current > self.max_terms:
raise StopIteration
else:
result = self.current
self.current, self.next_ = self.next_, self.current + self.next_
return result
for num in Fibonacci(10):
print(num) # 输出斐波那契数列前10项6.1.2 生成器作为轻量级协程的使用
生成器是一种特殊的迭代器,它使用yield关键字代替return来暂停函数的执行并返回一个值。每次调用__next__时,生成器函数会从上次暂停处继续执行。生成器简化了迭代器的实现,且由于其惰性求值特性,特别适合处理大数据流或无限序列。
def fibonacci(max_terms):
current, next_ = 0, 1
for _ in range(max_terms):
yield current
current, next_ = next_, current + next_
for num in fibonacci(10):
print(num) # 输出斐波那契数列前10项6.2 描述符与属性代理6.2.1 描述符协议与属性访问控制的底层机制
描述符是一种实现了__get__,__set__, 和/或__delete__方法的类。当描述符作为另一个类的属性时,对这个属性的访问会被相应描述符方法接管,从而实现对属性存取行为的精细控制。描述符是Python中属性访问控制的底层机制,@property装饰器、classmethod和staticmethod都是描述符的实例。
class CelsiusDescriptor:
def __init__(self):
self._value = 0
def __get__(self, instance, owner):
return self._value
def __set__(self, instance, value):
if not isinstance(value, (int, float)):
raise TypeError("Temperature must be a number.")
self._value = value
class Temperature:
celsius = CelsiusDescriptor()
temp = Temperature()
temp.celsius = 25 # 调用CelsiusDescriptor.__set__()
print(temp.celsius) # 调用CelsiusDescriptor.__get__()6.2.2 使用@property装饰器实现属性封装
@property装饰器可以将一个方法转化为只读属性,无需调用方法即可访问其返回值。同时,可以为该属性定义对应的setter和deleter方法,从而实现属性的读写和删除操作。这种机制有助于实现属性的封装,同时保持代码的简洁。
class Rectangle:
def __init__(self, width, height):
self.width = width
self.height = height
@property
def area(self):
return self.width * self.height
@area.setter
def area(self, value):
self.width, self.height = sorted([value, self.width * self.height]) # 保持原有长宽比
@area.deleter
def area(self):
self.width = self.height = 0
rect = Rectangle(4, 5)
print(rect.area) # 输出:20
rect.area = ½ # 设置面积,长宽比不变
print(rect.area) # 输出:16
del rect.area # 删除面积,宽高置零第7章 结论
Python面向对象编程(OOP)以其强大的抽象能力和代码复用价值,成为现代软件开发不可或缺的基石。在Python中,类是对现实世界实体的高度抽象,对象则是类的实例化表现,通过属性和方法描述对象的状态与行为。借助class关键字创建类,__init__方法初始化属性,而self关键词在方法调用中起到了链接对象与其方法的关键作用。
继承机制实现了代码的模块化与复用,单继承与多继承拓展了类的功能层次结构,super()函数促进了跨层级方法调用与协作。封装强调隐藏内部实现以暴露清晰的接口,多态允许多个类响应相同的消息,抽象类通过强制子类实现特定方法确保了统一接口。迭代器与生成器为数据流处理提供了便利,描述符则深入底层操控属性存取行为,@property装饰器实现属性封装,提高了代码的整洁度。
领取专属 10元无门槛券
私享最新 技术干货