目录
- 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),也就是说,在if
、for
或while
语句块中定义的变量,实际上是定义在包含该语句块的函数或模块的全局作用域或局部作用域中。这是与其他一些编程语言(如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_year
、daily_interest_rate
和future_value
都是局部变量。它们在calculate_compound_interest
函数内部被定义和使用,并且在函数执行完毕后被销毁。注意,这些变量在函数外部是不可见的(即不能从函数外部直接访问)。这就是局部作用域的基本原理。
1.2.2 全局作用域
全局作用域是整个Python脚本中都可以访问的作用域。在这里,我们将定义全局变量total_investment
和total_return
。
示例:假设我们有一个投资组合,我们想要计算其投资回报率(ROI,Return on Investment)。我们可以定义全局变量来存储投资的总金额和回报金额,然后在函数中计算ROI。
# 全局变量
total_investment = 100000 # 初始投资金额为10万
total_return = 15000 # 假设回报金额为1万5def calculate_roi():# 函数内部的计算将在局部作用域中进行roi = (total_return / total_investment) * 100 # 计算ROIprint(f"投资回报率为:{roi}%")# 调用函数,计算并打印ROI
calculate_roi()
在这个例子中,total_investment
和total_return
是全局变量,它们可以在全局作用域中被任何代码访问。我们在calculate_roi
函数内部引用了这两个全局变量来计算ROI。
1.2.3 修改全局变量
如果我们想在函数内部修改全局变量的值,我们需要使用global
关键字来声明。但是,在大多数情况下,最好避免在函数内部修改全局变量,因为这可能导致代码更难理解和维护。不过,为了完整解释,我们还是给出一个例子:
# 全局变量
total_investment = 100000 # 初始投资金额为10万
total_return = 15000 # 假设回报金额为1万5def update_investment_and_return(new_investment, new_return):global total_investment, total_returntotal_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 = nameself.price = pricedef 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, abstractmethodclass FinancialProduct(ABC):@abstractmethoddef calculate_return(self):pass
接着,我们定义两个具体的金融产品类Stock和Bond,它们继承自FinancialProduct并实现了calculate_return方法:
class Stock(FinancialProduct):def __init__(self, name, current_price, purchase_price):self.name = nameself.current_price = current_priceself.purchase_price = purchase_pricedef calculate_return(self):return (self.current_price - self.purchase_price) / self.purchase_priceclass Bond(FinancialProduct):def __init__(self, name, face_value, coupon_rate, years_to_maturity):self.name = nameself.face_value = face_valueself.coupon_rate = coupon_rate / 100 # 将百分比转换为小数self.years_to_maturity = years_to_maturitydef 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方法),那么我们就可以把它当作鸭子来处理。