Python推导式和函数

Python推导式

Python 推导式是一种独特的数据处理方式,可以从一个数据序列构建另一个新的数据序列的结构体。

Python 支持各种数据结构的推导式:

  • 列表(list)推导式
  • 字典(dict)推导式
  • 集合(set)推导式
  • 元组(tuple)推导式

1.列表推导式

  • 作用

    用简单的表达式方式来创建列表

  • 语法规则

    [ 表达式 for 自定义变量 in 可迭代对象 ]
    # 或
    [ 表达式 for 自定义变量 in 可迭代对象 if 真值表达式 ]
    
  • 示例

    # 生成一个列表, 里面有 100 个数是[1, 4, 9, 16, 25, ...]
    # 用 for 语句实现
    L = []
    for x in range(1, 101):
        L.append(x ** 2)
    print(L)
    
    # 用列表推导式
    L2 = [ x ** 2 for x in range(1, 101)]
    print(L2)
    
    L3 = []
    for x in range(1, 101):
        if x % 2 == 0:
            L3.append(x ** 2)
    
    L3 = [ x ** 2 for x in range(1, 101) if x % 2 == 0]  # 取出所有的偶数, L3 = [4, 16, 36, ...]
    

2.字典推导式

字典推导基本格式:

  • { 键表达式: 值表达式 for 元素 in 集合 }
  • { 键表达式: 值表达式 for 元素 in 集合 if 条件 }
# 将列表中各字符串值为键,各字符串的长度为值,组成键值对
listdemo = ['karen','jack', 'marry']
newdict = {key:len(key) for key in listdemo}
print(newdict)#{'karen': 5, 'jack': 4, 'marry': 5}


#提供三个数字,以三个数字为键,三个数字的平方为值来创建字典:
dic = {x: x**2 for x in (2, 4, 6)}
print(dic)#{2: 4, 4: 16, 6: 36}

3.集合推导式

集合推导式基本格式:

  • { 表达式 for 元素 in 序列 }
  • { 表达式 for 元素 in 序列 if 条件 }
#计算数字 1,2,3 的平方数:
setnew = {i**2 for i in (1,2,3)}
print(setnew)#{1, 4, 9}


#判断不是 abc 的字母并输出:
a = {x for x in 'abracadabra' if x not in 'abc'}
print(a)#{'d', 'r'}

4.元组推导式

元组推导式可以利用 range 区间、元组、列表、字典和集合等数据类型,快速生成一个满足指定需求的元组。

元组推导式和列表推导式的用法也完全相同,只是元组推导式是用 () 圆括号将各部分括起来,而列表推导式用的是中括号 [],另外元组推导式返回的结果是一个生成器对象。

元组推导式基本格式:

  • (表达式 for 元素 in 序列 )
  • (表达式 for 元素 in 序列 if 条件 )
#生成一个包含数字 1~9 的元组
a = (x for x in range(1,10))
print(a)#返回的是生成器对象
print(tuple(a))#使用 tuple() 函数,可以直接将生成器对象转换成元组

Python函数

1.定义函数

  • 作用

    用于封装语句块,提高代码的重用性

    def 函数名(形式参数列表):
    	语句块
    
  • 说明

    1. 函数代码块以 def 关键词开头,后接函数标识符名称和圆括号 ()

    2. 函数名是一个变量,不要轻易对其赋值

    3. 函数有自己的名字空间,在函数外部不可以访问函数内部的变量,在函数内部可以访问函数外部的变量,但不能轻易对其改变

    4. 函数的形参列表如果不需要传入参数,形式参数列表可以为空

    5. 任何传入参数和自变量必须放在圆括号中间,圆括号之间可以用于定义参数。

    6. 函数内容以冒号 : 起始,并且缩进。

    7. return [表达式] 结束函数,选择性地返回一个值给调用方,不带表达式的 return 相当于返回None。

2. 函数参数

2.1 函数的调用传参
  • 位置传参

​ 实际参数传递时,实参和形参按位置来依次对应

  • 关键字传参

​ 实际参数传递时,实参和形参 按名称依次对应

​ 注:位置传参要先于关键字传参

2.2 函数的形式参数定义方法

函数的缺省参数(默认参数)

语法

def 函数名(形参名1=默认实参1, 形参名2=默认实参2, ... ):
    语句块

说明

缺省参数即默认实参,必须自右向左依次存在(即,如果一个参数有缺省参数,则其右侧的所有参数都必须有缺省参数)

