码迷,mamicode.com
首页 > 其他好文 > 详细

函数返回值

时间:2017-10-24 11:35:26      阅读:139      评论:0      收藏:0      [点我收藏+]

标签:for   函数   生命周期   打印   out   print   二次   否则   函数地址   

1、函数的返回值:
例子:
	def show(x):
		print(x)
		return x+1
		return x+2

	show(5)
	>>>5
	Out[37]: 6
	#打印5 返回值6  只执行第一个return
	python函数使用return语句返回‘返回值‘
	所以函数都有返回值,如果没有return语句,隐式调用return None
	return语句并不一定是函数的语句块的最后一句语句
	一个函数可以存在多个return语句,但只有一条可以执行
	如果函数执行了return语句,函数就会返回,当前执行的return语句后的其他语句就不执行了

return 等价于 return None

return 作用
	结束调用 返回值
	例子:
		1.
		def showlist():
			return[1,3,5]
		2.
		def showlist():
			return 1,3,5

		1. showlist函数返回一个列表[1,3,5]
		2. showlist函数返回一个元组(1,3,5)
函数不能返回多个值
	return[1,3,5] 返回的是一个列表对象
	return 1,3,5  看似返回多个值,隐式被python封装成了元组

2、作用域:
	一个标识符的可见范围,这就是标识符的作用域;也可以说变量的作用域
	1.
	x=5
	def fn():
		print(x)
	fn()
	>>>5
	2.
	x=50
	def fn2():
		x+=1
		print(x)
	fn2()
	>>>(x+=1)Error:local variable ‘x‘ referenced before assignment 在赋值前引用了变量x
	解析:
		调用fn2()->x+=1 等同 x= x+1 ,在这里右边x+1 赋值给x ,相当于x被赋值重新定义,
		在内部定义了一个局部变量x,这个时候x只是个标识符,但是x并没有完成赋值就被右边执行+1操作。
		如果在本地作用域中,先给x赋一个新值就不会报错
全局作用域:
	整个程序环境都可见

局部作用域:
	在函数、类等内部可见
	局部变量使用范围不能超过其所在的局部作用域
1.
	def fn1():
		x = 1 #local 变量x 在外部不可见
	def fn2():
		print(x)
	fn2()
	>>> Error  name‘x‘ is not defined

2. y = 10#y是全局变量 可见于内部
	def fn():
		print(y)
	fn()
	>>>10

	嵌套结构:
1.
	def outer1():
		o = 65
		def inner():
			print(‘inner:{}‘.format(o))
			print(chr(o))
		print(‘outer:{}‘.format(o))
		inner()
	outer1()
>>>outer:65
>>>inner:65
>>>A
outer1(1)-> o =65 ->输出outer-> inner()->inner:65->chr(o) = A
2.
	def outer2():
		o = 65
		def inner():
			o = 97
			print(‘inner:{}‘.format(o))
			print(chr(o))
		print(‘outer:{}‘.format(o))
		inner()
	outer2()
>>>outer:65
>>>inner:97
>>>a
outer2()->o = 65 -> 输出outer -> inner() o =97 -> inner:97 -> chr(o)=a
	外层变量作用域在内层作用域可见
	内层作用域inner中,定义了o=97,重新定义了一个新的变量o,但是o没有覆盖外层的o=65
例:
	x = 5
	def foo():
		y = x+1
		x +=1
		print(x)
	foo()
	>>>错误指向y=x+1 Error local variable ‘x‘ referenced before assignment 
	在赋值前引用了变量x
	x+=1 等同 x = x+1,x+1 赋值定义x 本地作用域中,x被重新定义赋值,但此时的x只是一个标识符,
	还没有完成赋值,就被执行+1操作。如果在本地作用域中,在x+=1 前给x赋值 就可以继续往下进行。
	所以这里会报错,在x赋值前引用了变量x。但是,当没有x+=1 时,只有y=x+1 ,
	这时,x引用的是外部的x=5,调用foo()时,可以正常打印x


