我们前面学的都是面向过程式的编程(代码从上到下写,并运行),而函数式编程是将繁杂的代码通过整理特性进行规整。像图书馆一样,将小说、教学、外文等书籍进行分类。让编程人员或看代码人员很容易的查看该段代码的特性。并且可以重复的利用该段代码进行相同的操作、像图书馆书是公用的一样,谁都可以去看,这样又能便于观察又能重复使用,是日后主要使用的技术。

def test():         #设置一个函数名称
#test #注释函数作用
print('函数式编程') #函数程序处理逻辑
return 0 #定义返回值,如果没有定义将返回None
test() #调用

函数:

1. 可以在调用时,在括号内放入参数,里面有(位置参数,关键字参数,混合参数,默认参数,汇总参数)

2. 位置参数必须要在关键字参数前面。

位置参数:

将参数一一对应,并传入到函数中:

def func(a,b,c):
print(a,c,b)
func(1,2,3) #将1=>a,2=>b,3=>c

关键字参数:

将特定的参数以赋值形式对应起来。

def func(a,b,c):
print(a,c,b)
func(a=1,b=2,c=8)

混合参数(位置参数与关键字参数)

不能写在位置参数的前面:

def func(a,b,c):
print(a,c,b)
test(3,b=2,c=1) √
test(c=1,2) X

默认参数:
调用函数的时候,默认参数非必须传递。
如果再没有定义其他,就以默认的来。

在定义默认值时:不可变类型随便传,但可变类型需要注意:

def test(x,y=1):
print(y) test(2)

汇总参数:

1. *args:接收N个位置参数,转换成元组的形式。

def test1(x,*args):
  print(x)
  print(args)
test1(1,2,3,4,5,6) & test1(1,*[2,3,4,5,6]) #这里的*后面的列表是将列表内容提取并重新赋值给元组,以元组形式输出。

2. **kwargs:把N个关键字参数,转换成字典的方式。

def test1(x,**kwargs):
print(x)
print(kwargs)
# test1(1,name='3',age=20)
test1(2,name='xuan',age=9)
test1(1,**{'name':"xuan",'age':20}) #将字典内容提取,在重新赋值给函数内的kwargs
2
{'name': 'xuan', 'age': 9}
1
{'name': 'xuan', 'age': 20}

作用域:

在Python中,一个函数就是一个作用域,而所有的函数都挂靠在.py文件的总作用域中。

在这里写的代码分为:全局作用域和局部作用域

1. 全局作用域

  • 要使用全大写形式定义变量名称,为了将局部变量做标识。
  • 局部作用域全部挂靠在全局作用域内
NAME = 'a1'
def func():
name = 'a2'
print(name)
print(NAME)
func()

2. 局部作用域:

  • 局部作用域可以调用全局作用域。局部和局部,全局和局部不能调用。
  • 局部作用域之间无法调用,可以使用父作用域。
def change_name(name): #一个函数叫做一个作用域,
  print('before change',name)
  name='XB'
  print('after change',name) name = 'xb'
change_name(name)
print(name)

global:

在局部作用域中,进行全局作用域内容的查找,并可以修改。(只能修改可变类型,不可变类型为局部内重新赋值)

NAME = 'a1'
def func():
global NAME
NAME = 'bbb'
func()
print(NAME)

nonlocal:

在子局部作用域中,进行对父级局部作用域的内容查找不更改全局作用域内容,并可以修改。(同样修改可变类型,不可变类型为局部内重新赋值)

NAME = 'a1'
def func():
NAME = '111'
def func2():
nonlocal NAME
NAME = 'bbb'
func2()
print(NAME)
func()
print(NAME)

返回值:

在函数中使用return来进行函数这个子作用域的返回值的关键字。其中:

1. 默认如果没有return,但定义了取值变量的话,默认为None。

def papa():
print('111')
a = papa() #a就是None

2. 如果只有一个返回值,那么就返回相应的数值和数据类型。如果有多个返回值,那么将返回一个元组。

def papa():
dic = {'k1':'v1'}
return dic #将返回字典类型
return {'k1':'v1'},{'k1':'v1'},{'k1':'v1'} #将返回元组类型 a = papa()
print(a)

3. 返回值同样可以返回另一个函数的内存对象地址

def a():
print('111')
def papa():
return a #返回一个内存对象地址,返回后可以直接运行。
b = papa()
b()lam

lambda

用于表示简单的函数时,可以使用lambda来进行,其中需要注意的:

1. 只能用一行来表示lambda

2. 只能用参数传的值,而不能自己定义一个变量。

使用lambda默认就会有一个return。

a = lambda : 1+1   #将1+1的结果返回到a中。
print(a())

lambda可以搭配三元运算使用:

a = lambda : 1 if 1+1 == 2  else 2   #判断如果1+1等于2的话,那么返回1,否则返回2
print(a())

其他:

lis = lambda : [ i for i in range(10) if i%3 == 0 ]   #循环1-10,判断其中哪些为3整除,添加到列表中,生成一个lambda。
print(lis())