形参的定义

  • 位置形参

    def 函数名(形参名1, 形参名2, ...):
    	pass
    
  • 星号元组形参(*args)

    def 函数名(*元组形参名):
    	pass
    

    作用:收集多余的位置实参,元组形参名一般命名为args

    def myfunc2(*args):
    	print("len(args)=", len(args))
    	print('args=', args)
    
    myfunc2() # args=()
    myfunc2(1, 2, 3) # args=(1, 2, 3)
    
    def myfunc3(a, b, *args):
    	print(a, b, args)
        
    myfunc3(1, 2) # 1-->a, 2-->b, ()--->args
    myfunc3(1, 2, 3, 4) # # 1-->a, 2-->b, (3, 4)--->args
    
  • 命名关键字形参

    def 函数名(*, 命名关键字形参1, 命名关键字形参2, ...):
    	pass
    # 或者
    def 函数名(*args, 命名关键字形参1, 命名关键字形参2, ...):
    	pass
    

    作用:强制,所有的参数都必须用关键字传参

    def myfunc4(a, b,*args, c, d):
    	print(a, b, c, d)
        
    myfunc4(1, 2, d=4, c=3) # 正确,c,d 必须关键字传参
    myfunc4(1, 2, 3, 4) # 错误
    
  • 双星号字典形参(**kwargs)

    def 函数名(**字典形参名):
    	pass
    

    作用:收集多余的关键字传参,字典形参名最多有一个,字典形参名 一般命名为 kwargs

    def myfunc5(**kwargs):
    	print(kwargs)
    	
    # {'name': 'tarena', 'age': 18}-->kwargs
    myfunc5(name='tarena', age=18)
    

函数的形参定义方法说明

  • 位置形参,星号元组形参,命名关键字参数,双星号字典形参,缺省参数可以混合使用。

  • 函数的形参定义自左至右的顺序为:位置形参,星号元组形参,命名关键字参数,双星号字典形参

    def fn(a, b, *args, c, d, **kwargs):
    	print(a)
    	print(b)
    	print(*args)
    	print(c)
    	print(d)
    	print(kwargs)
        
    fn(100, 200, 300, 400, c='C',name='tarena',d='D')
    
2.3 可变不可变

可更改**(mutable)与不可更改(immutable)**对象

在 python 中,strings, tuples, 和 numbers 是不可更改的对象,而 list,dict 等则是可以修改的对象。

  • **不可变类型:**变量赋值 a=5 后再赋值 a=10,这里实际是新生成一个 int 值对象 10,再让 a 指向它,而 5 被丢弃,不是改变 a 的值,相当于新生成了 a。

  • **可变类型:**变量赋值 la=[1,2,3,4] 后再赋值 la[2]=5 则是将 list la 的第三个元素值更改,本身la没有动,只是其内部的一部分值被修改了。

python 函数的参数传递:

  • **不可变类型:**值传递: 如整数、字符串、元组。如 fun(a),传递的只是 a 的值,没有影响 a 对象本身。如果在 fun(a) 内部修改 a 的值,则是新生成一个 a 的对象。

  • **可变类型:**引用传递: 如 列表,字典。如 fun(la),则是将 la 真正的传过去,修改后 fun 外部的 la也会受影响

python 中一切都是对象(后面会讲),严格意义我们不能说值传递还是引用传递,我们应该说传不可变对象和传可变对象。可以通过内置的 id() 函数来查看内存地址变化。

3. 匿名函数

在Python中,匿名函数通常使用 lambda 关键字来创建。匿名函数也被称为lambda函数,它是一种简单的、一行的函数,常用于临时需要一个小函数的地方。匿名函数的语法如下:

lambda [函数的参数列表]: 表达式

作用:

  • 创建一个匿名函数对象

  • lambda 是关键字,表示你正在定义一个匿名函数。

  • 同 def 类似,但不提供函数名

  • [函数的参数列表] 是函数的参数,可以有零个或多个参数,参数之间用逗号分隔。

  • : 表达式 是函数的返回值,通常是一个表达式,匿名函数会计算这个表达式并返回结果。

说明:lambda 表达式 的创建函数只能包含一个表达式

def myadd(x, y):
	return x + y
print('1 + 2 =', myadd(1, 2)) # 3

# myadd 函数可以改写成
myadd2 = lambda x, y: x + y
print('3 + 4 =', myadd2(3, 4)) # 7

square = lambda x: x * x
print(square(5)) # 输出: 25

4. 变量作用域

