赞
踩
def function(参数1,参数2……):
‘’‘函数的功能简介’‘’
//函数代码块
a = func()
注意:一定不要弄混淆这几个概念。
函数对象,是python中的一个对象,包括对象的3要素:id,type、value;函数对象,是在解释器启动的时候,已经存放到内存空间,存在的是函数的代码部分,并没有存储数值。
函数调用,是指调用函数,开始执行,并为函数的数据分配栈内存空间,当函数执行完后,分配的数据也销毁。
函数调用中,注意参数是可变对象还是不可变对象。如果是可变对象,函数内的操作会影响原有可变对象,如果是不可变对象,对原来传入的不可变对象没有影响,因为不可变对象会创建新的对象,并不会影响原来的不可变对象。
# 是指b和a同时都指向函数对象
func()
ref_func = func
a = func() # 函数执行完后,用a来接收func()调用后的执行结果
def func(x, y, z):
// 代码块
def func(name, age, city="bj"):
// 代码块
# 调用有默认参数的函数
func("Kitty", 18, city="nj") //city=“nj”会覆盖默认取值bj
func("Mike", 20, "sh") // city="sh"会覆盖默认取值bj
def func(*args, **kwargs):
// 代码块
def func(city="bj", age=6):
// 代码块
- def func_test(alist=[]):
- alist.append("END")
- return alist
-
- print(func_test())
- >> ["END"]
-
- print(func_test())
- >> ["END", "END"]
为什么会出现这种情况呢?
函数有__defaults__和__name__等内置变量,在定义一个函数后,内存中会分配函数代码,但并没有分配函数的数据,其中内存中分配了函数的__default__等变量;当调用一个函数,会为该调用的函数分配栈空间,函数执行完成,栈内存空间会被释放。
对于__defaults__中存储的变量,函数调用会更改__defaults__的值,但并没有销毁这部分取值。
而默认变量就存储在__defaults__变量中。
4.6.1、默认参数,参数尽量为不可变对象,否则会造成每次使用,会得到不同的结果。
这里涉及到函数的内存分配。
python中内存分配交给python解释器,函数定义中,会在内存空间中分配空间,包括函数的定义,以及函数的__name__、__defaults__等变量,都在内存中,这里只分配了函数的代码,并没有为函数的数据分配内存空间;当函数被调用,函数的引用会分配新的栈空间,函数执行完后,函数的栈销毁,但此时函数内存中的函数定义,以及函数的__name__、__defaults__变量一直都在,如果函数的调用修改了__name__或__defaults__,会影响函数每次的返回结果。
而默认参数,就是分配在__defaults__所指的内存空间中,是在函数定义中就已被分配,如果是可变对象,会每次都更改__defaults__的取值,可能会影响函数每次执行的结果。
4.6.2、参数传递是引用传递
在调用函数的时候,会从实参传递给形参,参数传递只有引用传递。
如果参数是不可变对象,比如数、字符串、元组,参数传递后,并没有分配新的对象,只是新增了一个对象的引用;函数执行完后,函数销毁,形参的引用也减少;
如果参数是可变对象,比如列表、字典、集合,参数传递后,也没有分配新的对象,新增对象的引用;函数执行完后,形参的引用也减少,但需要注意的是,因为并没有分配新的内存空间,经过函数的处理后,会改变原来实参所指向的对象的取值。
# 匿名函数格式
变量 = lamdba 参数1, 参数2, 参数3: 表达式
lamdba是函数的匿名表示方法,在表示一些较简短的函数时,可以使用。
lamdba函数有其自身的函数作用域。
函数的作用域,也叫名称空间。主要有3种类型:
需要注意的是,可以引入新的作用域的只有:模块、类、函数(包括嵌套的函数)。如果是其他代码块,比如try...except...或其他for/while等语句,并不会引入新的作用域。
作用范围:内置作用域built-in > 全局作用域global > 闭包中父类的作用域enclosing > 局部作用域local
搜索顺序:局部作用域local > 闭包中父类的作用域enclosing > 全局作用域global > 内置作用域built-in,可以理解为,一个变量,首先会在局部搜索查找该变量,如果没有在到全局变量中查看,如果在没有继续扩大范围到内置变量中查找。这一点可以说明,局部变量,是可以访问全局变量的,而反之,全局变量是不能访问局部变量。
局部变量可访问全局变量,前提是:如果局部变量中搜索不到变量,会继续扩大范围搜索全局变量。但是局部变量并没有修改全局变量,如果想修改全局变量,需要使用关键字global。
name = "Test" def var_domain(): global name name = "local name" print(name) var_domain() print(name)>> 全局变量name已修改成local name
nonlocal关键字,主要用以局部变量来修改局部变量的父类变量时使用,即在闭包的函数中,子类变量修改父类变量。
name = "Test" def var_domain(): name = "local name" def inner_func(): nonlocal name name = "inner name" print(name) inner_func() print(name) var_domain() print(name)>> 闭包的局部变量local name,已经被修改为inner name
globals():返回字典,获取全局作用域内的变量-值的字典,包括全局变量以及内置全局变量。
locals():返回字典,可获取所在位置的局部作用域内的变量-值的字典
函数的高级函数有一个共同的特定:传入的参数都为函数,对一个序列进行处理。
用法:map(__func, __iter1, __iter2, ……),第2个参数,第3个,第n个参数的个数,与func的参数个数有关
返回:python3.7返回的是迭代器
def square(x): return 9*x res = list(map(square, [1, 2, 3, 4]))>> [9, 18, 27, 36]
def square(x, y): return x+y res = list(map(square, [1, 2, 3, 4], [9, 10, 11, 19]))>> [10, 12, 14, 23]
注意:在python3.7后,reduce已经不是内置函数,如果需要使用reduce,需引入包from functools import reduce
from functools import reduce def add(x, y): return x + y res = reduce(add, [1, 9, 10, 11])>> 31
用法:filter(__function, __iterable),对序列iterable中的每个元素作为参数,传递给function进行判断,如果为True,则放入列表中,如果为False,则过滤掉
返回:python3.7返回的是迭代器,如果想得到列表,可直接用内置list方法
def is_odd(n): return n%2 == 1 res = list(filter(is_odd, [1, 2, 3, 4, 5, 6, 7, 8, 9]))>> [1, 3, 5, 7, 9]
偏函数可以理解为,是对原有一个函数的改动,在原有函数上新增默认参数。
经常使用的偏函数模块是:from functools import partial
from functools import partial def part_test(x, age=10): return "x is at age {}".format(age) part_test_20 = partial(part_test, age=20) # 创建一个偏函数part_test_20,注意这里的part_test_20和part_test均是函数的对象 print(part_test_20("hello"))>> hello is at age 20
先创建一个偏函数,给定一个默认参数的取值;在调用偏函数,相当于调用了一个有固定默认参数的函数。
调用自身的函数,即递归函数。递归函数都可以用循环来实现,用递归简洁且逻辑清晰。
递归函数最大的问题是:会出现栈溢出。因为调用函数,会使用栈内存空间,函数调用,会非分配栈内存空间,函数执行完后,会释放栈内存空间,因为是递归调用,会有较多入栈操作,但是栈空间并不是无限的,可能导致栈内存溢出的问题。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。