闭包:

闭包是嵌套在函数中的函数,而闭包必须是内层函数对外层函数的变量(非全局变量)的引用。

为函数创建一个区域(内部变量供自己使用)为以后执行提供数据。

#实例
li = []
def func(new_value):
li.append(new_value)
total = sum(li)
return total/len(li)
print(func(1000))
print(func(2000))
print(func(5000)) #那么问题来了,li是全局变量,我可以在全局随意更改。
li = []
def func(new_value):
li.append(new_value)
total = sum(li)
return total/len(li)
print(func(1000))
print(func(2000))
li.append(120301)
print(func(5000))
#得出来的结果就大不相同了。如何有解决办法,那就是把li放到函数的小作用域里。 def func(new_value):
li = []
li.append(new_value)
total = sum(li)
return total/len(li)
print(func(1000))
print(func(2000))
print(func(5000))
#这样一来,每次运行函数,就会新生成一个新的列表出来。那么值就没有变化了。接下来如何解决这个问题。闭包就来了。 def func():
li = []
def func1(new_value):
li.append(new_value)
total = sum(li)
return total/len(li)
return func1
func = func()
print(func(1000))
print(func(2000))
print(func(5000)) #这样一来,即不会出现全局模式更改的问题,也不会担心列表重新生成的问题。这就是比好。

其中,下面一块区域叫做闭包:

    li = []
def func1(new_value):
li.append(new_value)
total = sum(li)
return total/len(li)

我们可以通过查看函数内是否有自由变量来侧面证明是不是闭包。

def func():
li = []
def func1(new_value):
li.append(new_value)
total = sum(li)
return total/len(li)
return func1
func = func()
print(func.__code__.co_freevars) #查看函数的自由变量
#('li',)
print(func.__code__.co_varnames) #查看函数的局部变量
#('new_value', 'total')

函数需要注意的点:

1. 根据数据类型的不同,有些是有返回值的,有些是没有返回值的。

lis = []
def a():
return lis.append('111')
b = a()
print(b) #由于列表形式的添加是没有返回值的,所以返回的是None
lis = '123'
def a():
return lis + '321'
b = a()
print(b) #由于字符串是有返回值的,所以返回的是所需值

2. 需要判断是传入函数内存地址还是函数的return的值。

def func():
print('1111')
return 0
lis = [func,func,func] #这里传入的是函数的内存地址。不是执行结果。
for item in lis:
print(item) #打印的是内存地址
'''
<function func at 0x000001D8489B9550>
<function func at 0x000001D8489B9550>
<function func at 0x000001D8489B9550>
'''
def func():
return 0
lis = [func(),func(),func()] #这里传入的是运行完func的返回值
for item in lis:
print(item) #打印的是0
'''
0
0
0
'''

3. 闭包问题

def func(name):
v = lambda x:x+name
return v v1 = func('武沛齐')
v2 = func('alex')
v3 = v1('银角')
v4 = v2('金角')
print(v1,v2,v3,v4)
result = []
for i in range(10):
func = lambda : i # 注意:函数不执行,内部代码不会执行。
result.append(func) print(i)
print(result)
v1 = result[0]()
v2 = result[9]()
print(v1,v2)
def func(num):
def inner():
print(num)
return inner result = []
for i in range(10):
f = func(i)
result.append(f) print(i)
print(result)
v1 = result[0]()
v2 = result[9]()
print(v1,v2)

4. 实参与形参

传参的类型是否为可变类型,如果可变类型,那么实参也会一起改变,如果是不可变类型,那么就会重新创建一个方法内部变量。

###########传入不可变类型############
def func(a):
a += 1
print(id(a))
a = 7
func(a)
print(id(a))
print(a) #判断ID输出是否一样,a输出的结果?
############传入可变类型################### def func(a):
a[0] = 8
print(id(a))
a = [1,2,3]
func(a)
print(id(a))
print(a)
#判断ID输出是否一样,a输出的结果?

函数中的那些坑:

1. 函数中有定义一个空列表作为形参:

def a(b,lis=[])

问题:在没有传入新的列表当做实参时,将会使用定义好的空列表,那么将会导致多个没有定义的实参重复调用该空列表。这将导致数据内容不一致的问题。

def b(a,lis=[]):
for i in range(a):
lis.append(i*i)
print(lis)
b(3)
b(3)
b(3)
'''
[0, 1, 4]
[0, 1, 4, 0, 1, 4]
[0, 1, 4, 0, 1, 4, 0, 1, 4]
'''

可以传参时传入一个自己的空列表,那么就将使用自己传入的空列表。

def b(a,lis=[]):
for i in range(a):
lis.append(i*i)
print(lis)
b(3,[])
b(3,[])
b(3,[])
'''
[0, 1, 4]
[0, 1, 4]
[0, 1, 4]
'''

如何解决这类问题,要么就删除空列表,要么就进行判断。

