学习的敌人是自己的满足,要认真学习一点东西,必须从不自满开始。对自己,“学而不厌”,对人家,“诲人不倦”;
函数的复用非常重要,一套定义只需要定义一次;
在传参数、使用函数的时候,对引用类型一定要小心;
本章总结:
函数默认值中,可变类型与不可变类型的引用是 不同的;
- 可变类型list,set等 函数的默认值是可以多次复用的;(引用类型与非引用类型的区别), 默认引用类型,引用类型的元素变动,并不是元组的变化;
- 默认值参数只初始化一次
- print(bar.defaults) 与顺序相关;
print(bar.kwdefaults) 与字典相关;- 缺省值是函数对象本身的特殊属性,它是放在函数对象上的,函数对象是跟函数定义相关,函数标识符在内存中就关联到函数定义中去了;
- 影子拷贝可以防止 引用类型的复用的;看看是不是你想要的结果;
1.函数默认值的本质
下面重点介绍默认值参数的坑,虽然说是两个坑,但实际上是一个意思。
————使用可变类型作为默认值,就有可能修改这个默认值;(你需要看看这些变量是否会变化!)
1.1 默认值参数的值是在函数定义时确定的
默认值参数只初始化一次
def foo(xyz=[1]): #默认值参数只初始化一次
xyz += [1]
print(xyz)
foo()
foo()
------------------
[1, 1]
[1, 1, 1]
传入值每次都重新传入,调用函数;
def foo(xyz=[1]):
xyz += [1]
print(xyz)
foo([1])
foo([1])
foo([1])
----------------------
[1, 1]
[1, 1]
[1, 1]
1.2 默认值参数只初始化一次
如果参数的默认值是数字、字符串、元组或其他不可变类型的数据,并不会有什么影响,但是如果参数的默认值是列表、字典、集合等可变类型数据的话,这里有个大坑。
可变类型list,set等 的默认值是可以复用的;
可变类型与不可变类型变量的默认值区别:
def foo(xyz=[1]):
#xyz = bar.__defaults__
xyz += [1] # xyz = xyz +1
print(xyz)
def bar(xyz=1):
#xyz = foo.__defaults__ # [1,1]
xyz += 1
print(xyz)
bar()
bar()
bar()
print(bar.__defaults__) #查看函数对象缺省值;
print(foo.__defaults__)
-------------------------------------------------
2
2
2
(1,)
([1],)
可变类型的默认值是可以复用的;
>>> def demo(newitem, old_list=[]):
old_list.append(newitem)
return old_list
>>> print(demo('5', [1, 2, 3, 4]))
[1, 2, 3, 4, '5']
>>> print(demo('aaa', ['a', 'b']))
['a', 'b', 'aaa']
>>> print(demo('a'))
['a']
>>> print(demo('b')) #注意这里的输出结果
['a', 'b']
如果想得到正确结果,建议把函数写成下面的样子:
def demo(newitem, old_list=None):
if old_list is None:
old_list = [] # old_list=[:]
old_list.append(newitem)
return old_list
例子1:
def foo(xyz=None,u='abc',z=123):
if xyz is None:
xyz = []
xyz.append(1)
print(xyz)
foo()
print(foo.__defaults__)
foo()
print(foo.__defaults__)
foo([10])
print(foo.__defaults__)
foo([10,5])
print(foo.__defaults__)
-------------------------------------------
[1]
(None, 'abc', 123)
[1]
(None, 'abc', 123)
[10, 1]
(None, 'abc', 123)
[10, 5, 1]
(None, 'abc', 123)
定义函数默认的形式
1. 函数默认的定义形式(最复杂的形式):
def bar(xyz,a=2, b='abc', c=(4,), *args, m=5, n=[],**kwargs): # m,n为kwargs
pass
print(bar.__defaults__)
print(bar.__kwdefaults__) # 关键字参数**kwargs缺省值给 前面的m,n 关键字;
-----------------------------------------------
(2, 'abc', (4,))
{'m': 5, 'n': []}
可变类型复用的常见形式;
def foo(w,u = 'abc', *, z=123, zz=[456]):
u = 'xyz'
z = 789
zz.append(1)
print(w,u,z,zz)
print(foo.__defaults__)
foo('mageedu')
foo('mageedu')
print(foo.__kwdefaults__)
------------------------------------------------
('abc',)
mageedu xyz 789 [456, 1]
mageedu xyz 789 [456, 1, 1]
{'z': 123, 'zz': [456, 1, 1]}
函数默认值的作用域
防止可变类型的复用;
def foo(xyz=[],u = 'abc', z=123):
xyz = xyz[:]
xyz.append(1)
print(xyz)
foo()
print(foo.__defaults__)
foo()
foo()
print(foo.__defaults__)
--------------------------------------------
[1]
([], 'abc', 123)
[1]
[1]
([], 'abc', 123)
函数定义小技巧:不会把内容写死;既可以做复用,也可以做不可变类型;
def foo(xyz=None, u='abc', z=123):
if xyz is None:
xyz = []
xyz.append(1)
print(xyz)
return xyz
foo()
foo()
print(foo.__defaults__)
foo([10])
print(foo.__defaults__)
d = foo([10,5]) # [10 , 5 ,1]
print(foo.__defaults__)
foo(d) #[10 , 5 ,1, 1]
--------------------------------------------
[1]
[1]
(None, 'abc', 123)
[10, 1]
(None, 'abc', 123)
[10, 5, 1]
(None, 'abc', 123)
[10, 5, 1, 1]
[10, 5, 1, 1]
2.重要的函数属性
__ 是两个字符(注意)双下划线;
_doc返回指定函数的文档字符串。
_name返回函数名字。
_module_返回函数定义所在模块的名字。
func._defaults返回一个包含默认参数值的元组。
func._globals返回一个包含函数全局变量的字典引用。
func._dict返回支持任意函数属性的命名空间。
func._closure返回一个胞体元组,其中胞体包含了函数自由变量的绑定。
def foo(xyz=[1]):
xyz += [1]
print(xyz)
foo()
print(foo.__defaults__)
-----------------------------
[1, 1]
([1, 1],)
网友评论