(8)揭示Python编程精髓:深潜继承与多态的奇幻之旅

news2024/9/17 9:05:49

目录

  • 1. 命名空间与作用域
    • 1.1 命名空间概述
    • 1.2 作用域
    • 1.2.1 局部作用域
    • 1.2.2 全局作用域
    • 1.2.3 修改全局变量
    • 1.2.4 嵌套作用域
  • 2. 继承
  • 3. 多态(Polymorphism)

1. 命名空间与作用域

1.1 命名空间概述

命名空间是一个从名字到对象的映射,它在Python程序中定义了一系列变量的名称。每个命名空间都是一个字典的实现,虽然字典是直接由用户创建的,但是命名空间的创建和使用完全由解释器来控制。
在这里插入图片描述

1.2 作用域

在Python编程中,作用域(Scope)是指程序中定义变量的区域,决定了变量的可见性和生命周期。它规定了程序中哪些区域能够访问特定的变量名称。

Python中的作用域主要有四种:

  • 内置作用域(Built-in Scope):内置作用域包含了Python内置的函数和异常类,以及内置的函数和异常名(如abs(), int(), list(), Exception等)。这个作用域在Python解释器启动时创建,每个模块都可以访问内置作用域。
    然而,在Python中,我们通常不会直接提及“内置作用域”(Built-in Scope)作为一个独立的作用域级别,尽管技术上内置名称(如内置函数和异常等)确实存在于一个特定的命名空间中。然而,当我们讨论作用域时,我们通常指的是全局作用域、局部作用域和(可能的)嵌套作用域。

  • 局部作用域(Local Scope):局部作用域是在函数或方法内部定义的变量的作用域。函数参数和函数内部定义的变量都属于局部作用域。局部变量在函数调用时创建,在函数返回时销毁。

  • 全局作用域(Global Scope):全局作用域是最外层的命名空间,在模块级别定义的变量属于全局作用域。全局作用域在程序执行时创建,程序的所有模块都可以访问全局作用域中的变量。

  • 嵌套作用域(Enclosing Scope):在嵌套函数中,外部函数定义的变量对内部函数而言是可见的,但仅当内部函数没有定义同名的局部变量时。这个作用域在嵌套函数或类定义时创建。

在Python中,变量的访问遵循LEGB规则,即Local(局部作用域)-> Enclosing(嵌套作用域,如果有的话)-> Global(全局作用域)-> Built-in(内置作用域)。这意味着,在查找一个变量时,Python会首先在当前的作用域中查找,如果找不到,它会向上一级作用域查找,直到找到为止或者引发NameError

需要注意的是,Python中没有块级作用域(Block Scope),也就是说,在ifforwhile语句块中定义的变量,实际上是定义在包含该语句块的函数或模块的全局作用域或局部作用域中。这是与其他一些编程语言(如C++或Java)不同的地方。

1.2.1 局部作用域

在Python中,局部作用域通常指的是在函数内部定义的变量所存在的作用范围。这些变量只能在定义它们的函数内部被访问。当函数被调用时,这些局部变量被创建,并在函数执行完毕后被销毁。

为了说明局部作用域在金融领域的应用,我们可以考虑一个简单的例子:
一个计算复利(Compound Interest)的函数。在这个函数中,我们将使用局部变量来存储如利率(interest rate)、本金(principal amount)、年份(years)和计算结果(future value)等信息。

def calculate_compound_interest(principal, annual_interest_rate, years):
    # 这些变量是局部变量,只能在calculate_compound_interest函数内部访问
    # 假设一年有365天,这是为了简化计算(实际中应考虑闰年等情况)
    days_in_year = 365
    
    # 将年利率转换为日利率
    daily_interest_rate = annual_interest_rate / (100 * days_in_year)
    
    # 使用复利公式计算未来的价值
    future_value = principal * ((1 + daily_interest_rate) ** (days_in_year * years))
    
    # 返回计算结果
    return future_value

# 示例:计算10000元本金在5%年利率下,10年后的复利
principal = 10000
annual_interest_rate = 5
years = 10
result = calculate_compound_interest(principal, annual_interest_rate, years)
print(f"未来的价值是: {result:.2f}元")

