一、函数初识

函数的产生:函数就是封装一个功能的代码片段。

li = ['spring', 'summer', 'autumn', 'winter']
def function():
count = 0
for j in li:
count += 1
print(count)
function()        # 4
  • def 关键字,定义一个函数
  • function 函数名的书写规则与变量一样。
  • 括号是用来传参的。
  • 函数体,就是函数里面的逻辑代码

代码从上至下执行,执行到def function() 时, 将function这个变量名加载到临时内存中,但它不执行

函数的执行:函数名 + ()

使用__name__方法获取函数名 ,使用__doc___方法获取函数的解释  

def func1():
"""
此函数是完成登陆的功能,参数分别是...作用。
return: 返回值是登陆成功与否(True,False)
"""
print(666) func1()
print(func1.__name__) #获取函数名
print(func1.__doc__) #获取函数名注释说明
执行输出:
666
func1
此函数是完成登陆的功能,参数分别是...作用。
return: 返回值是登陆成功与否(True,False)

这个有什么用呢?比如日志功能,需要打印出谁在什么时间,调用了什么函数,函数是干啥的,花费了多次时间,这个时候,就需要获取函数的有用信息了

1. 函数返回值

写函数,不要在函数中写print(),  函数是以功能为导向的,除非测试的时候,才可以写print()

  • 在函数中,遇到return结束函数
def fun():
print(111)
return
print(444)
fun()
执行输出:111
  • 将值返回给函数的调用者
def fun():
a = 134
return a
print(fun())
执行输出:123

1)无 return

def fun():
pass
print(fun())
执行输出:None

2)return 1个值该值是什么,就直接返回给函数的调用者,函数名()

def fun():
return [1,2,3]
print(fun())
执行输出:[1, 2, 3]

3)return 多个值 将多个值放到一个元组里,返回给函数的调用者。

def fun():
return 1,2,[33,44],'abc'
print(fun())
执行输出:
(1, 2, [33, 44], 'abc')

2. 函数的传参

(1)实参:在函数执行者里面的参数叫实参

位置参数:按顺序一一对应

def func(a,b,c):
print(a)
print(b)
print(c) func('fdsafdas',3,4)
执行输出:
fdsafdas
3
4

如果少一个参数呢?

def func(a,b,c):
print(a)
print(b)
print(c) func(3,4)
执行报错:TypeError: func() missing 1 required positional argument: 'c'

必须是一一对应的。

def compare(x,y):
ret = x if x > y else y #三元运算,针对简单的if else才能使用
return ret print(compare(123,122334)) #

关键字参数:可以不按顺序,但是必须一一对应

def compare(x,y):
ret = x if x > y else y
return ret
print(compare(y=13,x=1))
执行结果:13

混合参数:关键字参数一定要在位置参数后面

def func1(a,b,c,d,e):
print(a)
print(b)
print(c)
print(d)
print(e) func1(1,4,d=2,c=3,e=5)
执行输出:
1
4
3
2
5

(2) 形参:

位置参数:按顺序和实参一一对应,位置参数必须传值

def func(a,b,c):
print(a)
print(b)
print(c) func('fdsafdas',3,4)
执行输出:
fdsafdas
3
4

默认参数:传参则覆盖,不传则默认,默认参数永远在位置参数后面

1.

def func(a,b=666):
print(a,b)
func(1,2)
执行输出:1 2

2.

def func(a,b=666):
print(a,b)
func(1) 执行输出:1 666

举一个场景:班主任录入员工信息表,有2个问题:第一,男生居多;第二,完成函数功能 *****

def  Infor(username,sex='男'):
with open('name_list',encoding='utf-8',mode='a') as f1:
f1.write('{}\t{}\n'.format(username,sex)) while True:
username = input('请输入姓名(男生以1开头):').strip()
if '' in username:
username = username[1:] #去除1
Infor(username)
else:
Infor(username,'女')

③动态参数当函数的形参数量不一定时,可以使用动态参数。用*args和**kwargs接收,args是元组类型,接收除键值对以外的参数(接收位置参数),kwargs是字典类型,接收键值对(关键字参数)并保存在字典中。

def func(*args,**kwargs):
print(args,type(args))
print(kwargs,type(kwargs)) func(1,2,3,4,'alex',name = 'alex')
输出结果是:
(1, 2, 3, 4, 'alex') <class 'tuple'>
{'name': 'alex'} <class 'dict'>

