python 函数(一)

函数初识/名称空间/作用域/高阶函数/globals()local()/关键字global/nonlocal

函数初识

1、函数基本组成

写一个函数

def my_len(s):
    count = 0
    for i in s:
        count += 1
    return count

s1 = "aldjfalkdjfd"
s1_len = my_len(s1)
print(s1_len)

# def : 关键字

# my_len : 函数名

# s : 形参

# return : 返回 return 可以返回一个或多个值,返回一个值的时候,值是什么类型的数据,返回就是什么类型的数据,值是多个的时候,返回一个元祖

# 函数如果没有return的话返回None

# 函数的作用:减少重复的代码,提高代码的复用性,是代码更加简洁,可读性强

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

2、函数传参

# 函数的传参:让函数封装的这个功能,盘活

# 实参,形参

def my_len(s):
    count = 0
    for i in s:
        count += 1
    return count

s1 = "aldjfalkdjfd"
s1_len = my_len(s1)
print(s1_len)

# s就是形参

# s1就是实参

3、实参角度分类

1、位置参数:

从左至右,一一对应

# 练习题

# 写一个函数,只接收两个int的参数,函数的功能是将较大的数返回
def big_num(a, b):
    if type(a) is int and type(b) is int:
        if a > b:
            return a
        else:
            return b
ret = big_num(23, '4')
print(ret)

# 三元运算符

就是简单的  if  else

a = 10
b = 20
c = a if a>b else b     # a > b的话,c = a,否则 c = b
print(c)

答案:20


上面的也可以写成这样

def complit(a,b):
    return a if a>b else b
a = 10
b = 20
print(complit(a,b))

答案:20


#  2、关键字参数

def userinfo(name,age,area,telnum):
    print("姓名:%s age:%s area:%s telnum:%s" %(name,age,area,telnum))

userinfo(name="bob",age=18,area="henan",telnum=1234324354)
userinfo(age=23,area='hanguo',name='simida',telnum=2343244)

显示结果:

姓名:bob age:18 area:henan telnum:1234324354
姓名:simida age:23 area:hanguo telnum:2343244


# 练习题
# 函数:传入两个字符串参数,将两个参数拼接完成后形成的结果返回。
def join_str(a,b):    
    return a + b

a = "bob"
b = 'sb'
ret = join_str(a=a,b=b)
print(ret)

显示结果: bobsb


# 3、混合参数
# 1、位置参数一定要在关键字参数的前面
# 2、不可以重复传参:重复传参也就是位置参数传入了一次,然后关键字参数又去传一次

def userinfo(name,age,area,telnum):
    print("姓名:%s age:%s area:%s telnum:%s" %(name,age,area,telnum))

userinfo("juice",18,telnum=23425454,area="diqiu")

显示结果:

姓名:juice age:18 area:diqiu telnum:23425454

4、形参角度分类

# 1、位置参数    :同实参的位置参数,都是从左到右,一一对应

# 2、默认参数    :在进行函数调用的时候,可以传值也可以不传值,传值的话就用传入的值,没有传的话就用默认的值

def userinfo(name,age,sex='男'):
    print('姓名:%s  age:%s  性别:%s'%(name,age,sex))

userinfo("alex",18,sex='女')
userinfo('bob',20)

答案:

姓名:alex  age:18  性别:女
姓名:bob  age:20  性别:男


# 3、万能参数

# 定义一个函数:注意开放封闭原则
def eat(a,b,c,d):
    print('请你吃:%s %s %s %s'%(a,b,c,d))
eat('鸡','鸭','鱼','肉')
# 上面的eat的参数就写死了,如果需要扩展更多的食物就的修改函数里面的源代码,这就违反了开放封闭原则
# *
def eat(*args):
    food = '请你吃:'
    for i in range(len(args)):
        food += args[i]
    return food
print(eat('鸡','鸭','鱼','肉','羊','牛肉'))

# *args可以接收任意的位置参数,你在扩展的时候就不用动源代码,只需要在调用的时候传入参数即可


练习题

# 写一个函数,计算传入函数的所有的数字的和
def sum_func(*args):
    sum = 0
    for i in args:
        if type(i) is int:
            sum += i
    return sum
ret = sum_func(2,3,7,8,3,7,30,"alex")
print(ret)

答案:60

# *args是接收所有的位置参数,哪来接收所有的关键字参数呢?    **kwargs

def fun(**kwargs):
    print(kwargs)
fun(name='bob',age=50)   # 打印:{'name': 'bob', 'age': 50}
# ** 会把所有的关键字参数转换成字典赋值给kwargs

# 4、仅限关键字参数

# 形参里面的仅限关键字参数,比如下面的函数
def func(*args,c,**kwargs):         # c就是仅限关键字参数
    print(args)
    print(c)
    print(kwargs)
func(1,3,name='alex',c=5,age=18)       # 调用的时候必须以关键字参数调用,也就是说必须写成 c=多少,调用的时候仅限关键字参数的位置要放在位置参数的后面
# 答案:
(1, 3)
5
{'name': 'alex', 'age': 18}


5、参数的传入顺序

# 位置参数,*args, 仅限关键字参数,位置参数,**kwargs      # 其中仅限关键字参数和位置参数可以调换位置

6、实参中的*,*的魔性用法

#  *  **在函数调用时,* 代表打散
def func(*args,**kwargs):
    print(args)
    print(kwargs)
# func([1,2],[3,4])
# 答案
'''
([1, 2], [3, 4])
{}
'''

# func(*[1,2],*[3,4])            # 相当于:  func(1,2,3,4)
# 结果:
'''
(1, 2, 3, 4)
{}
'''

func(**{"a":"alex"},**{'b':'dt'})    # 相当于: func(a='alex',b='dt')
# 结果:
'''
()
{'a': 'alex', 'b': 'dt'}
'''