在这个示例中,days_in_yeardaily_interest_ratefuture_value都是局部变量。它们在calculate_compound_interest函数内部被定义和使用,并且在函数执行完毕后被销毁。注意,这些变量在函数外部是不可见的(即不能从函数外部直接访问)。这就是局部作用域的基本原理。

1.2.2 全局作用域

全局作用域是整个Python脚本中都可以访问的作用域。在这里,我们将定义全局变量total_investmenttotal_return

示例:假设我们有一个投资组合,我们想要计算其投资回报率(ROI,Return on Investment)。我们可以定义全局变量来存储投资的总金额和回报金额,然后在函数中计算ROI。

# 全局变量
total_investment = 100000  # 初始投资金额为10万
total_return = 15000  # 假设回报金额为1万5

def calculate_roi():
    # 函数内部的计算将在局部作用域中进行
    roi = (total_return / total_investment) * 100  # 计算ROI
    print(f"投资回报率为:{roi}%")

# 调用函数,计算并打印ROI
calculate_roi()

在这个例子中,total_investmenttotal_return是全局变量,它们可以在全局作用域中被任何代码访问。我们在calculate_roi函数内部引用了这两个全局变量来计算ROI。

1.2.3 修改全局变量

如果我们想在函数内部修改全局变量的值,我们需要使用global关键字来声明。但是,在大多数情况下,最好避免在函数内部修改全局变量,因为这可能导致代码更难理解和维护。不过,为了完整解释,我们还是给出一个例子:

# 全局变量
total_investment = 100000  # 初始投资金额为10万
total_return = 15000  # 假设回报金额为1万5

def update_investment_and_return(new_investment, new_return):
    global total_investment, total_return
    total_investment = new_investment  # 更新投资金额
    total_return = new_return  # 更新回报金额
    calculate_roi()  # 重新计算并打印ROI

# 调用函数,更新投资金额和回报金额,并重新计算ROI
update_investment_and_return(120000, 20000)

在这个例子中,我们定义了一个新函数update_investment_and_return,它接受新的投资金额和回报金额作为参数,并使用global关键字声明了要修改的全局变量。然后,它更新了这些全局变量的值,并重新计算了ROI。

1.2.4 嵌套作用域

在Python中,嵌套作用域通常与嵌套函数相关,即一个函数内部定义的另一个函数。在这种情况下,内部函数可以访问其外部函数(即包含它的函数)的局部作用域中的变量,这被称为封闭作用域或外部作用域。

下面是一个使用嵌套作用域和金融示例的Python代码。我们将创建一个计算贷款支付金额的函数,并在其中定义一个嵌套的利率计算函数。

def calculate_monthly_payment(principal, annual_rate, term_years):
    # 将年利率转换为月利率
    def calculate_monthly_rate(annual_rate):
        return annual_rate / 12 / 100
    
    # 嵌套函数内部使用外部函数的变量
    monthly_rate = calculate_monthly_rate(annual_rate)
    
    # 贷款期数(月份)
    total_payments = term_years * 12
    
    # 使用公式计算每月支付金额(这里简化处理,没有包含复杂的还款计算)
    # 注意:这里仅用于示例,真实情况中需使用专门的贷款公式
    monthly_payment = principal * monthly_rate / (1 - (1 + monthly_rate) ** -total_payments)
    
    return round(monthly_payment, 2)  # 保留两位小数

# 示例:计算50,000元的贷款在5%的年利率下,10年期限的每月支付金额
loan_amount = 50000
annual_interest_rate = 5
loan_term = 10
monthly_payment = calculate_monthly_payment(loan_amount, annual_interest_rate, loan_term)
print(f"每月需要支付: {monthly_payment} 元")

在上面的示例中,calculate_monthly_payment 函数是一个外部函数,它接收贷款本金、年利率和贷款期限(年)作为参数。这个函数内部定义了一个嵌套函数 calculate_monthly_rate,用于将年利率转换为月利率。嵌套函数可以访问其外部函数 calculate_monthly_payment 的作用域中的变量 annual_rate。然后,外部函数使用嵌套函数计算出的月利率来计算每月的支付金额,并返回结果。

