标签: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