“ * "的魔性作用

(1)在函数定义时:*位置参数和**关键字参数代表聚合

将所有实参的位置参数聚合到一个元组中,并将这个元组赋值给args。在关键参数前加“ ** ”代表将实参的关键字参数聚合到一个字典中,并将这个字典赋值给kwargs。

将2个列表的所有元素赋值给args

def func(*args):
print(args) l1 = [1,2,30]
l2 = [1,2,33,21,45,66]
func(*l1)
func(*l1,*l2)
执行输出:
(1, 2, 30)
(1, 2, 30, 1, 2, 33, 21, 45, 66)

传两个字典给**kwargs

def func(**kwargs):
print(kwargs) dic1 = {'name':'jack','age':22}
dic2 = {'name1':'rose','age1':21}
func(**dic1,**dic2)
执行输出:
{'name': 'jack', 'age': 22, 'name1': 'rose', 'age1': 21}
def func(*args,**kwargs):
print(args)
print(kwargs) func(*[1,2,3], *[4,5,6], **{'name':'alex'}, **{'age':18})   #相当于func([1,2,3,4,5,6], {'name':'alex','age':18})

(2)在函数的调用执行时,打散

  *可迭代对象,代表打散(list,tuple,str,dict(键))将元素一一添加到args。

   **字典,代表打散,将所有键值对放到一个kwargs字典里。

def func(*args,**kwargs):
print(args,kwargs) dic1 = {'name':'jack','age':22}
dic2 = {'name1':'rose','age1':21} func(*[1,2,3,4],*'asdk',**dic1,**dic2)
执行输出:(1, 2, 3, 4, 'a', 's', 'd', 'k') {'age1': 21, 'name': 'jack', 'age': 22, 'name1': 'rose'}

形参的顺序:位置参数 ----> *args ----->关键字参数-------->默认参数 ------->**kwargs

*args参数,可以不传,默认为空(),**kwargs 动态传参,他将所有的关键字参数(未定义的)放到一个字典中

def func(a,b,c,d,*args,e='男',**kwargs):
print(a,b,c,d,args,e,kwargs) func(1,2,3,4,5,6,7,v=3,m=7,h=9,e='女')
执行输出:1 2 3 4 (5, 6, 7) 女 {'v': 3, 'h': 9, 'm': 7}
def func(a,b,c,**kwargs):
print(kwargs)
func(1,2,r=4,b1=5,c1=6,c=7) 执行输出:{'r': 4, 'c1': 6, 'b1': 5}

执行没有报错,是因为函数接收参数后,它会从左边到右找,最后找到了c,c=7参数,在a,b,c里面已经定义好了,所以在输出的字典中,并未出现。因为kwargs返回的是未定义的关键字参数。

如果函数含有多个未知参数,一般使用如下格式:

def func1(*args,**kwargs):
pass
func1()

二、命名空间和作用域

  当执行函数的时候,他会在内存中开辟一个临时名称空间,存放函数体内的所有变量与值的关系,随着函数的执行完毕,临时空间自动关闭。

函数里面的变量,在函数外面能直接引用么?不能

def func1():
m = 1
print(m) print(m) # NameError: name 'm' is not defined

上面为什么会报错呢?现在我们来分析一下python内部的原理是怎么样:

我们首先回忆一下Python代码运行的时候遇到函数是怎么做的,从Python解释器开始执行之后,就在内存中开辟里一个空间,每当遇到一个变量的时候,就把变量名和值之间对应的关系记录下来,但是当遇到函数定义的时候,解释器只是象征性的将函数名读入内存,表示知道这个函数存在了,至于函数内部的变量和逻辑,解释器根本不关心。等执行到函数调用的时候,Python解释器会再开辟一块内存来储存这个函数里面的内容,这个时候,才关注函数里面有哪些变量,而函数中的变量会储存在新开辟出来的内存中,函数中的变量只能在函数内部使用,并且会随着函数执行完毕,这块内存中的所有内容也会被清空。

1. 命名空间和作用域

命名空间:存放”名字与值关系的空间“

①全局命名空间:代码在运行时,创建的存储”变量名与值的关系“的内存空间

②局部命名空间:在函数调用时临时开辟出来的空间,会随着函数的执行完毕而被清空

③内置命名空间:存放了python解释器为我们提供的名字:input,print,str,list,tuple...它们都是我们熟悉 的,拿过来就可以用的方法。

