您当前的位置: 首页 >  Python
  • 0浏览

    0关注

    214博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

python(10):函数(变量-作用域-递归函数-命名空间)

不愿透露姓名の网友 发布时间:2019-07-23 19:13:45 ,浏览量:0

在这里插入图片描述

文章目录
  • 一、关于*的一些打散功能
  • 二、了解函数
  • 三、函数的返回值return
  • 四、函数的参数
    • 1.无参数的函数
    • 2.有参数的函数
  • 五、函数的命名空间
  • 六、全局变量和局部变量
  • 七、函数的作用域以及执行顺序(LEGB)
  • 八、递归函数
  • 九、Python的常见内置函数
  • 十、匿名函数:lambda

一、关于*的一些打散功能

在说函数之前我们先了解一下*号,这个*好在传入可变参数和接收多个值会偶尔使用到

# ---------------------------全部打散
a = [1, 2, 3, 4, 5]
b = (1, 2, 3, 4, 5)
c = {1, 2, 3, 4, 5}
d = '12345'
print(*a)  # 1 2 3 4 5
print(*b)  # 1 2 3 4 5
print(*c)  # 1 2 3 4 5
print(*d)  # 1 2 3 4 5

# -----------------------------部分打散
a = [1, 2, 3, 4, 5]
b, *c = a
print(b)  # 1
print(c)  # 2,3,4,5

d, *e, f = a
print(d)  # 1
print(e)  # [2, 3, 4]
print(f)  # 5
二、了解函数

问题1:什么是函数呢?

函数是为了将相同功能的一段代码进行封装,然后我们在使用的时候不用写重复代码,只需要传入规定的参数,然后执行对应的功能即可。

下边是函数的一个基本格式

def func(argument1, argument2):#参数可有可无,可多可少
	"""我是注释,一般可以写函数的功能,还有参数分别是什么 和 返回值的返回内容"""
    pass
    return argument1, argument2(返回值可有可无,)

问题2:那么我们函数有什么特点呢?:

  1. 函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段。
  2. 函数必须先定义后调用,定义的时候函数代码块以 def 关键词开头,后接函数标识符名称和()
  3. 函数内容以冒号起始,并且缩进。
  4. 函数的第一行语句可以选择性地使用文档字符串—用于存放函数说明。
  5. return [表达式] 结束函数,选择性地返回一个值给调用方。不写return或者只写return默认返回None,并且返回值可以设置多个
  6. 函数的本质是调用对应函数名的内存地址

问题3:关于函数名字的定义规则?

  1. 字母,下划线和数字组成,且数字不能开头
  2. 长度任意长
  3. 不能和python关键字同名
三、函数的返回值return

就是执行该函数,返回一个或多个规定好的值

注意:

  1. 函数可以有1个或者多个返回值
  2. return后边不写返回的内容,默认返回None
  3. return一个作用是返回内容,另一个作用是结束函数(函数一旦执行return,函数立刻终止)
def fun():
    return "hello"

	print(1111) # 已经return,无法执行


x = fun()
print(x)     # hello
四、函数的参数

问题:什么是函数的参数?

1.举一个例子,当我们孩子进入一个学校,我们输入孩子的名字,学校直接告诉我们孩子是不是我们学校的学生,那么我们把学校告诉我们这件事看出一个函数,然后孩子的名字就是我们需要告知学校的参数。 2.同样有的函数也可以不传参数,只执行他自己的事情,我们调用函数就只是一个触发他的过程,例如我们碰见亲爱的领导,叫了一声领导,但是领导没理你,那么这种时候只是单纯起一个叫他的过程。

关于函数参数顺序遵循: 位置参数,元组参数,默认参数,字典参数

1.无参数的函数
def print_():
    print('hello world')

print_()         # 输出hello world
print_()         # 输出hello world
2.有参数的函数

我们先了解什么是实参和形参?

  • 形参就是函数名圆括号里面的参数,形参包括默认参数,可变参数
  • 实参就是我们调用函数时候传入的参数,传参需要按照规定的形式填,实参包含关键字参数,顺序参数

① 位置(顺序)参数和关键字参数

def add(name, age, sex):  # 此处参数位置叫形参,定义的时候没有实际的值
    """
        函数执行了一个传入名字年龄性别而返回一句话的内容,返回值msg为一句话
    """
    msg = f'我叫{name},年龄{age}岁,性别是{sex}生。'
    return msg

#  ---------------------实参:此处调用函数括号的参数叫实参,因为此处的参数有实际的值

 # 位置参数:传入值的顺序要与实际参数相对应,那么这种一般按顺序对应的就叫位置参数
result =add('彪子', '18', '女') 
print(result) # 我叫彪子,年龄18岁,性别是女生。


