器 | python函数

222 阅读4分钟

这是我参与更文挑战的第5天,活动详情查看: 更文挑战

函数的出现是为了提高应用的模块性,和代码的重复利用率。

1.概念

函数标准结构如下:

def <函数名> (<函数参数>):
    <代码块>
    return <返回表达式,可不返回>

2.参数传递

2.1 变量&对象

python 中,变量是没有类型,只有对象有类型

a = 'stone'
list= [1,2,3]

上面代码中,'stone'String类型,[1,2,3]List类型,而变量alist只是对一个对象的应用,相当于C语言中的指针,也就是说,a可以指向一个String类型,可以指向List类型,也可以指向其它类型。

2.2 可变对象和不可变对象

python变量保存的是对象的引用,这个引用指向堆内存里的对象,在堆中分配的对象分为两类,一类是可变对象,一类是不可变对象。

众所周知,Python3 的六个标准对象类型中:

  • **不可变对象类型(3 个):**Number(数字)、String(字符串)、Tuple(元组);
  • **可变对象类型(3 个):**List(列表)、Dictionary(字典)、Set(集合)。

对于不可变对象,即变量指向的内存的中的值不能够被改变

int_val=5 
int_val=10

如上两行代码,第一行代码让变量int_val指向堆上新开辟的空间整数5,第二行代码在堆上开辟新的空间存储整数10,让变量int_val指向新开辟的空间,原来存储整数5堆空间的内容没有改变,这即是不可变

可通过内置函数id(int_val)打印两次内存空间地址,可以看到两次地址值不一样

对于可变对象,即变量指向的内存的中的值能够被改变

list_val=[1,2,3]
list_val[1]=4

如上两行代码,列表list_val 可改变,直接改变指向的内存中的值,没开辟新空间,这即是可变

可通过内置函数id(list_val)打印两次内存空间地址,可以看到两次地址值是不一样

2.3函数传参

python规定参数传递都是传递引用,也就是传递给函数的是原变量实际所指向的内存空间,修改的时候就会根据该引用的指向去修改该内存中的内容。

通过以下的代码讲解:

#函数体修改参数内容
def val_change(int_val,str_val,list_val):
    int_val = int_val+1
    str_val = str_val + 'd'
    list_val[1] = 1
    return int_val, str_val, list_val
#调用函数
int_a = 1
str_a = 'ac'
list_a = [0, 0]
[int_b, str_b, list_b] = val_change(int_a, str_a, list_a)
print('int_a = ', int_a)
print('int_b = ', int_b)
print('str_a = ', str_a)
print('str_b = ', str_b)
print('list_a = ', list_a)
print('list_b = ', list_b)

输出结果

int_a =  1
int_b =  2
str_a =  ac
str_b =  acd
list_a =  [0, 1]
list_b =  [0, 1]

通过上面例子,可以得出结论:

  1. 对于函数参数是不可变对象,函数体对该对象的修改时,修改的是复制的对象,不会影响函数外部的参数
  2. 对于函数参数是可变对象,函数体对该对象的修改会直接影响到函数外部的参数

3.迭代器和生成器

3.1迭代器

迭代器是一个可以记住遍历的位置的对象。迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。

使用方式

  1. iter(<可迭代对象>)创建迭代器对象,可迭代对象包括字符串列表元组对象,或者自定义迭代对象
  2. next(<迭代器对象>),迭代器的下一个元素

具体使用步骤:

list =[1,2,3]
iterator = iter(list) # 创建跌迭代器对象
print(next(iterator)) # 打印迭代器的下一个元素,输出1

注意

使用内置函数next(),可能出现StopIteration异常,这个异常用于标识迭代的完成,防止出现无限循环的情况。

自定义迭代器对象

把一个类作为一个迭代器使用需要在类中实现两个方法 __iter__()__next__()

3.2生成器

使用了 yield 的函数被称为生成器,生成器是一个返回迭代器的函数,只能用于迭代操作,可以理解为生成器就是迭代器。调用一个生成器函数,返回的是一个迭代器对象。

原理

在调用生成器运行的过程中,每次遇到 yield 时函数会暂停并保存当前所有的运行信息,返回 yield 的值, 并在下一次执行 next() 方法时从当前位置继续运行

使用方式

见如下代码

#自定义一个支持浮点数的rangedef custom_range(start,end,step):    x = start    while x < end:        yield x        x += step
#使用生成器,与用迭代器无异for i in range(1,10,0.5):    print(i)

4.lambda

使用 lambda 来创建匿名函数

使用方式

#不使用lambdadef add(x,y):    return x+y
#使用lambdaadd=lambda  x,y:x+y

5.作用域

定义在函数内部的变量拥有一个局部作用域,定义在函数外的拥有全局作用域。global关键字申明使用全局作用于的变量。

通过以下例子讲解:

count = 0 #全局变量index = 0 #全局变量def count_num():    global count#全局变量    count += 1    index = 2#局部变量    print('in function ', count, index)    count_num()print('out function ', count, index)

输出

in function  1 2out function  1 0

6.深入浅出函数参数

下载.jpg