注意,虽然嵌套函数在这里很有用,但它不是必需的。你也可以直接在 calculate_monthly_payment 函数中编写计算月利率的代码,而不是使用嵌套函数。但是,当逻辑变得更加复杂或者你需要将一部分逻辑封装起来以便在多个地方重用时,嵌套函数就会非常有用。

2. 继承

在Python中,继承是一种面向对象编程的重要特性,它允许我们创建一个新的类(称为子类或派生类),这个类继承自一个或多个已存在的类(称为父类或基类)。子类可以继承父类的属性和方法,并可以添加新的属性和方法或重写父类的方法。

在金融领域,继承可以用于创建不同种类的金融产品类,例如,一个基本的金融产品类可以被继承以创建具体的股票类、债券类、基金类等。下面是一个使用Python继承及金融领域的示例。

# 定义一个基本的金融产品类
class FinancialProduct:
    def __init__(self, name, price):
        self.name = name
        self.price = price
    
    def buy(self):
        print(f"购买了 {self.name},价格为 {self.price} 元。")
    
    def sell(self):
        print(f"出售了 {self.name},价格为 {self.price} 元(仅为示例,实际卖出价格可能不同)。")

# 继承自金融产品类的股票类
class Stock(FinancialProduct):
    def __init__(self, name, price, symbol):
        super().__init__(name, price)  # 调用父类的初始化方法
        self.symbol = symbol  # 股票特有的属性:股票代码
    
    def dividend(self, amount):
        print(f"股票 {self.name} (代码 {self.symbol}) 分红 {amount} 元。")

# 创建一个股票对象并测试其方法
if __name__ == "__main__":
    apple_stock = Stock("苹果公司股票", 150.0, "AAPL")
    apple_stock.buy()
    apple_stock.sell()
    apple_stock.dividend(3.0)

    # 尝试使用基类的方法创建一个普通的金融产品(不是股票)
    bond = FinancialProduct("国债", 100.0)
    bond.buy()
    bond.sell()

在这个例子中,我们定义了一个FinancialProduct类作为基类,它包含了金融产品的一些通用属性和方法,如name(产品名称)、price(产品价格)、buy(购买)和sell(出售)。

然后我们定义了一个Stock类,它继承自FinancialProduct类。Stock类添加了一个额外的属性symbol(股票代码)和一个新的方法dividend(分红)。Stock类的__init__方法调用了父类FinancialProduct__init__方法以设置通用的属性和方法,然后添加了Stock特有的属性。

__main__部分,我们创建了一个Stock对象和一个FinancialProduct对象,并分别调用了它们的方法。这展示了子类如何使用继承来重用父类的代码,并添加自己的特定属性和方法。

3. 多态(Polymorphism)

多态是面向对象编程的三大特性之一(继承、封装和多态),它意味着不同的对象对同一消息做出不同的响应。在Python中,多态性主要通过方法重写(Overriding)和方法重载(Overloading,虽然Python本身不支持传统的函数重载)来实现。

但是,在Python中,我们通常通过定义接口(通过抽象基类实现)或使用鸭子类型(duck typing)来实现多态性。

抽象基类允许你定义接口,子类可以继承这些接口并实现所需的方法。而鸭子类型则是一种动态类型方式,它并不关心对象的类型,只关注对象是否拥有某些方法或属性。

下面是一个使用Python的抽象基类和鸭子类型来展示金融领域多态性的示例:

首先,我们定义一个抽象基类FinancialProduct,它定义了一个计算回报率的接口:

from abc import ABC, abstractmethod
 
class FinancialProduct(ABC):
    @abstractmethod
    def calculate_return(self):
        pass

接着,我们定义两个具体的金融产品类Stock和Bond,它们继承自FinancialProduct并实现了calculate_return方法:

class Stock(FinancialProduct):
    def __init__(self, name, current_price, purchase_price):
        self.name = name
        self.current_price = current_price
        self.purchase_price = purchase_price
    
    def calculate_return(self):
        return (self.current_price - self.purchase_price) / self.purchase_price
 
