Python的学习-8-函数

函数

函数是可复用的程序代码块。函数的作用,不仅可以实现代码的复用,更能实现代码的一致性。一致性指,只修改函数的代码,则所有调用该函数的地方都能得到体现。

函数的基本概念

  1. 一个程序由一个个人物组成;函数就是代表一个任务或者一个功能
  2. 函数是代码复用的通用机制
python函数的分类

Python中函数分为如下几类:

  1. 内置函数
    我们使用的str(),list()等都是内置函数
  2. 标准库函数
    我们可以通过import语句导入库,然后使用其中定义的函数。这种标准库函数一般是官方提供的,一般是解释器自带的,不需要下载安装。
  3. 第三方库函数
    第三方一般是指除官方提供之外的,高质量的库,需要下载安装。
  4. 用户自定义函数
    用户自定义的函数,满足自身开发需求的函数。

函数的定义和调用

函数定义语法格式:

def  函数名(参数列表):
	"""文档字符串(函数说明)"""
	函数体

核心要点

  1. 使用def定义函数,Python指定def时,创建一个函数对象,并将这个对象绑定到函数变量上。

  2. 参数列表
    (1)圆括号内时形式参数列表,多个参数逗号隔开
    (2)形式参数不需要声明类型,也不需要指定函数返回值类型
    (3)无参数也要保留圆括号
    (4)实参列表必须与形参列表一一对应

  3. return返回值
    (1)函数体中包含return,则结束函数并返回
    (2)函数体中无return,返回None
    (3)要返回多个值,可以使用列表,元组,字典,集合等把要返回的值组合在一起。

  4. 调用函数之前,必须要先定义函数
    (1)内置函数对象会自动创建
    (2)标准库和第三方库通过import导入模块时,会创建函数对象。

形参和实参

def function(var1,var2):
    '''
    文档字符串
    :param var1:
    :param var2:
    :return:
    '''
    print(var1,var2)

function("Hello","World")
help(function.__doc__)

在上面这个函数中function()中,var1和var2是形式参数,他们的作用范围仅仅是在本函数中。在调用函数时,我们在圆括号中书写的内容则是实际参数。形参和实参必须一一对应。

调用help(函数名.doc)可以打印输出函数的文档字符串。

变量

变量的作用域(全局变量和局部变量)

全局变量:
1.在函数和类定义之外声明的变量。作用域为定义的模块,从定义位置开始直到模块结束。
2.全局变量降低了函数的通用性和可用性,尽量避免使用。
3.全局变量一般做常量使用
4.函数内部要改变全局变量的值,使用global声明

局部变量:
1.在函数体(包括形式参数)声明的变量
2.局部变量的引用比全局变量快
3.若局部变量和全局变量同名,则在函数内隐藏全局变量,优先使用局部变量

Python在创建函数对象的时候,同时会在栈中创建一个栈帧,栈帧会用于保存该函数的局部变量名,这些变量名指向堆中的变量值,哈桑农户调用完毕之后,栈帧删除。

在编译原理中,在符号表的章节中有一段关于作用域的内容,感兴趣的可以自行搜索相关信息。

参数的传递

函数的参数传递本质上就是:从实参到形参的赋值操作。Python一切皆对象,所有的赋值操作都是引用的赋值操作。所以python中参数传递都是”引用传递“(也就是地址传递)。
具体操作有两类:

  1. 对”可变对象"进行写操作,直接作用域对象本身
  2. 对”不可变对象“进行"写操作",会产生一个新的"对象空间",并用新的值填充这块空间。(起到值传递的效果,实际上也是地址传递,只不过原地址被覆盖)

可变对象有:
字典,列表,集合,自定义的对象等
不可变对象有:
数字,字符串,元组,函数等

传递可变对象和不可变对象的引用

具体可以看下面的代码。

#传递可变对象的引用
a = [10,20]
def f2(n):
    print("n:",id(n))
    n.append(30)

print("a的ID:",id(a))
f2(a)
print("a的ID:",id(a))
print(a)

b = 100

def f3(n):
    print("n:",id(n))
    n += 200
    print("n:",id(n))
    print(n)
print("B的ID:",id(b))
print(b)
f3(b)
print("B的ID:",id(b))
print(b)

浅拷贝和深拷贝

浅拷贝和深拷贝可以使用内置函数:copy()和deepcopy()。

  • 浅拷贝:不拷贝子对象的内容,只拷贝子对象的引用
  • 深拷贝:连子对象的内存全部拷贝,对子对象的修改不会影响源对象
#测试浅拷贝和深拷贝
import copy

