Python万字长文基础教程第五章:面向对象编程

向量数据库大模型云通信

picture.image

点击上方蓝字关注我们

picture.image

picture.image

小编已经为大家准备好Python万字长文基础教程学习资料,进入公众号点击下方Python菜单可以直接获取!!!

picture.image

第5章 面向对象编程

面向对象编程(OOP)是一种强大的编程范式,它将数据和操作数据的方法组织到对象中。本章将深入探讨Python中的面向对象编程概念,包括类和对象、继承和多态、以及封装和抽象。通过学习这些概念,读者将能够设计更加模块化、可重用和易于维护的代码。

5.1 类和对象

类和对象是面向对象编程的基础。类是对象的蓝图,定义了对象的属性和方法,而对象是类的实例。本节将介绍如何在Python中定义和使用类,以及如何创建和操作对象。

在Python中,使用class关键字定义类。类可以包含属性(数据)和方法(函数)。创建类的实例称为实例化,通过调用类名并传递必要的参数来完成。每个对象都有自己的属性集,可以调用类中定义的方法。

以下是一个简单的Car类的示例:

  
class Car:  
    def \_\_init\_\_(self, make, model, year):  
        self.make = make  
        self.model = model  
        self.year = year  
        self.odometer\_reading = 0  
      
    def get\_descriptive\_name(self):  
        long\_name = f"{self.year} {self.make} {self.model}"  
        return long\_name.title()  
      
    def read\_odometer(self):  
        print(f"This car has {self.odometer\_reading} miles on it.")  
      
    def update\_odometer(self, mileage):  
        if mileage >= self.odometer\_reading:  
            self.odometer\_reading = mileage  
        else:  
            print("You can't roll back an odometer!")  
  
# 创建Car类的实例  
my\_car = Car("audi", "a4", 2019)  
print(my\_car.get\_descriptive\_name())  
my\_car.read\_odometer()  
  
# 更新里程数  
my\_car.update\_odometer(23500)  
my\_car.read\_odometer()

在这个例子中,Car类定义了汽车的基本属性(品牌、型号、年份和里程表读数)和一些方法。__init__方法是一个特殊的方法,称为构造函数,它在创建对象时自动调用,用于初始化对象的属性。

get_descriptive_name方法返回格式化的字符串,描述汽车的基本信息。read_odometer方法打印当前的里程表读数,而update_odometer方法允许更新里程表读数,同时防止里程表被回拨。

创建Car类的实例后,可以访问其属性(如my_car.make)和调用其方法(如my_car.get_descriptive_name())。这展示了对象的基本操作。

除了实例方法,Python还支持类方法和静态方法。类方法使用@classmethod装饰器,可以访问类属性但不能访问实例属性。静态方法使用@staticmethod装饰器,不能访问类属性或实例属性,通常用于实现与类相关但不依赖于类状态的功能。

本节介绍了Python中类和对象的基本概念和用法。通过定义类,可以创建具有特定属性和行为的对象。类提供了一种组织代码的方式,使得代码更加模块化和易于理解。掌握类和对象的概念是深入学习面向对象编程的基础。

5.2 继承和多态

继承和多态是面向对象编程的两个核心概念。继承允许创建一个新类,基于现有的类,而多态允许使用统一的接口来操作不同类型的对象。本节将探讨如何在Python中实现继承和多态,以及它们如何增强代码的可复用性和灵活性。

继承允许定义一个类,该类继承另一个类的属性和方法。被继承的类称为父类或基类,而继承的类称为子类或派生类。子类可以重写父类的方法,也可以添加新的属性和方法。

以下是一个展示继承的示例,基于之前的Car类:

  
class ElectricCar(Car):  
    def \_\_init\_\_(self, make, model, year, battery\_size):  
        super().\_\_init\_\_(make, model, year)  
        self.battery\_size = battery\_size  
      
    def describe\_battery(self):  
        print(f"This car has a {self.battery\_size}-kWh battery.")  
      
    def update\_odometer(self, mileage):  
        print("Electric cars don't have traditional odometers.")  
        super().update\_odometer(mileage)  
  
# 创建ElectricCar实例  
my\_tesla = ElectricCar("tesla", "model s", 2019, 75)  
print(my\_tesla.get\_descriptive\_name())  
my\_tesla.describe\_battery()  
my_tesla.update_odometer(10000)

在这个例子中,ElectricCar类继承自Car类。super().__init__(make, model, year)调用父类的构造函数来初始化从Car类继承的属性。ElectricCar类添加了一个新的battery_size属性和describe_battery方法,同时重写了update_odometer方法以适应电动车的特性。

Python支持多重继承,允许一个类继承多个父类。但这需要谨慎使用,因为它可能导致复杂的继承层次结构和命名冲突。

多态性允许使用一个统一的接口来操作不同类型的对象。在Python中,多态性是通过"鸭子类型"实现的:如果一个对象具有特定的方法,就可以在需要该方法的地方使用它,而不管它的实际类型是什么。

以下是一个展示多态性的示例:

  
def describe\_vehicle(vehicle):  
    print(vehicle.get\_descriptive\_name())  
    vehicle.read\_odometer()  
  
# 使用不同类型的对象调用相同的函数  
my\_car = Car("toyota", "camry", 2020)  
my\_tesla = ElectricCar("tesla", "model 3", 2021, 80)  
  
describe\_vehicle(my\_car)  
describe\_vehicle(my\_tesla)

在这个例子中,describe_vehicle函数可以接受任何具有get_descriptive_nameread_odometer方法的对象。这展示了多态性的强大之处:可以编写更通用、更灵活的代码。

除了继承,Python还支持组合,即在一个类中包含其他类的实例作为属性。组合通常优于继承,因为它提供了更好的灵活性和更松散的耦合。

