Python 基础系列 | 第八讲 函数编程

1.为什么需要函数?

  • 假设现在我们有这样一个需求,我们要实现中国移动用户短信通知服务,主要需求如下:
  1. 如果用户话费余额小于10元,则向用户发送余额不足通知短信;
  2. 如果用户流量余量小于20M, 则向用户发送流量不足通知短信;
  3. 如果用户免费短信调小于30条,则向用户发送免费短信条数不足通知短信;
  • 我们实现上述业务需求的解决思路如下:
while Trueif 话费余额 < 10:
        #余额不足通知短信,提醒用户充话费
        建立连接
        发送短信
        关闭连接
    
    if 流量余量 > 20:
        #流量余量不足通知短信,提醒用户充流量
        建立连接
        发送短信
        关闭连接
    
    if 免费短信条数 < 30 :
        #免费短信条数不足通知短信
        建立连接
        发送短信
        关闭连接
  • 仔细观察上述代码,我们发现有很多语句是重复的(if 条件语句下),我们可以把这些语句拿出来作为公用:
def 发送短信(content):
	建立连接
    发送短信
    关闭连接
while Trueif 话费余额 < 10:
		发送短信(“话费余额不足”)
    
    if 流量余量 > 20:
    	发送短信(“流量余量不足”)
    
    if 免费短信条数 < 30 :
        发送短信(“免费短信条数不足”)
  • 可以发现,上述两种解决方案,显然第二种比第一种好,好在如下:

代码量少了(减少了程序员的工作)
提高了代码的重复利用率,避免重复造轮子

2.函数的作用是什么?(函数式编程的好处)

  • 提高了代码的重用性和可读性。

3.函数是什么?

  • 函数是组织好的、可重复使用的,用来实现单一功能的代码段。

4.如何定义函数

def 函数名(形参)
	函数体
	返回值
  • Python 标准库提供给了我们一个内置函数 len(),用来实现计算字符串、元组、列表等对象的长度,接下来,我们实现自己的计算长度的函数,如下:
def my_len(str_obj):
	size = 0
	for x in str_obj:
		size += 1
	return size
  • 函数调用
print(my_len("hello"))
print(my_len("welcome"))

5.函数的参数

5.1 形参与实参

  • 在函数定义的时候,我们声明的参数,称之为形参。
  • 在函数调用的时候,传递的参数,称之为实参。
  • 实参将会通过赋值运算符赋值给形参(具体如何赋,不同情况具有不同的处理方式)

5.2 从实参的角度

5.2.1 位置参数(按位置传参)

  • 按照位置顺序将实参赋值给形参
def print_stu_info(name,age,gender):
	print(name, age, gender)
print_stu_info("zhangsan", 25, "男")
  • 从形参的角度讲,位置参数必须传值,因此也称之为必备参数
def print_stu_info(name,age,gender):
	print(name, age, gender)
print_stu_info() 
# 报错:TypeError: print_stu_info() missing 3 required positional arguments: 'name', 'age', and 'gender'

5.2.2 关键字参数(按关键字传参)

  • 按照关键字传值
def print_stu_info(name,age,gender):
	print(name, age, gender)
print_stu_info(age=26, name="lisi", gender="女")

5.2.3 位置参数和关键字参数混合使用

  • 位置参数必须在关键字参数的前面
  • 一个形参只能被赋值一次
def print_stu_info(name,age,gender):
	print(name, age, gender)
print_stu_info("wangwu", age=30, gender="女") #正确
print_stu_info("wangwu", age=30, "女") # 报错:SyntaxError: positional argument follows keyword argument

5.3 从形参的角度

5.3.1 默认参数

  • 函数定义的时候,给某些形参指定默认值,这种参数则称之为默认参数。
  • 默认参数的使用陷阱: 我们通常在使用默认参数的时候,一定要将其指向不可变的对象,不要赋值为可变类型的对象。避免不符合我们预期的逻辑错误(不是语法错误)
def print_alert_info(device, message=[]):
	message.append("温度过高")
	print("{} 设备告警信息: {}".format(device, message))
	
# 第一次调用
print_alert_info("电饭煲")
# 第二次调用
print_alert_info("微波炉")

5.3.2 可变参数(动态参数)

  • 可变位置参数:多余的位置参数都会由args统一接收,并打包成一个元组对象
def print_stu_info(name, age, gender, *args):
	print(name, age, gender)
	print(args, type(args))
print_stu_info("张三", 20, "男", 175, "50kg", "13435667788")
  • 可变关键字参数: 多余的关键字参数都会由kwargs统一接收,并打包成一个字典对象
def print_stu_info(name, age, gender, **kwargs):
	print(name, age, gender)
	print(kwargs, type(kwargs))
print_stu_info("张三", 20, "男", height=175, weight="50kg", phone="13435667788")
  • 混合使用
def print_stu_info(name, age, gender, *args, **kwargs):
	print(name, age, gender)
	print(args, type(args))
	print(kwargs, type(kwargs))
  • 默认参数、动态参数的定义顺序
def print_stu_info(name, age, gender, *args, weight="50kg", **kwargs):
	print(name, age, gender)
	print(weight)
	print(args, type(args))
	print(kwargs, type(kwargs))