全局变量(Global):
1.
	x = 5
	def foo():
		global x
		x+=1
		print(x)

	使用global关键字的变量后,自动将foo()内的x声明为使用外部的全局作用域定义的变量x
	这里x+=1就不报错了
	foo()
	>>>6
2.
	def foo():
		global z
		z = 10
		z +=1
		print(z)
	>>>foo() ->11
	>>>print(z)->11
	这里使用了global,z的作用域为全局,但是外部并没有z变量。内部z=10赋值即定义,内部作用域为一个外部作用域
	的变量赋值,所以z+=1 不会报错。这里的z作用域还是全局,所以print(z) 不会报错并正常打印

以上总结:
	(1)x+=1 原则上是引用赋值,但python动态语言特殊,先赋值才算是定义然后才可以被引用。
	当然,可以在这条语句前 添加一个x=0类似赋值语句或者使用global将变量x指定为全局作用域 
	(2)内部作用域使用了x=0这样的赋值语句后会重新定义变量x的作用域为局部。但是使用了global
	后,变量x作用域就变成了全局,x=0 就相当于对全局作用域的变量x赋值

‘global‘使用:
	(1)在函数中,使用了global,外部作用域变量会在内部作用域中可见,但是这样会破坏函数的封装,所以局部和
	外部应尽量隔离;
	(2)如果函数需要使用外部全局变量,应使用函数传参的方式解决



闭包:
	(1) 自由变量:未在局部作用域中定义的变量。
	(2) 闭包;出现在嵌套函数中,指的是内层函数引用到了外层函数的自由变量,就形成了闭包。

def counter():
	c = [0] #对c赋值
	def inc():
		c[0] += 1#c是一个列表,对c列表的元素赋值 并不是对c赋值 所以不会出错
		return c[0]
	return inc  #返回函数的对象(callable) inc()函数的调用

>>>foo = counter() #counter() -> return inc->inc() ,foo就变成了可调用对象 (callable) 
>>>print(foo(),foo())#调用foo
#1、foo() -> c=[0] -> inc()->c[0]+=1->1
#2、foo() -> c=[0] -> inc()->c[1]+=1->2
>>>c = 100#外部c赋值定义100
>>>print(foo())
#foo() -> c=[0] -> inc()->c[2]+=1->3

在counter函数中,定义了变量c,下面嵌套了一个inc函数; inc函数中使用了变量c。
对于inc函数来讲,c是一个自由变量,inc函数引用了counter函数的自由变量,这里就产生了闭包。
每次调用inc函数,c的值随着c[0]+=1产生累加。
c=100,c相当于全局变量,但在函数中c作为局部变量,两者没有关系,inc函数引用的是counter()下的
自由变量,所以再次调用foo还是累加1

nonlocal 关键字
	使用了nonlocal关键字,将变量标记在上级的局部作用域中定义但不能是全局作用域中定义
def counter():
	count = 0
	def inc():
		nonlocal count
		count+=1
		return count
	return inc
foo = counter()
foo()#1
foo()#2

count 是外层函数的局部变量,被内部函数引用
内部函数使用nonlocal关键字声明count变量在上一级作用域中
形成闭包

默认值的作用域:
1.
	def foo(xyz = 1):
		print(xyz)

	foo()#1
	foo()#1
	print(xyz)#Error "Name ‘xyz‘ is not defined" 
	xyz虽然是形参,但属于局部变量,只能在内部打印

2.
	def foo(xyz=[]):
		xyz.append(1)
		print(xyz)
	foo() #[1]
	foo()#[1,1]
foo()第二次[1,1]:
因为函数也是对象,python把函数的默认值放在了属性中,这个属性伴随着这个函数对象整个生命周期