继承和多态是面向对象编程的强大工具,它们提高了代码的可重用性和灵活性。继承允许基于现有类创建新类,而多态性使得可以用统一的方式处理不同类型的对象。正确使用这些概念可以创建更加模块化、可维护的代码结构。

5.3 封装和抽象

封装和抽象是面向对象编程的重要概念,它们有助于创建更安全、更易于使用的代码。封装通过限制对对象内部细节的访问来保护数据,而抽象则通过隐藏复杂的实现细节来简化接口。本节将探讨如何在Python中实现封装和抽象。

封装是将数据和操作数据的方法绑定在一起的概念,同时限制对某些组件的直接访问。在Python中,可以使用双下划线前缀来创建私有属性和方法,这是实现封装的一种方式。

以下是一个展示封装的示例:

  
class BankAccount:  
    def \_\_init\_\_(self, owner, balance=0):  
        self.\_\_owner = owner  
        self.\_\_balance = balance  
      
    def deposit(self, amount):  
        if amount > 0:  
            self.\_\_balance += amount  
            print(f"Deposited ${amount}. New balance: ${self.\_\_balance}")  
        else:  
            print("Invalid deposit amount")  
      
    def withdraw(self, amount):  
        if 0 < amount <= self.\_\_balance:  
            self.\_\_balance -= amount  
            print(f"Withdrew ${amount}. New balance: ${self.\_\_balance}")  
        else:  
            print("Invalid withdrawal amount or insufficient funds")  
      
    def get\_balance(self):  
        return self.\_\_balance  
  
# 使用BankAccount类  
account = BankAccount("Alice", 1000)  
account.deposit(500)  
account.withdraw(200)  
print(f"Current balance: ${account.get\_balance()}")  
  
# 尝试直接访问私有属性(这将失败)  
# print(account.\_\_balance)  # 这行会抛出AttributeError

在这个例子中,__owner__balance是私有属性,不能从类外部直接访问。通过提供depositwithdrawget_balance方法,类控制了对这些属性的访问,确保了数据的完整性和安全性。

Python还提供了属性装饰器,它们提供了一种更优雅的方式来实现getter和setter方法:

  
class Temperature:  
    def \_\_init\_\_(self, celsius=0):  
        self.\_celsius = celsius  
      
    @property  
    def celsius(self):  
        return self.\_celsius  
      
    @celsius.setter  
    def celsius(self, value):  
        if value < -273.15:  
            raise ValueError("Temperature below absolute zero is not possible")  
        self.\_celsius = value  
      
    @property  
    def fahrenheit(self):  
        return (self.celsius * 9/5) + 32  
      
    @fahrenheit.setter  
    def fahrenheit(self, value):  
        self.celsius = (value - 32) * 5/9  
  
# 使用Temperature类  
temp = Temperature(25)  
print(f"Celsius: {temp.celsius}, Fahrenheit: {temp.fahrenheit}")  
temp.fahrenheit = 77  
print(f"Celsius: {temp.celsius}, Fahrenheit: {temp.fahrenheit}")

在这个例子中,@property装饰器创建了一个getter方法,而@celsius.setter创建了一个setter方法。这允许像访问普通属性一样访问celsiusfahrenheit,同时仍然可以控制它们的行为。

抽象是通过隐藏复杂的实现细节来简化接口的过程。Python提供了abc(Abstract Base Classes)模块来创建抽象类和方法。抽象类不能被实例化,它们的目的是为子类定义一个共同的接口。

以下是一个使用抽象类的示例:

  
from abc import ABC, abstractmethod  
  
class Shape(ABC):  
    @abstractmethod  
    def area(self):  
        pass  
      
    @abstractmethod  
    def perimeter(self):  
        pass  
  
class Rectangle(Shape):  
    def \_\_init\_\_(self, width, height):  
        self.width = width  
        self.height = height  
      
    def area(self):  
        return self.width * self.height  
      
    def perimeter(self):  
        return 2 * (self.width + self.height)  
  
class Circle(Shape):  
    def \_\_init\_\_(self, radius):  
        self.radius = radius  
      
    def area(self):  
        return 3.14159 * self.radius ** 2  
      
    def perimeter(self):  
        return 2 * 3.14159 * self.radius  
  
# 使用Shape子类  
rect = Rectangle(5, 3)  
circ = Circle(2)  
  
shapes = [rect, circ]  
for shape in shapes:  
    print(f"Area: {shape.area()}, Perimeter: {shape.perimeter()}")

在这个例子中,Shape是一个抽象基类,定义了所有形状都应该实现的方法。RectangleCircle类继承自Shape并实现了这些方法。这样可以确保所有的Shape子类都有一致的接口,同时允许每个子类有自己的实现。

封装和抽象是创建稳健、易维护的面向对象代码的关键概念。封装通过限制对对象内部状态的直接访问来保护数据完整性,而抽象则通过定义清晰的接口来简化复杂性。正确运用这些概念可以创建出更加模块化、安全和易于使用的代码。

picture.image

点击下方公众号获取更多学习及项目资料:

大家好,我是呈予贝,专注于C/C++、Python、自动驾驶开发。探索AI在自动驾驶领域的新应用,并致力于分享有关AI和AIGC(人工智能生成内容)的相关知识。

0
0
0
0
关于作者
关于作者

文章

0

获赞

0

收藏

0

相关资源
大规模高性能计算集群优化实践
随着机器学习的发展,数据量和训练模型都有越来越大的趋势,这对基础设施有了更高的要求,包括硬件、网络架构等。本次分享主要介绍火山引擎支撑大规模高性能计算集群的架构和优化实践。
相关产品
评论
未登录
看完啦,登录分享一下感受吧~
暂无评论