def TestCopy():
    """测试i浅拷贝"""
    print("浅拷贝")
    a = [10,20,[50,60]]
    b = copy.copy(a)
    print("a",a)
    print("b",b)
    print("对子对象b[2]进行操作")
    b.append(30)
    b[2].append(70)
    print("a", a)
    print("b", b)

def TestDeepCopy():
    """测试深拷贝"""
    print("深拷贝")
    a = [10,20,[50,60]]
    b=copy.deepcopy(a)
    print("a:",a)
    print("b:",b)
    print("对子对象b[2]进行操作")
    b.append(80)
    b[2].append(7)
    print("a:", a)
    print("b:", b)

TestCopy()
TestDeepCopy()
"""
浅拷贝
a [10, 20, [50, 60]]
b [10, 20, [50, 60]]
对子对象b[2]进行操作
a [10, 20, [50, 60, 70]]
b [10, 20, [50, 60, 70], 30]
深拷贝
a: [10, 20, [50, 60]]
b: [10, 20, [50, 60]]
对子对象b[2]进行操作
a: [10, 20, [50, 60]]
b: [10, 20, [50, 60, 7], 80]
"""

总结:传递不可变对象时,不可变对象里面包含的子对象是可变对象。若方法内修改了这个可变对象,则源对象也发生变化。

参数的几种类型

位置参数

函数调用时,实参默认按参数列表的位置与形参一一对应,需要个数和顺序都对应。

def f1(a,b,b):
	print(a,b,c)
f1(1,2,3)

默认值参数

在形参列表中对形参进行赋值,就可以设置参数默认值。这个时候默认值参数的位置可以不传递实参。

def f1(a=0,b=0,c=0):
	print(a,b,c)
f1(1,2)
f1()

命名参数

在调用函数的时候,按照形参的名字传递参数,不必遵循位置参数对应原则。

def f1(a,b,c):
	print(a,b,c)
f1(1,2,3)
f1(c=10,a=0,b=5)

可变参数

可变参数指的是“可变数量的参数”。分两种情况:

  1. *param,将多个参数收集到一个元组对象中
  2. **param,将多个参数收集到一个字典对象中
def f1(a,b,*c):
	print(a,b,c)
f1(8,9,19,20,21)
#  8 9 (19, 20, 21)
def f2(a,b,**c):
	print(a,b,c)
f2(8,9,name="rain",age=19)
#  8 9 {'name': 'rain', 'age': 19}
强制命名参数

在带*的可变参数后面增加新的参数,必须是命名参数。因为从逻辑上来说,不指明参数的传递,那么第一个的可变参数就不知道药将哪几个参数组合在一起。

def f1(*a,b,c):
	print(a,b,c)

f1("%","$",b=1,c=3)
#    ('%', '$') 1 3

lambda表达式和匿名函数

lamnda表达式可以用来声明匿名函数。
lambda函数是一种简单的,在同一行中定义函数的方法。
lamda函数实际生成了一个函数对象。
lamda表达式只允许包含一个表达式,不能包含复杂语句,该表达式的计算结果就是函数的返回值。
lambda表达式的基本语法如下:
lambda arg1,arg2,arg3 : <表达式>
arg1/arg2/arg3为函数的参数。<表达式>相当于函数体。

f = lambda a,b,c :a+b+c
print(f)
print(f(1,2,3))

g=[lambda a: a*2,lambda b :b**2]
print(g[0](1),g[1](1))
"""结果
<function <lambda> at 0x000001BF5FF7F040>
6
2 1
"""

eval函数

功能:将字符串str当成有效的python表达式来求职并返回计算结果
语法:eval(source,global,locals )
参数:

  • source:一个Python表达式或函数compile()返回的代码对象
  • globals:可选。必须是dictionary
  • locals:可选。任意映射对象
s="print('Hello World')"
eval(s)

a=10
b=20
c = eval("a+b")
print(c)

dict = dict(a=100,b=200)
d=eval("a+b")
print(d)
d=eval("a+b",dict)
print(d)

递归函数

递归函数就是:自己调用自己的函数。
每个递归函数包含两个部分:

  • 终止条件
    表示递归什么时候结束。
  • 递归步骤
    把第n步和第n-1步相关联

递归在算法涉及和分析中是一种很重要的解决思路。

LEGB规则

Python在查找变量名时,按照LEGB规则去寻找
Local→Enclosed→Global→Built in

  • Local:指的是函数或者类的方法内部
  • Enclosed:指的是嵌套函数
  • Global:指的是模块中的全局变量
  • Built in:指的是Python为自己保留的特殊名称
# 可以自行对不同的str注释之后查看效果
str = "global"
def outer():
    str="outer"
    def inner():
        str="inner"
        print(str)
    inner()
outer()
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值