def b(a,lis=[]):
if lis:
lis = []
for i in range(a):
lis.append(i*i)
print(lis)
b(3,[])
b(3,[])
b(3)
b(3)
b(3)
'''
[0, 1, 4]
[0, 1, 4]
[0, 1, 4]
'''

 

Python——函数&作用域的更多相关文章

  1. Python函数作用域的查找顺序

    函数作用域的LEGB顺序 1.什么是LEGB? L:local 函数内部作用域 E:enclosing 函数内部与内嵌函数之间 G:global 全局作用域 B:build-in 内置作用域 2.它们 ...

  2. python函数作用域,嵌套函数,闭包

    函数作用域                                                                                                ...

  3. python函数作用域LEGB

    我们的在学习Python函数的时候,经常会遇到很多定义域的问题,全部变量,内部变量,内部嵌入的函数,等等,Python是如何查找的呢?以及Python又是按照什么顺序来查找的呢?这里做一个顺序的说明 ...

  4. python函数作用域

    python中函数作用域 在python中,一个函数就是一个作用域 name = 'xiaoyafei' def change_name(): name = '肖亚飞' print('在change_ ...

  5. python函数作用域,闭包,装饰器

    第一:函数作用域: L:local 函数内部作用域 E:enclosing       函数内部与内嵌函数之间(闭包) G:global            全局作用域 B:build_in    ...

  6. 07.python函数作用域global、nonlocal、LEGB

    函数作用域 作用域 一个标识符的课件范围,这就是标识符的作用域,一般常说的是变量的作用域 def foo():    x = 100 print(x) # 可以访问到吗 上例中x不可以访问到,会抛出异 ...

  7. Python函数作用域和匿名函数

    匿名函数的定义 全局变量和局部变量的概念 global(全局变量)和 nonlocal(局部变量) 闭包.递归.回调 匿名函数 匿名函数  lambda 语法规则:lambda   参数 : 表达式 ...

  8. python函数 -- 作用域,异常处理

    1.def语句和参数 python定义函数的关键词为def,格式如下: def 函数名([变元],[变元],....)          #保存在变元中的值,在函数返回后该变元就会被销毁了. 2.返回 ...

  9. python函数-作用域

    可以把作用域”看成是变量的容器.当作用域被销毁时,所有保存在该作用 域内的变量的值就被丢弃了,只有一个全局作用域,它是在程序开始时创建的.如 果程序终止,全局作用域就被销毁,它的所有变量就被丢弃了. ...

随机推荐

  1. Maven构建报错问题解决

    [ERROR] Failed to execute goal on project zepeto-admin: Could not resolve dependencies -SNAPSHOT: Fa ...

  2. js组件常用封装方法。。。。。【组件封装】 ★★★★★★

    公共弹窗js写法:mcake弹窗封装Dialog.js function Dialog(bg,els,opts) { this.$els = $(els); this.$Dialogbg = $(bg ...

  3. Jmeter多业务混合场景如何设置各业务所占并发比例

    在进行多业务混合场景测试中,需要分配每个场景占比. 具体有两种方式: 1.多线程组方式: 2.逻辑控制器控制: 第一种: jmeter一个测试计划可以添加多个线程组,我们把不同的业务放在不同的线程组中 ...

  4. matlab中可用于进行轮廓提取的函数

    本文主要总结一下在matlab中可用于进行轮廓提取的函数. 1 bwperim 根据参考资料[2]的提示,可以使用bwperim()函数进行轮廓提取,具体代码如下: %读取原图im = imread( ...

  5. Ubuntu安装FreeSWITCH亲测

    本人在安装FreeSWITCH的时候遇到了相当多的坑,网上很多方法都模棱两可,经常装失败,最后终于装成功后做一下总结 最顺利的安装方式 1. 下载压缩文件 下载地址:http://files.free ...

  6. PID:我应该何时计算积分项?

    最近看到了Brett Beauregard发表的有关PID的系列文章,感觉对于理解PID算法很有帮助,于是将系列文章翻译过来!在自我提高的过程中,也希望对同道中人有所帮助.作者Brett Beaure ...

  7. Ingress 访问日志分析与监控

    阿里云Ingress除了提供外部可访问的 URL.负载均衡.SSL.基于名称的虚拟主机外,还支持将所有用户的HTTP请求日志记录到标准输出中.同时Ingress访问日志与阿里云日志服务打通,您可以使用 ...

  8. linux查看哪个进程占用磁盘IO

    方法一: $ iotop -oP 命令的含义:只显示有I/O行为的进程 测试结果: 方法二: $ pidstat -d 1 命令的含义:展示I/O统计,每秒更新一次 测试结果:

  9. 【视频开发】【计算机视觉】doppia编译之三:编译安装opencv库

    这里我介绍2种方法 (1)利用别人写好的脚本编译,相对来说省力一点  上Github下载别人写好的脚本文件,网址 https://github.com/jayrambhia/Install-OpenC ...

  10. Python 获取文件类型后缀

    import os path='file.txt' file=os.path.splitext(path) filename,type=file print(filename) print(type)