3.引用类型:
	def foo(xyz = [], u=‘abc‘, z=123):
		xyz.append(100)
		print(xyz)

	print(foo.__defaults__)
	>>>([],‘abc‘,123)
	
	print(foo(),id(foo))
	print(foo.__defaults__)
	>>>[100]
	>>>None 2502614720296
	>>>([100], ‘abc‘, 123)
	
	print(foo(),id(foo))
	print(foo.__defaults__)
	>>>[100,100]
	>>>None 2502614720296

函数地址并没有变,调用它,它的属性__defaults__中使用元组保存所有默认值
xyz默认值是引用类型,引用类型元素的变化不等同元组变化
可变类型默认值,如果使用默认值,就可能修改这个默认值(list)
4.非引用类型:
	def foo(w, u=‘abc‘, z=123):
		u = ‘xyz‘
		z = 123
		print(w,u,z)

	print(foo.__defaults__)
	>>>(‘abc‘,123)
	foo(‘test‘)
	>>>test xyz 123
	print(foo.__defaults__)
	>>>(‘abc‘,123)
__defaults__属性中使用元组保存所有默认值,它不会因为在函数体内使用了它而改变

5.函数体内不改变默认值
	def foo(xyz=[], u=‘abc‘, z=123):
		xyz = xyz[:]
		xyz.append(1)
		print(xyz)

	foo()
	print(foo.__defaults__)
	>>>[1]
	>>>([],‘abc‘,123)

	foo(10)
	print(foo.__defaults__)
	>>>[10,1]
	>>>([],‘abc‘,123)

	xyz都是传入参数或者默认参数的副本,无法修改原参数
	使用影子拷贝的方法创建一个新的对象,永远不能改变传入的参数

6.None作为默认值:
	def foo(x = None, y=‘abc‘, z = 123):
		if x is None:#如果是None
			x = []#创建一个列表
		x.append(1)#否则追加1
		print(x)
	foo()
	print(foo.__defaults__)
	>>>1
	>>>(None, ‘abc‘, 123)

	foo()
	print(foo.__defaults__)
	>>>1
	>>>(None, ‘abc‘, 123)

	foo([10])
	print(foo.__defaults__)
	>>>[10,1]
	>>>(None, ‘abc‘, 123)

1.通过值的判断就可以灵活的选择创建或者修改传入对象
2.这种方式灵活,应用广泛
3.许多函数的定义,都可以看到使用None这个不可变的值作为默认参数(贯用法)。


全局函数的销毁:
1.重新定义同名函数
2.del语句删除函数对象
3.程序结束掉

def foo(x= [], y=‘zz‘, z = 123):
	x.append(1)
	return x
print(foo(),id(foo),foo.__defaults__)
def foo(x= [], y=‘zz‘, z = 123):
	x.append(1)
	return x
print(foo(),id(foo),foo.__defaults__)
del foo
print(foo(),id(foo),foo.__defaults__)

>>>[1] 2603035412272 ([1], ‘zz‘, 123)
>>>[1] 2603035412136 ([1], ‘zz‘, 123)
>>>Error  name‘foo‘ is not defined #foo未定义

局部函数销毁:
1.重新在上级作用域定义同名函数
2.del语句删除函数对象
3.上级作用域销毁时

def foo(x=[], y=‘zz‘, z=123):
    x.append(1)
    def inner(a=10):
        pass
    def inner(a=100):
        print(x)
    print(id(inner))
    return inner
bar = foo()
print(id(foo),id(bar), foo.__defaults__, ba
	r.__defaults__)
del bar
print(id(foo),id(bar), foo.__defaults__, bar.__defaults__)

>>>2551461446248
>>>2551461445704 2551461446248 ([1], ‘zz‘, 123) (100,)
>>>Error name ‘bar‘ is not defined

  

函数返回值

标签:for   函数   生命周期   打印   out   print   二次   否则   函数地址   

原文地址:http://www.cnblogs.com/hkcs/p/7721861.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!