python基础

注:python中和C/C++一样的性质,均被略过
本博文将简单解释这部分知识,比较简单,但也相对很基础!将使用idle讲解

1.子函数中不能改变全局变量

>>> a = 'globals'
>>> def foo():
	a = 'locals'
	print(locals())
>>> print(globals())
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, 'a': 'globals', 'foo': <function foo at 0x0000024DC879F1E0>}
>>> foo()
{'a': 'locals'}
>>> print(a)
globals
>>> 

在调用foo()a依旧还是globals
原因在于,局部变量和全局变量和C/C++一样,存放在不同的内存区域,互不影响。
并且,子函数调用变量,先搜索局部变量是否存在再搜索全局变量。

2.函数内嵌与闭包


>>> def out(x):
	def inner():
		return x*2
	print(inner)
	return inner
>>> a = out(2)
<function out.<locals>.inner at 0x0000024DC879FD90>
>>> a
<function out.<locals>.inner at 0x0000024DC879FD90>
>>> a1 = out(3)
<function out.<locals>.inner at 0x0000024DC879FE18>
>>> a1
<function out.<locals>.inner at 0x0000024DC879FE18>
>>> a2 = out(4)
<function out.<locals>.inner at 0x0000024DC7CF1E18>
>>> a2
<function out.<locals>.inner at 0x0000024DC7CF1E18>
>>> a()
4
>>> a1()
6
>>> 

可见,xinner()当作是全局变量的存在,并且函数名也是可以作为对象直接传递或返回,而不需要函数指针这种东西。

闭包就是函数嵌套产生的新概念,在C/C++,返回函数名,只代表返回了这个函数所在地址,其环境未知,在return 2*x会报x未定义错误。
python则不会,上个例子输出a a1 a2 可以看到地址每个a内部的inner地址和a地址是一样的,同时输出表明function out.<locals>.inner我输出的是一个function叫inner,结果和分析吻合;而每个a的地址却不一样,可以推断返回的不仅仅是地址,还有别的信息,这就是有关x的信息了,我们把它叫做引用环境。

闭包 == 函数 + 引用环境

python中,如果在一个内嵌函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内嵌函数就被认为是闭包(closure)。

闭包使用典型错误1:

>>> def out(x):
	def inner():
		x = x*2
		return x
	return inner

>>> c = out(2)
>>> c()
Traceback (most recent call last):
  File "<pyshell#97>", line 1, in <module>
    c()
  File "<pyshell#95>", line 3, in inner
    x = x*2
UnboundLocalError: local variable 'x' referenced before assignment
>>> 

这就报错了???明明几乎一样地code出错了?
原因在于:python的规则是只要出现在等号左边的变量都认为是新的变量,即x = x*2这句,x已经是inner()内部的局部变量了,但是x没有先定义,所以报UnboundLocalError错。
正确:

>>> def out(x):
	def inner():
        nonlocal x
		x = x*2
		return x
	return inner
>>> c = out(2)
>>> c()
4
>>> 

错误2

flist = []
for i in range(3):
    def foo(x):
        print(x + i)
    flist.append(foo)
for f in flist:
    f(2)
# results:
4
4
4
>>> 

原因在于i在3次for之后变成2,而flist中的foo并没有给变量实例化,所以只记录了需要加i,最后在for中都加上了2.
改成:

flist = []
for i in range(3):
    def foo(x, y=i):
        print(x + y)
    flist.append(foo)
for f in flist:
    f(2)
# results:
2
3
4
>>> 

3.修饰器和@符号

上面讲了闭包的概念后,自然就引出修饰器的定义

>>> def outer(some_func):
    	def inner(n):
        	print("before some_func")
         	ret = some_func() # 1
      	return ret + n
   	return inner
>>> def foo():
		return 1
>>> foo
<function foo at 0x0000026AC729F6A8>
>>> foo = outer(foo)
>>> foo(1)
before some_func
2
>>> foo
<function outer.<locals>.inner at 0x0000026AC729F7B8>

foo = outer(foo)这行,将foo再用outer封装后再命名为foo,增加功能但使用方法不变,这就是修饰的概念;
可以看见,前后的foo地址发生变化(显然)

上例自己实现了一个非常简单的修饰器,python中提供了语法糖@符号来供程序猿使用,不需要写foo = outer(foo)这条语句。可能会使得意义更加明确吧~

>>> def outer(some_func):
    	def inner(n):
        	print("before some_func")
         	ret = some_func() # 1
      	return ret + n
   	return inner
>>> @outer
	def foo():
		return 1
>>> foo(1)
before some_func
2
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值