作用域:就是作用范围

①全局作用域:全局命名空间、内置命名空间。在整个文件的任意位置都能被引用、全局有效

②局部作用域:局部命名空间,只能在局部范围内生效

加载顺序:

内置命名空间(程序运行前加载)----->   全局命名空间(程序运行中从上至下加载) -----> 局部命名空间(程序运行中:调用时才加载)

取值顺序:

  在局部调用:局部命名空间->全局命名空间->内置命名空间

  在全局调用:全局命名空间->内置命名空间

综上所述,在找寻变量时,从小范围,一层一层到大范围去找寻。取值顺序:就近原则

局部变量举例

name = 'summer'
def func1():
name = 'spring'
print(name)
func1()
执行输出:spring
取值是从内到外
name = 'summer'
def func1():
print(name)
func1()

执行输出:summer

代码从上至下依次执行, 调用函数:函数里面从上至下依次执行。

print(111)
def func1():
print(333)
func2()
print(666)
def func2():
print(444)
def func3():
print(555)
func2() func1()
print(222)
执行输出:
111
333
444
666
222
def f1():
def f2():
def f3():
print("in f3")
print("in f2")
f3()
print("in f1")
f2()
f1()
执行输出:
in f1
in f2
in f3

2. globals和locals方法

print(globals())         #全局名称空间所有变量,字典
print(locals())       #局部名称空间所有变量,字典 (当前

globals()和locals()一般很少用,在函数逻辑比较复杂的情况下,可能会用到。

li = ['spring', 'summer', 'autumn', 'winter']

def func():
a = 1
b = 2
print('func', globals())
print('func', locals()) def func1():
c = 3
d = 4
print('func1', globals())
print('func1', locals()) func1() func()

输出结果

func {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x011CC410>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'C:/Users/Administrator/houseinfo/test.py', '__cached__': None, 'li': ['spring', 'summer', 'autumn', 'winter'], 'func': <function func at 0x03542E40>}
func {'b': 2, 'a': 1}
func1 {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x011CC410>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'C:/Users/Administrator/houseinfo/test.py', '__cached__': None, 'li': ['spring', 'summer', 'autumn', 'winter'], 'func': <function func at 0x03542E40>}
func1 {'d': 4, 'c': 3}

 (1)global:

①在局部命名空间声明全局变量

def func2():
global name
name = 'summer' func2()
print(name)
执行结果:summer

②在局部命名空间对全局变量进行修改(限于字符串,数字)。

count = 1
def func1():
global count
count = count + 1
print(count)
func1()
print(count)
执行结果:
2
2

因为全局变量count被函数体的global count 覆盖了

(2)nonlocal

子函数对父函数的变量进行修改,此变量不能是全局变量

a = 4
def func1():
nonlocal a
a = 5 #修改全局变量
#print(name)
func1()
print(a)
执行输出:SyntaxError: no binding for nonlocal 'a' found

在局部作用域中,对父级作用域的变量进行引用和修改,并且引用的哪层,从那层及以下此变量全部发生改变。

1

def func1():
b = 6
def func2():
b = 666
print(b)
func2()
print(b) #父级不受影响
func1()
执行输出:
666
6

例2

def func1():
b = 6
def func2():
nonlocal b #表示可以影响父级,也就是func1()
b = 666 #重新赋值
print(b)
func2()
   print(b) #这个时候,影响了b的值,输出666
func1()
执行输出:
666
666

3******

def aa():                     #不受ccl影响
b = 42
def bb():
b = 10 #影响子级函数,b都是10
print(b)
def cc():
nonlocal b #只能影响父级,也就是bb()
b = b + 20 #b=10+20 也就是30
print(b)
cc()
print(b)
bb()
print(b)
aa()
执行输出:
10
30
30
42

注意

a = 5
def func1():
a += 1
print(a)
func1()

执行报错。这里函数对全局变量做了改变,是不允许操作的。函数内部可以引用全局变量,不能修改。如果要修改,必须要global一下

a = 5
def func1():
global a
a += 1
print(a) func1() #输出6

