2.1-python函数,作用域


python 函数

初始函数

函数的优势:

  1. 减少代码的重复性;
  2. 使代码可读性更高;

函数的结构与调用

函数的结构

def 函数名():
    函数体

def 关键词开头,空格之后接函数名称和(),最后还有一个':';

def 是固定的,不能变,是定义函数的关键字;

空格,为了将def关键字和函数名分开;

函数名:函数名只能包含字符串,下划线和数字且不能以数字开头;起函数名要尽量简短,并具有可描述性;

考好:必须加的,可以传参使用;

函数的调用

使用函数名加()就可以调用了,写法:函数名(),这个时候函数的函数体就会被执行;

这个指令写多少次,函数里的代码就运行多少次;

函数的返回值

一个函数就是封装一个功能,这个功能一般都会有一个最终结果;比如写一个登陆函数,最终登陆成功与否就需要返回一个结果。

设置返回值,使用python的关键字:return;

return:函数中遇到return,此函数结束,不再继续执行;

函数的返回值返回给 函数名()这个整体,也就是这个执行者;

return也可以返回多个值,以元组的形式返回的;

总结:

  1. 遇到return,函数结束,return下面的(函数内)的代码不会执行;

  2. return会给函数的执行者返回值;

    1. 如果return后面什么都不写,或者函数中没有return,则返回的结果是None
    2. 如果return后面写了一个值,返回给调用者这个值;
    3. 如果return后面写了多个结果,返回给调用者一个tuple(元组),调用者可以直接使用与uanzu的解构获取多个变量;
    def date():
        return '你好', '世界', '我是黑色利穆'
    a1, a2, a3 = date()
    print(a1, a2, a3)
    # 你好 世界 我是黑色利穆
    

函数的参数

函数是以功能为导向的;

函数的参数从两个角度划分:

  1. 形参:写在函数声明的位置的变量叫形参,形式上的一个完整,表示这个函数需要XX
  2. 实参:在函数调用的时候给函数传递的值,加实参,实际执行的时候给函数传递的信息,表示给函数XX

函数的传参就是函数将实际参数交给形参的过程;

def date(sex):  # 函数定义时(参数)这个就是形参
    print('设置筛选条件:性别: %s' %sex)
date('女')       # 函数执行时(参数),这个就是实参
# 设置筛选条件:性别: 女
# 过程:代码运行到date('女'),开始执行此函数同时将字符串'女'这个数据传递给变量sex,然后执行函数中的代码

实参角度

位置参数

位置参数就只从左至右,实参与形参一一对应

def date(sex, age, hobby):
    print('设置筛选条件:性别:%s, 年龄:%s, 爱好:%s' %(sex, age, hobby))
date('女', '25', '唱歌')
date('男', '25', '跳舞')
# 设置筛选条件:性别:女, 年龄:25, 爱好:唱歌
# 设置筛选条件:性别:男, 年龄:25, 爱好:跳舞

练习:

# 编写函数,给函数传递两个参数a,b。a,b相加,返回a参数和b参数相加的和
def f(a, b):
    c = a + b
    return c
print(f(10, 20))
# 30

# 编写函数,给函数传递两个参数a,b,比较a,b的大小,返回a,b中最大的那个数
def f(a, b):
    if a > b:
        return a
    else:
        return b
print(f(10,20))
# 20

# 三元运算符比较大小
def f(a, b):
    c = a if a > b else b   # 当a>b就把a赋值给c,否则就把b赋值给c
    return c
print(f(10, 20))
# 20

关键字参数

如果函数在定义的时候参数非常多,位置参数就不好用了。所以可以使用关键字参数,就不需要记住繁琐的参数位置了。

def date(sex, age, hobby):
    print('设置筛选条件:性别: %s,年龄:%s,爱好:%s' %(sex, age, hobby))
date(hobby='唱歌', sex='女', age='35')
# 设置筛选条件:性别: 女,年龄:35,爱好:唱歌

混合参数

混合参数,就是可以使用位置参数,也可以指定关键字参数;

ps:关键字参数一定要在位置参数后面;