# 关键词参数:关键词参数可以不按原函数定义参数顺序写。但是关键字参数和位置参数同时使用时候,关键字参数必须放在位置参数后边
result1 = add(name='彪子', age='18', sex='女')  # 全部关键字参数
print(result1)  # 我叫彪子,年龄18岁,性别是女生。

result2 = add('彪子', '18', sex='女')  # 部分关键字参数
print(result2)  # 我叫彪子,年龄18岁,性别是女生。

②默认参数

  • 默认参数要有不可变类型的对象,如果是可变类型,可能有逻辑错误。
  • 默认参数针对的形参
def fun(name,age,sex='男'):
    print('名字:',name)
    print('年龄:',age)
    print('性别:', sex)
    
fun('张三',18 )                  #sex不写,则按函数定义时候的默认参数 男 进行赋值
fun('李四',18,'女')              #sex写后,会把默认参数的值重新赋值

结果: 在这里插入图片描述 ④可变参数

*args,一个*号,传入的为元组形式,即使传入一个值也会为元组

def fun(*args):                     
    print(args,type(args))
    
fun()
fun(1)
fun(1,2,3,4)

结果: 在这里插入图片描述

**kwargs,传入的是字典参数(传入形式: 键值名=参数)

def fun(**kwargs):
    print(kwargs,type(kwargs))

fun(name='张三',age=18)

结果: 在这里插入图片描述

五、函数的命名空间

Python中的三种命名空间

内置命名空间 —— python解释器

  • 就是python解释器一启动就可以使用的名字存储在内置命名空间中
  • 内置的名字在启动解释器的时候被加载进内存里

全局命名空间 —— 我们写的代码但不是函数中的代码

  • 是在程序从上到下被执行的过程中依次加载进内存的
  • 放置了我们设置的所有变量名和函数名

局部命名空间 —— 函数

  • 就是函数内部定义的名字
  • 当调用函数的时候 才会产生这个名称空间 随着函数执行的结束 这个命名空间就又消失了

注意:

  • 在局部:可以使用全局、内置命名空间中的名字
  • 在全局:可以使用内置命名空间中的名字,但是不能用局部中使用
  • 在内置:不能使用局部和全局的名字的
六、全局变量和局部变量

问题如果我们在外部想使用局部的变量怎么办呢?

  • global()函数可以访问全局命名空间
  • locals()可以访问局部名称空间

在这里插入图片描述 而且我们使用global可以在局部改变全局的a值(前提是本身函数内部没有定义a) 在这里插入图片描述

问题:如何实现局部变量和全局变量的互相修改呢?

  • global可以将局部变量变为全局变量
  • nonlocal可以修改外层(非全局)变量

global使用

def fun():
    global a
    a+=20
    print('函数内部:',a)
    
a=10
fun()
print('函数外部',a)

结果: 在这里插入图片描述

nonlocal使用

def fun():
    a=9
    def fun1():#--------------函数嵌套enclosing
        nonlocal a#-------------可以修改外层(非全局)的变量
        a=98#--------------就是将外层的a=9改变为98
        print('我是内部',a)

    fun1()
    print('我是外部',a)

fun()

结果: 在这里插入图片描述

七、函数的作用域以及执行顺序(LEGB)

问题:函数的作用域,是指一个参数在定义后的使用区间,如果一个函数调用了一个值,那么函数是怎么在代码里找到这个值呢?

这是一个函数套函数的形式,我们作用域遵循的原则就是LEGB

a = 1
b = 2
c = 3

def fun_out():
    a = 10
    b = 20
    def fun_in():
        a = 100
        print(a)#-----------L Local(函数内部)首先查找局部作用域,有则输出,没有找E
        print(b)#-----------E Enclosing(嵌套函数外层函数的内部)L没有该值就查找嵌套作用域,有则输出,没有向G
        print(c)#-----------G Global(模块全局)E没有该值找全局作用域G,有则输出,没有向B
        print(__name__)#----B Built-in(内建作用域)最后一步,查找内建作用域,,有则输出,没有报错
    fun_in()
    
fun_out()

结果: 在这里插入图片描述

八、递归函数
  • 递归函数是函数的高阶使用了,就是通过规则函数重复的调用自己本身,然后直到符合自己的结束条件参会结束。
  • 但是不能一直重复调用,所以我们需要设置一个明确的结束递归条件,也叫递归出口

递归函数经典案例:斐波那契数列

假定每对大兔每月能生产一对小兔,而每对小兔生长两个月就成为大兔.这个问题导致了著名的数列:1,1,2,3,5,8,13,21,34,55,89,144,233,·…它是一个线性递归数列,那么比如我们初始一只兔子,那么指定月份后,我们有多少只兔子呢