04 python之函数详解的更多相关文章

  1. python super()函数详解

    引言: 在类的多继承使用场景中,重写父类的方法时,可能会考虑到需要重新调用父类的方法,所以super()函数就是比较使用也很必要的解决方法: 文章来源: http://www.cnblogs.com/ ...

  2. Python匿名函数详解

    python 使用 lambda 来创建匿名函数. lambda这个名称来自于LISP,而LISP则是从lambda calculus(一种符号逻辑形式)取这个名称的. 在Python中,lambda ...

  3. Python 钩子函数详解

    ###### 钩子函数 ``` import pluggy hookspec = pluggy.HookspecMarker('aaa') hookimpl = pluggy.HookimplMark ...

  4. Python sorted函数详解(高级篇)

    sorted() 函数对所有可迭代的对象进行排序操作. sort 与 sorted 区别: sort 是应用在 list 上的方法,sorted 可以对所有可迭代的对象进行排序操作. list 的 s ...

  5. python socket函数详解

    关于socket函数,每个的意义和基本功能都知道,但每次使用都会去百度,参数到底是什么,返回值代表什么意义,就是说用的少,也记得不够精确.每次都查半天,经常烦恼于此.索性都弄得清楚.通透,并记录下来, ...

  6. Python print函数详解

    1 """ 2 print(...) 3 print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=Fals ...

  7. Python内置函数详解

    置顶   内置函数详解 https://docs.python.org/3/library/functions.html?highlight=built#ascii https://docs.pyth ...

  8. Python中的zip()与*zip()函数详解

    前言 实验环境: Python 3.6: 示例代码地址:下载示例: 本文中元素是指列表.元组.字典等集合类数据类型中的下一级项目(可能是单个元素或嵌套列表). zip(*iterables)函数详解 ...

  9. python基础之函数详解

    Python基础之函数详解 目录 Python基础之函数详解 一.函数的定义 二.函数的调用 三.函数返回值 四.函数的参数 4.1 位置参数 4.2 关键字参数 实参:位置实参和关键字参数的混合使用 ...

随机推荐

  1. SVG和canvas渲染的性能比较

    1.什么是SVG? 描述: 一种使用XML描述的2D图形的语言 SVG基于XML意味着,SVG DOM中的每个元素都是可用的,可以为某个元素附加Javascript事件处理器. 在 SVG 中,每个被 ...

  2. 0x03 前缀和与差分

    前缀和 [例题]BZOJ1218 激光炸弹 计算二位前缀和,再利用容斥原理计算出答案即可. #include <iostream> #include <cstdio> #inc ...

  3. 【C++】string::find函数

    int vis=a.find(b):从string a开头开始查找第一个遇到的string b,返回string a中所匹配字符串的第一个字符的下标位置,找不到则返回-1. int vis=a.fin ...

  4. requestAnimationFrame 兼容方案

    [toc] 编写涉及:css, html, js 在线演示codepen html代码 <div class="roll-box"> <div class=&qu ...

  5. Web前端开发工程师课程大纲

    PHP程序员雷雪松整理出来的一套独一无二的Web前端开发课程.本套Web前端开发课程专门为想励志成为优秀web前端工程师的学习者而总结归纳的,本套Web前端课程舍弃了一些不常用的即将废弃的HTML标签 ...

  6. C++7行代码实现求最大公约数

    最近在做奥赛题时碰到求最大公约数的问题,给出解决方案: int gcd(int a,int b){ int tmp = a%b; ){ return b; } else{ return gcd(b,t ...

  7. 我的第一个CAD程序

    [步骤1]新建项目 启动Visual Studio 2010,然后选择一个C#类库,设置好名称和保存位置,点击[确定] [步骤2]添加引用文件AcMgd.dll和AcDbMgd.dll 首次使用时,[ ...

  8. Jedis的配置和优化

    参数名:maxTotal 含义:资源池最大连接数 [默认值:8] 使用建议:需要考虑以下几点 1.业务希望的Redis并发量 2.客户端执行命令时间 3.Redis资源:例如应用个数(客户端)* ma ...

  9. 使用Cmake编译CEF时遇到Error in configuration process,project file may be invalid的解决办法

    今天在用Cmake编译cef框架时,弹出了错误,如图: 可以排查一下几种原因: 1.在64位计算机编译32位程序 可以更换编译环境,或者下载64位版本来解决这个问题. 2.选择的Visual Stud ...

  10. Hive 系列(四)—— Hive 常用 DDL 操作

    一.Database 1.1 查看数据列表 show databases; 1.2 使用数据库 USE database_name; 1.3 新建数据库 语法: CREATE (DATABASE|SC ...