Python 编程导论 Chapter 4 —— 函数、作用域与抽象

本文深入探讨Python编程中的函数、作用域和抽象概念。详细讲解了函数定义、关键字参数和默认值、作用域规则,通过递归阐述了斐波那契数列和回文检测的应用,并讨论了全局变量、模块以及文件操作的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


typora-copy-images-to: Risk Management and Financial Institution


typora-copy-images-to: Python 编程导论

Python 编程导论 Chapter 4 函数、作用域与抽象


  • 函数的作用是为了代码的通用性
  • 使Python可以更容易地扩展和重用代码

4.1 函数与作用域

4.1.1 函数定义
def name of function (list of formal parameters):
    body of function

def maxVal(x,y) :
    if x > y:
        return x
    else:
        return y
# x,y 在本例中是形式参数
# return 语句只能用在函数体中。

当函数被调用的时候,执行如下过程:
1. 构成实参的表达式被求值
2. 执行点从调用点转到函数体的第一条语句
3. 执行函数体中的代码,直到遇到return语句,此时,return后面的表达式就是此次调用函数的值,或者没有语句可以继续执行,此时函数返回值None
4. 这次函数调用的值就是返回值
5. 执行点移动到紧跟在这次函数调用后面的代码

# 实际练习:编写一个函数isIn,接受两个字符串作为参数,如果一个字符串是另一个字符串
# 的一部分,返回True,否则返回False。提示:你可以使用内置的str类型的操作符in。
def isin(x,y):
    if str(x) in str(y):
        return True
    else:
        return False

print(isin('name','names'))    
4.1.2 关键字参数和默认值
  • 两种方式可以将形参绑定到实参
    • 位置参数
    • 关键字参数
def printName(firstName, lastName, reverse = False):
    if reverse:
        print(f'{lastName} , {firstName}')
    else:
        print(firstName, lastName)
# ,但将关键字参数放在非关键字参数后面是不合法的

# 如:printName('Olga', lastName = 'Puchmajerova', False)
# 关键值经常与默认参数值结合使用
4.1.3 作用域
def f(x): #name x used as formal parameter
    y = 1
    x = x + y
    print('x =', x)
    return x


x = 3
y = 2
z = f(x)     #value of x used as actual parameter
print('z =', z)
print('x =', x)
print('y =', y)

# 每一个函数都定义了一个命名空间,也称为作用域
函数体中的赋值语句x = x + y将局部名称x绑定到对象4。f中的赋值语句根本不会影响f作用域之外的名称x和y的绑定

  • 作用域的理解:
  • 最顶层,shell层,用来记录这一层所有名称定义和它们当前的绑定
  • 调用函数时,建立新的符号表(栈帧),记录函数中所有名称定义,如果函数中又调用了一个函数 ,就再建立一个栈帧
  • 函数结束,栈帧随之消失
def f(x):
	def g():
		x = 'abc'
		print('x =', x)
	def h():
		z = x
		print('z =', z)
	x = x + 1
	print('x =', x)
	h()
	g()
	print('x =', x)
	return g

x = 3
z = f(x)
print('x =', x)
print('z =', z)
z()

输出:
x = 4
z = 4
x = abc
x = 4
x = 3
z = <function f.<locals>.g at 0x1092a7510>
x = abc

![1554214543494](C:\Users\James\Desktop\卢奕学习笔记以及博客\博客\Python 编程导论\1554214543494.png)

  • 引用名称时,顺序并不重要。只要在函数体内任何地方有对象与名称进行绑定(即使在名称作为赋值语句左侧项之前,就已经出现在某个表达式中),就认为这个名称是函数的局部变量
def f():
	print(x)
def g():
	print(x)
	x = 1
x = 3
f()
x = 3
g()
# 调用函数g时,出现UnboundLocalError: local variable 'x' referenced before assignment的错误

4.2 规范

def findRoot(x, power, epsilon):
	"""x和epsilon是整数或者浮点数,power是整数
		epsilon>0 且power>=1
		如果y**power和x的差小于epsilon,就返回浮点数y,
		否则返回None"""
	if x < 0 and power%2 == 0: #Negative number has no even-powered
#roots
		return None
	low = min(-1.0, x)
	high = max(1.0, x)
	ans = (high + low)/2.0
	while abs(ans**power - x) >= epsilon:
		if ans**power < x:
			low = ans
		else:
			high = ans
		ans = (high + low)/2.0
	return ans