print_stu_info("张三", 20, "男", weight="55kg", height=175, phone="13435667788")
print_stu_info("张三", 20, "男", "55kg", height=175, phone="13435667788") # 不符合预期
print_stu_info("张三", 20, "男", "hello", weight="55kg", height=175, phone="13435667788")
  • 在定义函数的时候,遵循一个原则:位置参数>可变位置参数*args>默认参数>可变关键字参数**kwargs,具体如下:
# 如下函数定义不合理
def print_stu_info(name, age, gender, weight="50kg", *args, **kwargs):
	print(name, age, gender)
	print(weight)
	print(args, type(args))
	print(kwargs, type(kwargs))
# 正确
print_stu_info("张三", 20, "男", "55kg", "hello", height=175, phone="13435667788")
# 报错:TypeError: print_stu_info() got multiple values for argument 'weight'
print_stu_info("张三", 20, "男", "hello", weight="55kg", height=175, phone="13435667788")
# 报错:SyntaxError: positional argument follows keyword argument
print_stu_info("张三", 20, "男", weight="55kg", "world", height=175, phone="13435667788")
  • 总结,我们应按如下方式定义函数参数顺序
def 函数名(参数1,参数2,*args,默认参数,**kwargs):
        """注释:函数功能和参数说明"""
        函数体
        return 返回值

6.函数的返回值

6.1 不写return语句,默认返回

  • 不写return的情况下,会默认返回一个None
  • 写return,后面不跟值,也返回None (作用:一旦遇到return,①可提前结束整个函数;② 可用于调试代码)

6.2 返回一个值

  • 用一个变量接受

6.3 返回多个值

  • 返回的多个值,会被打包成一个元组对象进行返回,因此,如果用一个变量来接受,接受到的就是一个元组对象
  • 也可以用多个变量来接收
  • 注意: 在python中,会把用逗号分割的多个值认为是一个元组对象。
t = 1,2,3
print(t, type(t))

7. Lambda 函数

  • 其设计的目的是为了解决实现一些功能简单的需求,通常就是一句话的逻辑
  • Lamda 函数的定义方法如下:
函数名 = lambda 参数1, 参数2:返回值
add = lambda x,y:x+y
  • Lamda函数的调用同普通函数调用一样
print(add(1,2))

8. 函数的嵌套定义(嵌套函数)

  • 在一个函数内部定义另一函数, 进而出现内部函数与外部函数的概念。
  • 内部函数可以访问外部函数的变量,外部函数不能访问内部函数的变量。
  • 函数的调用必须在函数定义之后。
def func1():
	print("func1")
	def func2():
		print("func2")
	func2()
func1()

9. 变量的作用域

9.1 什么是变量的作用域?

  • 顾名思义,变量的作用域指的是一个变量的作用范围(即某一变量能够在哪些地方是可访问的)。
  • 依据生效范围,通常可以分为全局作用域和局部作用域,对应的变量称之为全局变量和局部变量。

全局作用域:包括内置命名空间、全局命名空间,全局变量在整个文件的任意位置都能够使用
局部作用域:局部命名空间,局部变量只能在局部范围内生效

9.2 命名空间

  • 什么是命名空间?

Python 中的命名空间分为三种:① 全局命名空间;② 局部命名空间;③ 内置命名空间
内置命名空间是python解释器为我们提供的可以直接拿来就用的名字:len,input,print,str,list,tuple 等

  • 不同命名空间的加载顺序?
  1. 内置命名空间在程序运行前加载;
  2. 全局命名空间在程序运行中从上到下加载;
  3. 局部命名空间在程序运行中函数调用时才加载;

9.3 global 关键字

a = "hello"
def foo1():
	a = "welcome"
	print(a)

foo1()

def foo2():
	global a
	global b
	b = "world"
	print(a)
	print(b)
foo2()

9.4 nonlocal 关键字

  1. 外部函数必须有这个变量
  2. 在内部函数声明 nonlocal 变量之前不能再出现同名变量
  3. 内部函数修改这个变量,如果想在外部函数有这个变量的第一层函数中生效,则使用nonlocal
def outter_foo():
	a = "hello"
	def inner_foo1():
		a = "world"
		print("inner_foo1 中访问自己的局部变量a: " + a)
	def inner_foo2():
		print("inner_foo2 中访问外部函数中的变量a: " + a)

	def inner_foo3():
		nonlocal a
		a = "welcome"
		print("inner_foo3 中通过使用nonlocal关键字实现访问外部函数中的变量a: " + a)
	inner_foo1()
	inner_foo2()
	inner_foo3()
	print(a)

outter_foo()

10. 函数的本质

  • 函数名本质弄变量名类似,也是指向具体函数对象所在内存空间
  • 在Python中,函数对象是第一等对象(first-class object), 这意味着如下:
  1. 可作为函数的参数
  2. 可作为函数的返回值
  3. 可存入变量的实体 (可以被引用),如 new_len = len
  4. 可作为容器类型的元素
  5. 可在运行期创建
def func1():
    print('func1')
def func2():
    print('func2')
def fun3():
    print('func3')
funcs = [func1, func2, func3]
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页