func(*[1,3],*[5,9],**{'name':'bob','age':18})
# 结果:
'''
(1, 3, 5, 9)
{'name': 'bob', 'age': 18}
'''

func(2,4,*[1,3],*[5,9],**{'name':'bob','age':18})
# 结果:
'''
(2, 4, 1, 3, 5, 9)
{'name': 'bob', 'age': 18}
'''


python的名称空间

# 名称空间分类

1、内置名称空间(builtins.py)

2、全局名称空间(当前py文件)

3、局部名称空间(函数,函数执行时才开辟)


# 加载顺序

内置名称空间  -----  全局名称空间 ------  局部名称空间(函数执行时)

image

作用域

分类:

1、全局作业域   (包括内置名称空间、全局名称空间)

2、局部作业域     (局部名称空间)

a = "bob"
def func():
    b = "jim"
    print(b)
    print(a)
func()

# 显示结果:"jim"   "bob"

在这里:   a就在全局作业域里面,b在局部作用域里面,局部作用域可以引用全局作用域的变量,但是不可以修改全局作用域的变量,全局作用域不可以使用局部作用域的变量

比如下面的代码:

a = "bob"
def func():
    b = "jim"
    print(b)
    print(a)
    a += "sb"
func()

***这就会报错:UnboundLocalError: local variable 'a' referenced before assignment


为什么局部作用域不可以修改全局作用域的变量?

# 是因为局部作用域修改全局作用域的变量时,解释器就会认为在局部作用域里面已经

定义了该变量,所以就报错。


取值顺序

遵循的原则:就近原则,LEGB原则,如下图

image

函数的嵌套(高阶函数)

想要明白函数的嵌套,关键点:只要遇见了函数名+()就是函数的调用,如果没有就不是函数的调用:举例:

例1:

def func1():
    print('in func1')
    print(3)
def func2():
    print('in func2')
    print(4)
func1()
print(1)
func2()
print(2)
#  显示结果:   'in func1'  3   1  'in func2'  4   2

image

例2:


def func1():
    print('in func1')
    print(3)
def func2():
    print('in func2')
    func1()
    print(4)
print(1)
func2()
print(2)
# 显示结果:1   'in func2'  'in func1'  3   4  2

image

例3


def func2():
    print(2)
    def func3():
        print(6)
    print(4)
    func3()
    print(8)
print(3)
func2()
print(5)
# 显示结果:3   2   4   6   8   5

image

globals()   local()

# globals()  local()都是字典 

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

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

def func1():
age = 35
print(locals())
print(globals())
func1()

显示结果:

{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000024DF527F588>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'F:/python_project/python_22/day10/s2 global local.py', '__cached__': None, 'name': 'alex', 'func1': <function func1 at 0x0000024DF53373A8>}


{'age': 35}

函数补充

当默认参数是个可变参数时,调用的时候不传值的话,他们共用的是默认参数开辟的内存所在的内存地址

补充1:

def func1(a,b=[]):
    b.append(a)
    return b
ret1 = func1(20)
print(ret1)
ret2 = func1(10)
print(ret2)
# 显示结果:[20,]    [20,10]

11

补充2:

def func1(a,b=[]):
    b.append(a)
    return b
ret1 = func1(20)
ret2 = func1(10)
print(ret1)
print(ret2)
#  显示结果:   [20,10]      [20,10]

补充3:

def func1(a,list=[]):
    list.append(a)
    return list
ret1 = func1(20)
print(ret1)
ret2 = func1(10,[])
print(ret2)
# 显示结果:  [20,]    [10,]

补充4:

def func1(a,list = []):
    list.append(a)
    return list
ret1 = func1(20)
ret2 = func1(10,[])
ret3 = func1(100)
print(ret1)
print(ret2)
print(ret3)
# 显示结果: [20,100]    [10,]  [20,100]

总结:通过几个补充的例子,知道了默认值是可变数据类型时,要特别注意

补充5

count = 1
def func():
    count += 1                # 局部作用域只能引用全局作用域的变量,而不能修改
    print(count)
func()

# 显示结果:会报错

UnboundLocalError: local variable 'count' referenced before assignment


补充6:在函数中,如果你定义了一个变量,但是在定义这个变量之前对其引用了,那么解释器认为:语法问题。应该是在使用前先定义。

count = 1
def func():
    print(count)              # 解释器会以为你是先引用后定义
    count = 2
func()

# 显示结果:

UnboundLocalError: local variable 'count' referenced before assignment

关键字global   nonlocal

global:

# 有些时候就想在局部作用域里面改全局作用域里面的变量怎么办呢?

name = 'alex'
def func():
    name = 'bob'
    print(name)
func()
print(name)
# 显示结果:  bob   alex

name = 'alex'
def func():
    global name
    name = 'bob'
    print(name)
func()
print(name)
#   显示结果: 'bob'   'bob'

# global里面定义的变量,如果函数没有执行的话,全局是没有这个变量的,会报错
def func():
    global name
    name = 'alex'
    print(name)
print(name)
func()
# 显示结果:NameError: name 'name' is not defined

小结:global可以对全局变量进行引用和修改

nonlocal:

# nonlocal局部作用域对父级作用域的变量进行引用和修改

def func():
    name = 'alex'
    def inner():
        nonlocal name
        name = 'bob'
    inner()
    print(name)
func()        # 显示结果:  'bob'
 # 显示结果:  'bob'

image

# 小结:

1、nonlocal不能更改全局变量

2、局部作用域对父级作用域的变量进行引用和修改



----------------------- end -------------------------

posted @ 2020-04-09 15:57  全爱国  阅读(251)  评论(0编辑  收藏  举报