Python基础知识_第6节

1389-李同学

发表文章数:35

热门标签

,
首页 » Python » 正文

函数用法和底层分析

函数也是对象,内存底层分析

  • 函数也是对象。函数可以作为参数来传递,也可以作为返回值来返回。
    def print_str(n): 
    	print("str", n)
    c = print_str
    c(3)
    • 函数后面加(),则表示调用。

变量的作用域(全局变量和局部变量)

  • 全局变量
    • 避免使用,降低了函数的通用性和可读性。
    • 一般做常量使用。
    • 函数内要改变全局变量的值,使用global声明一下。
  • 局部变量
    • 优先考虑使用,引用要比全局变量快。
    • 如果局部变量和全局变量同名,则在函数内隐藏全局变量,只使用同名的局部变量
    • 局部变量储存到栈帧(stack frame)中,不能在函数外被调用。
  • 输出局部变量和全局变量
    • 函数内打印locals()、globals()。函数本身算全局变量。

局部变量和全局变量效率测试

  • 在特别强调效率,或者多层loop中,可将全局变量换成局部变量来使用。
def test02(): 
	b = math.sqrt 
	start = time.time() 
	for i in range(10000000):
		b(30) 
	end = time.time() 
	print("耗时{0}".format((end-start)))

参数的传递

  • 可变对象:字典、列表、集合、自定义的对象等。
  • 不可变对象:数字、字符串、元组、布尔值、function等。

传递可变对象的引用

  • 函数引用的是对象的地址。若对可变对象进行引用、修改,对象的的地址不变。

传递不可变对象的引用

  • 函数引用的是对象的地址。若对不可变对象进行再次赋值,对象的地址会改变。

浅拷贝copy和深拷贝deepcopy

  • 浅拷贝:不拷贝子对象的内容,只是拷贝子对象的引用。只拷贝个体。
    >>> import copy
    >>> def testCopy(): 
    	''' 测试浅拷贝 ''' 
    	>>> a = [10, 20, [5, 6]] 
    	>>> b = copy.copy(a)
    	>>> print("a", a) 
    	>>> print("b", b) 
    	
    	>>> b.append(30) 
    	>>> b[2].append(7) 
    	>>> print("浅拷贝......") 
    	>>> print("a", a) 
    	>>> print("b", b)
    	
    a [10, 20, [5, 6]] 
    b [10, 20, [5, 6]] 
    浅拷贝...... 
    a [10, 20, [5, 6, 7]] 
    b [10, 20, [5, 6, 7], 30] 

Python基础知识_第6节

  • 深拷贝:会连子对象的内存也全部拷贝一份,对子对象的修改不会影响源对象。拷贝一整个家族。
    >>> import copy
    >>> def testDeepCopy(): 
         ''' 测试浅拷贝 ''' 
         >>> a = [10, 20, [5, 6]] 
         >>> b = copy.deepcopy(a)
         >>> print("a", a) 
         >>> print("b", b) 
         
         >>> b.append(30) 
         >>> b[2].append(7) 
         >>> print("深拷贝......") 
         >>> print("a", a) 
         >>> print("b", b)
         
    a [10, 20, [5, 6]] 
    b [10, 20, [5, 6]] 
    深拷贝...... 
    a [10, 20, [5, 6]] 
    b [10, 20, [5, 6, 7], 30] 

Python基础知识_第6节

传递不可变对象时,如果发生拷贝,是浅拷贝

  • 传递不可变对象时。若不可变对象里面包含的子对象是可变的,且函数内对该子对象重新赋值,则源对象也会随之改变。
>>> a = (10,20,[5,6]) 
>>> print("a:",id(a))

>>> def test01(m): 
>>>	print("m:",id(m)) 
>>> 	m[2][0] = 888 
>>>	print(m) 
>>>	print("m:",id(m))

>>> test01(a) 
>>> print(a)

a: 41611632 
m: 41611632 
(10, 20, [888, 6]) 
m: 41611632 
(10, 20, [888, 6])

参数的几种类型

位置参数

  • def fcn(a, b, c):形参实参个数需要匹配,按位置传递参数。

默认值参数

  • def fcn(a, b, c=10, d=20):默认值参数必须位于位置参数后面,可不设置。

命名参数

  • def f1(a,b,c),f1(c=10,a=20,b=30):实参可以不按照形参的顺序,按照名称传递参数。

可变参数

  • 可变参数指的是“可变数量的参数”。分两种情况:
    1. *param(一个星号),将多个参数收集到一个“元组”对象中。
    2. **param(两个星号),将多个参数收集到一个“字典”对象中。
    >>> def f3(a,b,*c,**d): 
    >>>	print(a,b,c,d)
    8 9 (20, 30) {'name': 'gaoqi', 'age': 18}

强制命名参数

  • 在“可变参数”后面增加新的参数,必须是强制命名。
>>> def f1(*a,b,c): 
	>>> print(a,b,c)
>>> f1(2,b=3,c=4)
(2,) 3 4

lambda表达式和匿名函数

  • lambda arg1,arg2,arg3… : <表达式>
  • 表达式只允许包含一个表达式,不能包含复杂语句,该表达式的计算结果就是函数的返回值。
    >>> f = lambda a,b,c:a+b+c 
    >>> print(f) 
    >>> print(f(2,3,4))
    <function <lambda> at 0x0000000002BB8620> 
    9
    
    >>> g = [lambda a:a*2,lambda b:b*3,lambda c:c*4] 
    >>> print(g[0](6))
    12

eval()函数

  • eval(source, globals, locals) —-> value
    • source:表达式或函数compile()返回的代码对象。
    • globals:可选,必须是dictionary。
    • locals:可选,任意映射对象。
  • 字符串当成有效的表达式来求值并返回计算结果。
  • 将字符串当作语句来执行,因此有安全隐患。例如字符串中含有删除文件的语句。要慎重
>>> a = 10 
>>> b = 20 
>>> c = eval("a+b")
>>> print(c)
30

>>> dict1 = dict(a=100, b=200)
>>> d = eval("a+b", dict1)	# 如果不加后面的dict1,则d为30,默认使用global参数。加上dict1后,d为300,使用local函数。
>>> print(d)
300

递归函数 recursion

  • recursion之后的表达式,会在全部调用次数跑完后,一次性运行相应次数。
    • 从内存角度来讲,每次调用函数,会形成一个栈帧stack frame。recursion中,会逐次形成相应数量的栈帧,在出现最后一个栈帧后,再依次关闭这些栈帧。
  • 会消耗大量内存和运算能力。在处理大量数据时,谨慎使用。

未经允许不得转载:作者:1389-李同学, 转载或复制请以 超链接形式 并注明出处 拜师资源博客
原文地址:《Python基础知识_第6节》 发布于2020-11-06

分享到:
赞(0) 打赏

评论 抢沙发

评论前必须登录!

  注册



长按图片转发给朋友

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏

Vieu3.3主题
专业打造轻量级个人企业风格博客主题!专注于前端开发,全站响应式布局自适应模板。

登录

忘记密码 ?

您也可以使用第三方帐号快捷登录

Q Q 登 录
微 博 登 录