这次主要讲的内容是默认函数作用域值(缺省值)
1.先来在一串代码,分析一波:
def foo(x=1): # 形参都是局部变量
x += 1 # 有问题吗?没有,x=出现了,x就是foo函数的局部变量
print(x) #结果为:2
print(foo()) #结果为None
def foo1(y=[]): # 如果没有缺省值
y.append(1) # y是局部变量,y参数不提供就使用缺省值,缺省值在哪里?保存在函数对象上
print(y)
print(foo1(), foo1())
print(foo1([]), foo1([]))
print(foo1.__defaults__) # 缺省值保存在了元组中,元组1个元素,是列表 #默认用元组保存的
#结果为:
None
[1,1]
None,None
[1]
[1]
None None
([1, 1],)
# 小白解释:由于重点---打印[1,1]后,[1,1]转变为[]在进行执行第二次的(print(foo1([]),foo1([]))
#这里没有return值,所以返会None值
#keyword - only参数值的缺省值
def foo(xyz, m=123, *, n='abc', t=[1, 2]):
m = 456
n = 'def'
t.append(300)
print(xyz, m, n, t)
print(foo.__defaults__, foo.__kwdefaults__) #结果为(123,){‘n':'abc','t':[1,2]
foo('magedu') #结果为:madedu,123,abc,[1,2,300]---print(xyz, m, n, t)
print(foo.__defaults__, foo.__kwdefaults__) #结果为:(123,){'n':'abc','t':[1,2]}
这里为大家提供手写模板(图解代码)–字有点丑,不要介意
注意:1.属性__defaults__中使用元组保存所有位置参数默认值
2.属性__kwdefaults__中使用字典保存所有keyword-only参数的默认值
下面为给大家介绍一个知识点:
在函数之前,大家使用x+=1和x=x+1是一样,但是学到函数大家要知道是不一样,id地址不一样
#列表
a = list(range(2))
print(id(a), a)
a += [10] # 地址没有改变
print(id(a), a)
a = a + [20] # 地址发生改变
print(id(a), a) # -----------------不可变类型意为
# 元组
a = tuple(range(2))
print(id(a), a)
a += (10,) # 对于不可变类型元组来讲,将+= --转换为--- ==
print(id(a), a) # 地址发生改变
a += (20,)
print(id(a), a) # 地址发生改变
大家可以参观这两段代码去分析一下,后面还会写到
变量名解析原则
1.Local,本地作用域,局部作用域的local命名空间。函数调用时创建,调用结束消亡。
2.Ennclosing,python2.2时引入了嵌套函数,实现闭包,这个就是嵌套函数的外部函数的命名空间
3.Global,全局作用域,即一个模块的命名空间。模块被import时创建,解释器退出时消亡
4.Build-in,内置模块的命名空间。模块被import时创建,解释器退出时消亡。例如print(open),print和open都是内置的变量
------所以一个名词查找顺序就是LEGB
5.Lambda表达式
python中,使用Lambda表达式构建匿名函数
先来一串代码分析一下,带大家去分析一下:
lambda: 0
fn = lambda: 0
def fn(x):
return x + 1
print(fn)
#大致格式,重点在下面
print((lambda x, y: x + y)(4, 5))
# 结果为9
print((lambda *args: [x for x in args])(4, 5, 6))
# 小白解释:1.*args=(4,5,6)-----[for x in args]---[4,5,6]
print((lambda *args: list(args))(4, 5, 6))
# 小白解释:1.list为列表,可得--[args]--*args=args=(4,5,6)----[args]=[4,5,6]
print((lambda *args: [args])(4, 5, 6))
# 小白解释:1.*args=(4,5,6)----[args]----[(4,5,6)]
print((lambda *args: {x + 1 for x in args})(4, 5, 6))
# 小白解释:1.*args=(4,5,6)---x+1=5,6,7---{5,6,7}
# print((lambda *args: {x + 1 for x in args})(range(5))) # 报错
# 这里的range(10)没有解构---解构为:(*range(5))---0,1,2,3,4----print(range(5))--结果为---range(0,5)
print((lambda *args: {x for x in args})(range(10)))
print(*range(5))
print((lambda *args: {x % 3 for x in args})(*[i for i in range(100)]))
# 小白解释: *[i for i in range(100)]-----解构成0,1,2,3,4......
这上面主要代码运行方式,导航面给大家解释的特别清楚,大家可以看看。
————————————————————————————————————————————
这下面比较进阶了,大家可以看看,每个我都进行了解释
import random
print((lambda *args: {x % 3 for x in args})(*[random.randint(1, 1000) for i in range(100)]))
# 小白解释:[random.randint(1, 1000) for i in range(100)]--这串代码表示为:i是执行100次,在1~1000中随机取100个数
# 接着着100个数=args
# 应用
# 高阶函数使用场景
print(sorted(['a', 1, 'b', 12, 'c', 28], key=str)) # 这里的key=x即为列表中的数
# 对每个元素做str(item),一个参数,返回一个字符串str(item)---这里将所有数字都转换为字符串--这里的1,12,28都是字符串,字符串转换16进制,然后进行比较
# 小白解释:这里进行ASCLL表比较,‘a'转换为16进制以此类推
print(sorted(['a', 1, 'b', 12, 'c', 24], key=lambda item: 100))
# ---执行结果为--['a', 1, 'b', 12, 'c', 24]
# 小白解释:key的值都返回为100,这里的所有数字都记为100,所以都按顺序打印。
print(sorted(['a', 1, 'b', 12, 'c', 28], key=lambda x: str(x))) # 这里也是都转换字符串,在转换16进制进行比较
# 小白解释:一样的道理
print(sorted(['a', 1, 'b', 12, 'c', 28], key=lambda x: int(x, 16) if isinstance(x, str) else x))
# 小白解释:isinstance()内建函数判断数据类型---如果x是字符串,int(x,16)--解释--x将转换16进制,否则转换为x(16进制的数字)
# 16进制对照表:用数字0-9和字母a-f(或其大写A-F)表示0到15
# 这里的int()表示为十六进制的数
这节函数内容结束,如果有错误,希望得到大家的指出!!!