class Bond(FinancialProduct):
    def __init__(self, name, face_value, coupon_rate, years_to_maturity):
        self.name = name
        self.face_value = face_value
        self.coupon_rate = coupon_rate / 100  # 将百分比转换为小数
        self.years_to_maturity = years_to_maturity
        
    def calculate_return(self):
        # 这里为了简化,我们假设每年回报率是固定的
        return self.coupon_rate

现在我们可以定义一个函数来处理这些金融产品,这个函数不关心产品的具体类型,只要它实现了calculate_return方法即可:

def show_return(product):
    print(f"产品 {product.name} 的回报率为: {product.calculate_return() * 100:.2f}%")

# 创建金融产品实例
stock = Stock("苹果公司股票", 150.0, 100.0)
bond = Bond("五年期国债", 1000.0, 5.0, 5)
 
# 调用函数,展示回报率
show_return(stock)
show_return(bond)

在这个例子中,show_return函数展示了多态性。它接受一个FinancialProduct类型的参数,但实际上可以接受任何实现了calculate_return方法的对象。这就是鸭子类型的体现:如果它走起路来像鸭子(即拥有calculate_return方法),那么我们就可以把它当作鸭子来处理。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1918869.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

小程序多次扫描获取sence失败------ivx

扫码图片被告知侵权了,删除了,如果有需要的同学可以自己尝试。或者直接联系我。 在微信小程序里面有一个函数 wx.getEnterOptionsSync() 功能描述 获取本次小程序启动时的参数。如果当前是冷启动,则返回值与 App.onLaunch 的回调参数一致&am…

【C语言】C语言 学生成绩管理系统(源码+报告)【千行代码】【独一无二】

👉博__主👈:米码收割机 👉技__能👈:C/Python语言 👉公众号👈:测试开发自动化【获取源码商业合作】 👉荣__誉👈:阿里云博客专家博主、5…

SpringCloud架构师面试

一、微服务是什么 1、基本概念 微服务是一种架构风格(区别于单体架构、垂直架构、分布式架构、SOA架构),应用程序被划分为更小的、流程驱动的服务。 2、微服务的特征 轻量化:将复杂的系统或者服务进行纵向拆分,每个…

前端工程化(01):10款自动化构建工具初识。

前端工程化自动化构建工具是用于简化前端开发流程、提高开发效率和优化项目质量的工具。市面上的工具多种多样,贝格前端工场先介绍一下什么是前端工程化,为什么要前端工程化,以及常用工具,后面会对各种工具逐一介绍。 一、什么是…

【计算机组成原理 | 第三篇】各个硬件的组成部分

前言: 在前面的文章中,我们介绍了计算机架构的基本组成。可以知道计算机的基本架构由“存储器”,“运算器”,“控制器”,“输入设备”,“输出设备”这五部分组成。 在这片文章中,我们来深入的了…

文件编码、文件读取 (继续学习!)

1、文件编码 计算机中有许多可用编码: UTF-8(通用编码) GBK(中文体系经常使用) Big5(繁体字经常使用) 1)编码的定义 即规则集合,记录了内容和二进制之间进行相互转…

java的遍历的方法对比 效率对比

在 Java 中,遍历对象的方式主要取决于对象的类型和数据结构。以下是几种常见的遍历方式,以及它们的效率比较: 普通的 for 循环: 效率:高。使用普通的 for 循环可以直接根据索引来访问元素,适用于数组和实现…

软件测试面试题及答案,2024最强版

导读 精选400道软件测试面试真题,高清打印版打包带走,横扫软件测试面试高频问题,涵盖测试理论、Linux、MySQL、Web测试、接口测试、APP测试、Python、Selenium、性能测试、LordRunner、计算机网络、数据结构与算法、逻辑思维、人力资源等模块…

Nginx配置基础