def testFindRoot():      # 测试代码
	epsilon = 0.0001
	for x in [0.25, -0.25, 2, -2, 8, -8]:
		for power in range(1, 4):
			print('Testing x =', str(x), 'and power = ', power)
			result = findRoot(x, power, epsilon)
			if result == None:
				print(' No root')
			else:
				print(' ', result**power, '~=', x)
  • 函数的规范定义了函数编写者与使用者之间的约定。我们将函数使用者称为客户。可以认为约定包括以下两部分
    • 假设:客户使用函数必须满足的前提条件,通常是对实参的限制
    • 保证:函数实现的功能

4.3 递归

  • 递归是一种描述性方法

  • 递归定义包括两部分:

    • 一种基本情形可以直接得出某种特定情形的结果
    • 一种递归情形(归纳情形),定义了该问题再其它情形下的结果
  • 例如:

    1. 任何在美国境内出生的儿童;
    2. 在美国境外出生的婚生儿童,父母是美国公民,并且双亲之一在孩子出生前在美国居住过;
    3. 在美国境外出生的婚生儿童,双亲之一是美国公民,他(她)在孩子出生前至少在美国居住5年,且其中至少2年是在其14岁生日之后
# 阶乘的递归实现
def factR(n):
""""假设n是正整数
	返回n!""" 
	if n == 1:
		return n
	else:
		return n*factR(n - 1)
    
# 通过在factR函数体内调用factR,递归终究会在factR(1)时结束    
    
    
# 阶乘的迭代实现
def factI(n):
    """假设n是正整数
       返回 n!"""
    result = 1
    while n > 1:
        result = result * n
        n -= 1
    return result
4.3.1 斐波那契数列
# 斐波那契数列的递归实现
def fib(n):
	"""假定n是正整数
		返回第n个斐波那契数"""
	if n == 0 or n == 1:
	return 1
	else:
	return fib(n-1) + fib(n-2)

def testFib(n):
	for i in range(n+1):
		print('fib of', i, '=', fib(i))
  • 找到某种抽象方式表示问题的解,常常是编程过程中最困
    难的部分
4.3.2 回文
  • 递归经常用于非数值的问题中
# 定义函数 isPalinrome,检查一个字符串在顺读和倒读时是否一致
# 其中包含两个辅助函数 toChars 和 isPal
toChars 函数将所有字母转换为小写,并且移除所有非字母字符
isPal 使用递归完成实际工作
def isPalindrome(s):
	"""假设s是字符串
		如果s是回文字符串则返回True,否则返回False。
		忽略标点符号、空格和大小写。"""
	def toChars(s):
		s = s.lower()
		letters = ''
		for c in s:
			if c in 'abcdefghijklmnopqrstuvwxyz':
				letters = letters + c
		return letters
	def isPal(s):
		if len(s) <= 1:
			return True
		else:
			return s[0] == s[-1] and isPal(s[1:-1])
	return isPal(toChars(s))
当两个布尔值表达式通过and连接时,每个表达式被称为合取项。如果它们是通过or连接的,那么被称为分取项

4.4 全局变量

  • 定义:告诉Python,某一名称是定义在代码所在函数外层的模块作用域中的,而不是代码所在函数的作用域中的,否则就会被认为是局部变量
def fib(x):
    """假设x是正整数
        返回第x个斐波那契数"""
    global numFibCalls
    numFibCalls += 1
    if x == 0 or x == 1:
        return 1
    else:
        return fib(x-1) + fib(x-2)

def testFib(n):
	for i in range(n+1):
		global numFibCalls
		numFibCalls = 0
		print('fib of', i, '=', fib(i))
		print('fib called', numFibCalls, 'times.')

4.5 模块

  • 多人合作编写同一程序,那么试图更新同一个文件时,会很困难
# 创建一个circle.py的 文件
pi = 3.14159
def area(radius):
	return pi*(radius**2)
def circumference(radius):
	return 2*pi*radius
def sphereSurface(radius):
	return 4.0*area(radius)
def sphereVolume(radius):
	return (4.0/3.0)*pi*(radius**3)
  • 模块通常保存在单独的文件中
  • 乍看上去,使用点标记法有些麻烦。但换个角度想想,当我们导入一个模块时,根本不知道
    这个模块在实现时使用了哪些局部名称。使用点标记法可以充分限定变量名,避免名称冲突造成程序损害的可能性

4.6 文件

  • Python通过文件句柄处理文件,实现了操作系统的独立性
nameHandle = open('kids', 'w')
nameHandle.write('Michael\n')
nameHandle.write('Mark\n')
nameHandle.close()
nameHandle = open('kids', 'r')
for line in nameHandle:
	print(line[:-1])
nameHandle.close()

# 打开文件的方式参数,“a”追加,“w”写入,“r”读取

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值