def date(sex, age, hobby):
    print('设置筛选条件:性别: %s,年龄:%s,爱好:%s' %(sex, age, hobby))
date('男', hobby='唱歌', age='35')
# 设置筛选条件:性别: 男,年龄:35,爱好:唱歌

总结:

在实参角度看,参数分为三种:1.位置参数;2.关键字参数;3.混合参数(位置参数必须在关键字参数前面);

形参角度

位置参数

形参的位置参数和实参的位置参数一样,按照从左至右,一一对应;

默认值参数

在函数声明的时候,就可以给出函数参数的默认值,默认值参数一般是这个参数使用率较高,才会设置默认值参数

def stu_info(name, age, sex='男'):   # 录入学院信息,发现男生较多的时候,可以设置默认值
    print('录入学生信息')
    print(name, age, sex)
    print('录入完毕')
stu_info('张三', 11)

在位置参数,才能声明关键字参数;

动态参数

动态参数分为两种:

  1. 动态接收位置参数 *args
  2. 动态接收关键字参数 **kwargs

动态接收位置参数:*args

def eat(*args):
    print('今天我们吃的有:', args)
eat('蒸羊羔儿','蒸熊掌','蒸鹿尾儿','烧花鸭','烧雏鸡','烧子鹅')
# 今天我们吃的有: ('蒸羊羔儿', '蒸熊掌', '蒸鹿尾儿', '烧花鸭', '烧雏鸡', '烧子鹅')

args就是一个普通的形参,如果在args前加有个*,就具有了特殊意义。这样设置形参,这个形参会将实参所有的位置参数接收,放置在一个元组中,并将这个元组赋值给args这个形参;

练习:

# 传入函数中数量不定的int型数据,函数计算返回所有数的和并返回
def sum_max(*args):
    n = 0
    for i in args:
        n += i
    return n
print(sum_max(1, 2, 3, 4, 5, 6, 7, 8, 9))
# 45

动态接收关键字参数:**kwargs

实参角度有位置参数和关键字参数两种,*args接受所有位置参数,**kwargs接收所有关键字参数。接收所有关键字参数,然后将其转化成一个字典赋值给kwargs这个参数;

def func(**kwargs):
    print(kwargs)
func(name='黑色利穆', sex='男')
# {'name': '黑色利穆', 'sex': '男'}

动态参数的万能写法:

def func(*args, **kwargs):
    print(args)
    print(kwargs)
func('蒸羊羔儿','蒸熊掌','蒸鹿尾儿', name='黑色利穆', sex='男')
# ('蒸羊羔儿', '蒸熊掌', '蒸鹿尾儿')
# {'name': '黑色利穆', 'sex': '男'}

*的魔性用法

*的用法:

  1. 函数中分为打散和聚合;
  2. 函数外可以处理剩余的元素;

函数的打散和聚合

聚合:

*args将多个位置参数的实参,转成元组;**kwargs将多个关键词参数的实参,转成字典;起到的就是聚合作用;

打散:

s = 'HSLM'
l = [1, 2, 3, 4]
tu = ('黑色', '利穆')
def func(*args):
    print(args)
func(s, l, tu)
# ('HSLM', [1, 2, 3, 4], ('黑色', '利穆'))
func(*s, *l, *tu)
# ('H', 'S', 'L', 'M', 1, 2, 3, 4, '黑色', '利穆')

dic1 = {'name': '黑色利穆', 'age': 25}
dic2 = {'hobby': '唱歌', 'sex': '男'}
def func(**kwargs):
    print(kwargs)
func(**dic1, **dic2)
# {'name': '黑色利穆', 'age': 25, 'hobby': '唱歌', 'sex': '男'}

*处理剩下的元素

# 分别赋值
a, b = (1, 2)
print(a, b)
# 1 2

a, *b = (1, 2, 3, 4)
print(a, b)
# 1 [2, 3, 4]

*rest, a, b = range(5)
print(rest, a, b)
# [0, 1, 2] 3 4

print([1, 2, *[3, 4, 5]])
# [1, 2, 3, 4, 5]

形参的第四种参数:仅限关键字参数