def fbnq(n):
    if n == 1 or n == 2:
        return 1
    else:
        return fbnq(n - 1) + fbnq(n - 2)
n = int(input('请输入月份:'))
for i in range(1,n+1):
    print(i, '月兔子有:', fbnq(i))

结果: 在这里插入图片描述

九、Python的常见内置函数

1.求绝对值的函数:abs()

a=-1
print(abs(a))  # 1

2.求最大值得函数:max()

# 1.无key
a=[0,2,4,2,1,3]
print(max(a))#  返回最大的4

# 2.有key的max(参数,key=函数名)
a=[-1,-2,-4,-6]
b=max(a,key=abs)# 比较的时候按绝对值比较,输出原数值
print(b)

3.列表的内置排序函数(默认升序):sort()

①无key的sort()

b = [-1, -4, -2, -3]
b.sort()
print(b)#----------------------------------[-4,-3,-2,-1]

②有key的sort(参数,key=函数名)

a = [-1, -4, -2, -3]
a.sort(key=abs)#都是升序,只是按执行完的绝对值方法进行的升序,还是写的原值
print(a)#----------------------------------[-1, -2, -3, -4]

③降序

a = [-1, -4, -2, -3]
a.sort(reverse=True)
print(a )# -1,-2,-3,-4]

4.map(函数名,可迭代内容)

会依次将可迭代内容的每个元素执行该函数,并且返回新的值

x = [1, 2, 3, 4, 5]
def fun(x):
    return x * x
    
b = map(fun, x)

# 本身返回一个map对象,需要转换
print(list(b))#  [1, 4, 9, 16, 25]

5.filter(函数名,序列) 会依次将可迭代内容的每个元素执行该函数返回True或False,True的放到新列表,过滤不符合要求的元素,将符合元素放在一个新列表中

# 过滤奇数的方法
def fun(x):
    if x%2==0:
        return True
    else:
        return False
a=[1,2,3,4,5,6]
b=filter(fun,a)

# 本身返回一个filter对象,需要转换
print(list(b))#-------------------------------------------[2,4,6]

6.zip(序列1,序列2,序列3…) 将序列的各个对应元素一一打包成元组,按照最短的算

a=[1,2,3,4]#按照最短的,一一匹配
b=('a','b','c')
c=('啊','哦','窝')
d=zip(a,b,c)
for i in d:
    print(i)

结果:

在这里插入图片描述

十、匿名函数:lambda

1.基本定义

  • 形式: 变量名=lambda 参数1,参数2...:表达式

  • 注意:

    • 匿名函数的表达式参数是未知参数
    • 匿名不能包含循环,return,可以包含if-else
    • lambda表达式会产生一个新的局部作用域
  • 优点: 代码简洁,不增加额外变量

  • 缺点: 难于理解,降低了可读性

2.使用示例

举例1

hs = lambda x, y: x + y
b = hs(2, 3)

print(b) # -----------------------------5

举例2:匿名函数和三元表达式的搭配

max = lambda a, b: a if a > b else b

print(max(3, 4))  #  4

举例3: 匿名函数求列表的偶数

a = [1, 2, 3, 4, 5, 6, 7]

result = list(filter(lambda a: True if a % 2 == 0 else False, a))
print(result)  # [2, 4, 6]

3.匿名函数常见考题

题1:

def hehe():
    a=[]
    for i in range(3):
        a.append(lambda y:y*i)
    return a
z=hehe()
print(z[0](2))#--------------------------4
print(z[1](2))#------------------------4
print(z[2](2))#------------------------------4

原因:因为嵌套作用域的变量在嵌套的函数被调用时才会查找,所以他们实际上是统一的值(最后一次循环变量的值)。 理解方法1:相当于每次往列表里传入一个 lambda y:y * i 的表达式,而这个i真正是:调用的最后一次循环的i 理解方法2:比如第一次循环,往列表添加 lambda y:y * i 的表达式,此时i指向的是0,第二次,又往列表添加一个 lambda y:y*i 的表达式,此时i指向新的1,把原先的0覆盖…,最后指向4

若要改成预期结果,那么只需按照下边的改,或者是将其改造成一个生成器,不会让其提前运行也可

def hehe():
    a = []
    for i in range(3):
        a.append(lambda y, i=i: y * i)#---------此处的i,是默认参数,会自动赋值
    return a


z = hehe()
print(z[0](2))#--------------------------------0
print(z[1](2))#-------------------------------2
print(z[2](2))#-----------------------4

原因:i在每次运行时,都会把遇到的i=常数,赋值给匿名函数

关注
打赏
1657102503
查看更多评论
立即登录/注册

微信扫码登录

0.0558s