ect/nginx/nginx.conf配置 1)nginx 相关目录 工作目录:ect/nginx 家目录 执行文件:/usr/sbin/nginx 启动或重载 sudo /usr/sbin/nginx -t 检查配置文件 sudo /usr/sbin/nginx -s reload 重启服务 日志文件:/var/log/nginx 启动文…

除2! (题目来源:牛客)

题目来源:牛客网 给一个数组,一共有n个数。 你能进行最多k次操作。每次操作可以进行以下步骤: 选择数组中的一个偶数 a,将其变成a/2。 现在你进行不超过 k 次操作后,让数组中所有数之和尽可能小。请输出这个最小的和。…

虚幻引擎图文笔记:虚幻5(UE5.1.1)无法新建C++项目问题的解决

问题截图: Running E:/Unreal Engine/UE_5.1/Engine/Build/BatchFiles/Build.bat -projectfiles -project"E:/Unreal_Projects/UE5.1/TanChiShe/TanChiShe.uproject" -game -rocket -progress Running UnrealBuildTool: dotnet "..\..\Engine\Binar…

小巧低调的黑盒子,打造个性化音乐体验,欧尼士ONIX Alpha小尾巴上手

欧尼士ONIX的产品很有辨识度,这家来自英国的品牌,有着鲜明的黑金设计色彩,以及低调奢华的质感,当然最重要的是,欧尼士的音质表现非常出色,因此深受音乐爱好者的喜爱。在以手机等设备为载体的流媒体音乐盛行…

视频太大怎么压缩变小?这几种压缩方法值得收藏!

视频太大怎么压缩变小?在数字化浪潮汹涌的时代,处理大型视频文件已不再仅仅是存储空间的挑战,我们身处于数据洪流之中,数据的安全与隐私的保护已然成为了我们不得不面对的重大议题,特别是随着视频内容的井喷式增长及其…

【Java】零散知识--感觉每条都有知识在进入脑子唤起回忆

1,什么是双亲委派 AppClassLoader在加载类时,会向上委派,取查找缓存。 AppClassLoader >>ExtClassLoader >>BootStrapClassLoader 情况一 向上委派时查找到了,直接返回。 情况二 当委派到顶层之后,缓…

【cocos creator】2.x,伪3d拖拽,45度视角,60度视角,房屋装扮

伪3d拖拽,45度视角,60度视角 工程下载:(待审核) https://download.csdn.net/download/K86338236/89530812 dragItem2.t s import mapCreat2 from "./mapCreat2";const {ccclass, property } = cc._decorator; /*** 拖拽类,挂在要拖拽的节点上*/ @ccclass export…

04:定时器

定时器 1、定时器怎么定时2、怎样实现计数?2.1、控制寄存器TCON2.2、工作模式寄存器TCOM2.3、定时器T0 3、案例:通过定时器T0控制LED间隔1s亮灭 当定时器用的时候,靠内部震荡电路数数。当配置为定时器使用时,每经过1个机器周期&am…

【JavaEE】网络编程——UDP

🤡🤡🤡个人主页🤡🤡🤡 🤡🤡🤡JavaEE专栏🤡🤡🤡 文章目录 1.数据报套接字(UDP)1.1特点1.2编码1.2.1DatagramSocket1.2.2DatagramPacket…

数据结构复习计划之复杂度分析(时间、空间)

第二节:算法 时间复杂度和空间复杂度 算法(Algorithm):是对特定问题求解方法(步骤)的一种描述,是指令的有限序列,其中每一条指令表示一个或多个操作。 算法可以有三种表示形式: 伪代码 自然语言 流程图 算法的五…

时间地点双限定|省公派教师喜提香港城市大学访问学者邀请函

X老师的研究方向为图像处理和机器学习,其根据专业特点及外语水平,将访学目标锁定在香港,并要求20天内获得邀请函以申报省公派。我们仅用了10天时间,就获得了香港城市大学的邀请函,且研究方向高度契合,完成了…

Hive的分区表分桶表

1.分区表: 是Hive中的一种表类型,通过将表中的数据划分为多个子集(分区),每个分区对应表中的某个特定的列值,可以提高查询性能和管理数据的效率。分区表的每个分区存储在单独的目录中,分区的定义…