global: global 语句声明的一个或多个变量, 这些变量是全局变量

global 变量名1, 变量名2, ....

global 说明

  • 全局变量如果要在函数内部被赋值,则必须经过全局声明 global

  • 默认全局变量在函数内部可以使用,但只能取值,不能赋值

  • 不能先声明为局部变量,再用 global 声明为全局变量,此做法不符合语法规则

函数的形参已经是局部变量,不能用 global 声明为全局变量

局部作用域修改外部变量

在函数内部 提前用nonlocal声明 函数内部的某个变量为外部的变量

前提:必须是函数嵌套

说明:

(1)变量的查找顺序还是遵从:LEGB顺序

在 Python 中,LEGB 代表四种作用域的查找顺序:Local、Enclosing、Global 和 Built-in。

(2)局部作用域中若要修改外部函数嵌套作用域中的变量需要使用:nonlocal 语句

​ 格式:nonlocal 变量名

​ 作用:将局部作用域中变量声明为外部函数嵌套作用域中的变量。

LEGB****顺序

Local (L):

  • 本地作用域,指当前函数内部的变量。

  • 当你在函数内部定义变量并尝试访问它时,Python 首先会在函数内部查找这个变量。

Enclosing (E):

  • 闭包函数外的函数作用域,指嵌套函数的外部函数中定义的变量。

  • 如果在当前函数内部找不到变量,Python 会查找外层(闭包)函数中的变量。

Global (G):

  • 全局作用域,指模块级别定义的变量。

  • 如果在本地和闭包函数中找不到变量,Python 会查找全局作用域的变量。

Built-in (B):

  • 内建作用域,指 Python 预定义的变量、函数等,如 len 、 sum 等。

  • 如果在以上三个作用域中都找不到变量,Python 会查找内建作用域。

nonlocal:

  • 内部函数,如果修改外部嵌套变量,需要使用nonlocal语句声明

5. 函数的内存分配

1、将函数的代码存储到代码区,函数体中的代码不执行。

2、调用函数时,在内存中开辟空间(栈帧),存储函数内部定义的变量。

3、函数调用后,栈帧立即被释放。

def func(a, b):
	a = 20
	b[0] = 20
    
a = 10
b = [100]
func(a, b)
print(a) # 10
print(b) # 20

在这里插入图片描述

(1) 不可变类型参数有:

  • 数值型(整数,浮点数)

  • 布尔值bool

  • None 空值

  • 字符串str

  • 元组tuple

(2) 可变类型参数有:

  • 列表 list

  • 字典 dict

  • 集合 set

(3) 传参说明:

  • 不可变类型的数据传参时,函数内部不会改变原数据的值。

  • 可变类型的数据传参时,函数内部可以改变原数据。

6. 函数自调用**(递归)**

函数直接或间接的调用自身

讲故事**😗*

  • 从前有座山,山上有座庙,庙里有个老和尚讲故事
    • 从前有座山,山上有座庙,庙里有个老和尚讲故事
      • 从前有座山,山上有座庙,庙里有个老和尚讲故事

说明:

  • 递归一定要控制递归的层数,当符合某一条件时要终止递归调用

  • 几乎所有的递归都能用while循环来代替

递归的实现方法:

  • 先假设此函数已经实现

递归优缺点:

  • 优点:

    • 递归可以把问题简单化,让思路更为清晰,代码更简洁
  • 缺点:

    • 递归因系统环境影响大,当递归深度太大时,可能会得到不可预知的结果
# 计算阶乘
def factorial(n):
	result = 1
	i = 1
	while i <= n:
		result *= i
		i+=1
	return result

print("factorial: ", factorial(5))

间接的调用自身

讲故事**😗*

  • 从前有座山,山上有座庙,庙里有个老和尚讲故事
    • 从前有座山,山上有座庙,庙里有个老和尚讲故事
      • 从前有座山,山上有座庙,庙里有个老和尚讲故事

说明:

  • 递归一定要控制递归的层数,当符合某一条件时要终止递归调用

  • 几乎所有的递归都能用while循环来代替

递归的实现方法:

  • 先假设此函数已经实现

递归优缺点:

  • 优点:

    • 递归可以把问题简单化,让思路更为清晰,代码更简洁
  • 缺点:

    • 递归因系统环境影响大,当递归深度太大时,可能会得到不可预知的结果
# 计算阶乘
def factorial(n):
	result = 1
	i = 1
	while i <= n:
		result *= i
		i+=1
	return result

print("factorial: ", factorial(5))
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值