位置:放在*args后面,kwargs前面,默认参数的位置。与默认参数的前后顺序无所谓,只接受关键字传的参数:

def func(a, b, *args, c):
    print(a, b)
    print(args)
    print(c)
func(1, 2, 3, 4, c=5)
# 1 2
# (3, 4)
# 5

形参的顺序

位置参数,*args,默认参数,仅限关键字参数, **kwargs

练习:

'''
def foo(a,b,*args,c,sex=None,**kwargs):
    print(a,b)
    print(c)
    print(sex)
    print(args)
    print(kwargs)
# foo(1,2,3,4,c=6)
# foo(1,2,sex='男',name='alex',hobby='黑色利穆')
# foo(1,2,3,4,name='黑色利穆',sex='男')
# foo(1,2,c=18)
# foo(2, 3, [1, 2, 3],c=13,hobby='喝茶')
# foo(*[1, 2, 3, 4],**{'name':'黑色','c':12,'sex':'女'})
'''

名称空间,作用域

名称空间

  1. 全局命名空间 :直接在py文件中,函数外声明的变量都输全局命名空间;
  2. 局部命名空间:在函数中声明的变量会放在局部命名空间;
  3. 内置命名空间:存放python解释器为我们提供的名字,list,tuple,str,int这些都是内置命名空间;

加载顺序

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

取值顺序

局部名称空间 -- 全局名称空间 -- 内置名称空间

作用域

作用域就是作用范围,按照生效范围分为全局作用域和局部作用域;

全局作用域:包含内置命名空间和全局命名空间,在整个文件的任何位置都可以使用(遵循从上到下逐行执行);

局部作用域:在函数内部可以使用;

作用域命名空间:

  1. 全局作用域:全局命名空间, 内置命名空间
  2. 局部作用域:局部命名空间

内置函数globals(), locals()

globals():字典的形式返回全局作用域所有的变量对应关系;

locals():字典的形式返回当前作用域的变量的对应关系;

# 在全局作用域下打印
a = 2
b = 3
print(globals())
print(locals())


# 在局部作用域打印
a = 2
b = 3
def foo():
    c = 3
    print(globals())
    print(locals())
foo()

高阶函数(函数的嵌套)

只要遇见函数名+()就是函数的调用,如果没有就不是函数的调用;

# 例3:
def fun2():
    print(2)
    def fun3():
        print(6)
    print(4)
    fun3()
    print(8)
print(3)
fun2()
print(5)# 例1:
def func1():
    print('in func1')
    print(3)
def func2():
    print('in func2')
    print(4)
func1()
print(1)
func2()
print(2)


# 例2:
def func1():
    print('in func1')
    print(3)
def func2():
    print('in func2')
    func1()
    print(4)
print(1)
func2()
print(2)


# 例3:
def fun2():
    print(2)
    def fun3():
        print(6)
    print(4)
    fun3()
    print(8)
print(3)
fun2()
print(5)

关键字:global,nonlocal

global

局部作用域对全局作用域的变量(此变量只能是不可变的数据类型)只能引用,不能改变;需要改变时就要用到关键字global:

global作用:

  1. 声明一个全局变量
  2. 局部作用域对全局作用域的全局变量进行修改时,用global
count = 1
def search():
    global count
    count = 2
search()
print(count)
# 2

def func():
    global a
    a = 3
func()
print(a)
# 3

nonlocal

局部作用域想对父级作用域的变量进行改变时,需要用到nonlocal;

nonlocal作用:

  1. 不能改变全局变量;
  2. 在局部作用域中,对父级作用域(或者更外层作用域非全局作用域)的变量进行引用和修改,并且引用的那层及下变量全部发生改变;
def add_b():
    b = 33
    def do_global():
        b = 10
        print(b)
        def dd_nonlocal():
            nonlocal b
            b = b + 10
            print(b)
        dd_nonlocal()
        print(b)
    do_global()
    print(b)
add_b()
# 10
# 20
# 20
# 33
posted @ 2020-12-03 18:46  黑色利穆  阅读(86)  评论(0编辑  收藏  举报