python全栈开发从入门到放弃之函数进阶
1、三元运算
1 a= 1 2 b=2 3 max = (a if a>b else b ) #条件成立的结果 if 条件 else 条件不成立的结果 4 print(max)
2、先上一首python之禅
1 import this 2 3 Beautiful is better than ugly. 4 Explicit is better than implicit. 5 Simple is better than complex. 6 Complex is better than complicated. 7 Flat is better than nested. 8 Sparse is better than dense. 9 Readability counts. 10 Special cases aren't special enough to break the rules. 11 Although practicality beats purity. 12 Errors should never pass silently. 13 Unless explicitly silenced. 14 In the face of ambiguity, refuse the temptation to guess. 15 There should be one-- and preferably only one --obvious way to do it. 16 Although that way may not be obvious at first unless you're Dutch. 17 Now is better than never. 18 Although never is often better than *right* now. 19 If the implementation is hard to explain, it's a bad idea. 20 If the implementation is easy to explain, it may be a good idea. 21 Namespaces are one honking great idea -- let's do more of those!
Python之禅 by Tim Peters
优美胜于丑陋(Python 以编写优美的代码为目标)
明了胜于晦涩(优美的代码应当是明了的,命名规范,风格相似)
简洁胜于复杂(优美的代码应当是简洁的,不要有复杂的内部实现)
复杂胜于凌乱(如果复杂不可避免,那代码间也不能有难懂的关系,要保持接口简洁)
扁平胜于嵌套(优美的代码应当是扁平的,不能有太多的嵌套)
间隔胜于紧凑(优美的代码有适当的间隔,不要奢望一行代码解决问题)
可读性很重要(优美的代码是可读的)
即便假借特例的实用性之名,也不可违背这些规则(这些规则至高无上)
不要包容所有错误,除非你确定需要这样做(精准地捕获异常,不写 except:pass 风格的代码)
当存在多种可能,不要尝试去猜测
而是尽量找一种,最好是唯一一种明显的解决方案(如果不确定,就用穷举法)
虽然这并不容易,因为你不是 Python 之父(这里的 Dutch 是指 Guido )
做也许好过不做,但不假思索就动手还不如不做(动手之前要细思量)
如果你无法向人描述你的方案,那肯定不是一个好方案;反之亦然(方案测评标准)
命名空间是一种绝妙的理念,我们应当多加利用(倡导与号召)
python之禅上写到命名空间是一种绝妙的理念,让我们一起多加利用吧
2、
命名空间一共分为三种:
全局命名空间
局部命名空间
内置命名空间
*内置命名空间中存放了python解释器为我们提供的名字:input,print,str,list,tuple...它们都是我们熟悉的,拿过来就可以用的方法。
三种命名空间之间的加载与取值顺序:
加载顺序:内置命名空间(程序运行前加载)->全局命名空间(程序运行中:从上到下加载)->局部命名空间(程序运行中:调用时才加载)
取值:
在局部调用:局部命名空间->全局命名空间->内置命名空间
1 x = 1 2 def f(x): 3 print(x) 4 5 print(10)
在全局调用:全局命名空间->内置命名空间
1 x = 1 2 def f(x): 3 print(x) 4 5 f(10) 6 print(x)
1 print(max)
作用域
作用域就是作用范围,按照生效范围可以分为全局作用域和局部作用域。
全局作用域:包含内置名称空间、全局名称空间,在整个文件的任意位置都能被引用、全局有效
局部作用域:局部名称空间,只能在局部范围内生效
globals和locals方法
1 print(globals()) 2 print(locals())
1 def func(): 2 a = 12 3 b = 20 4 print(locals()) 5 print(globals()) 6 7 func()
global关键字
1 a = 10 2 def func(): 3 global a 4 a = 20 5 6 print(a) 7 func() 8 print(a)
总结:
站在全局看:
使用名字:
如果全局有:用全局的
如果全局没有:用内置的
为什么要有作用域的概念:
为了函数内的变量不会影响到全局
作用域:
小范围的可以用大范围的
但是大范围的不能用小范围的
范围从大到小(图)
在小范围内,如果要用一个变量,是当前这个小范围有的,就用自己的
如果在小范围内没有,就用上一级的,上一级没有就用上上一级的,以此类推。
如果都没有,报错
函数的嵌套和作用域链
函数的嵌套调用
1 def f1(): 2 print('f1') 3 def f2(): 4 a = 10 5 f1() 6 f2() 7 #代码从上到下读取,f2()调用会调用f2()函数体的内容,最后发现f1()然后调用f1()开始执行函数体的内容最后输出f1
函数的嵌套定义
函数的嵌套
为了保护内部函数,确定内部函数只能在外部函数中被调用
1 def animal(): 2 def tiger(): 3 print('bark') 4 print('eat') 5 tiger() 6 animal() #函数嵌套调用 7 8 9 eat 10 bark
1 def f1(): 2 def f2(): 3 def f3(): 4 print("in f3") 5 print("in f2") 6 f3() 7 print("in f1") 8 f2() 9 10 f1()
函数的作用域链
1 ef f1(): 2 a = 1 3 def f2(): 4 print(a) 5 f2() 6 7 f1()
1 def f1(): 2 a = 1 3 def f2(): 4 a = 2 5 f2() 6 print('a in f1 : ',a) 7 8 f1()
nonlocal关键字
1 def f1(): 2 a = 1 3 def f2(): 4 nonlocal a 5 a = 2 6 f2() 7 print('a in f1 : ',a) 8 9 f1() 10 #函数会使用自己本身的a的赋值,f2()函数体里面的赋值用完会从内存删除掉,想保留要加入nonlocal 加变量名才能会取f2()函数体里a的赋值
函数名的本质
函数名本质上就是函数的内存地址
1.可以被引用
1 def func(): 2 print('func') 3 print(func) 4 f=func 5 print(f) 6 f() 7 8 <function func at 0x000001C390B4B9D8> 9 <function func at 0x000001C390B4B9D8> 10 func 11 12 13 #会指向函数的内存地址,不会取用函数里面的值,只有加()才能调用函数
2.可以被当作容器类型的元素
1 def func(): 2 print('func') 3 print(func) 4 f=func 5 print(f) 6 l = [f] 7 print(l) 8 l[0] == f 9 l[0]() 10 11 12 <function func at 0x0000025B3C73B9D8> 13 <function func at 0x0000025B3C73B9D8> 14 [<function func at 0x0000025B3C73B9D8>] 15 func
3.可以当作函数的参数和返回值
1 第一类对象(first-class object)指 2 1.可在运行期创建 3 2.可用作函数参数或返回值 4 3.可存入变量的实体。
*不明白?那就记住一句话,就当普通变量用
闭包
1.闭 内部的函数
2.包 包含了对外部函数作用域中变量的引用
闭包的常用形式
1 def hei(): 2 x = 20 3 def inner(): 4 print(x) #局部的 5 return inner
闭包函数:
内部函数包含对外部作用域而非全剧作用域名字的引用,该内部函数称为闭包函数
函数内部定义的函数称为内部函数
由于有了作用域的关系,我们就不能拿到函数内部的变量和函数了。如果我们就是想拿怎么办呢?返回呀!
我们都知道函数内的变量我们要想在函数外部用,可以直接返回这个变量,那么如果我们想在函数外部调用函数内部的函数呢?
是不是直接就把这个函数的名字返回就好了?
这才是闭包函数最常用的用法
1 def func(): 2 name = 'eva' 3 def inner(): 4 print(name) 5 return inner 6 7 f = func() 8 f()
判断闭包函数的方法.__closure__
1 def func(): 2 name = 'eva' 3 def inner(): 4 print(name) 5 print(inner.__closure__) 6 return inner() 7 func() #看输出是否有cell元素有就是闭包函数 8 9 10 (<cell at 0x000002711EE465B8: str object at 0x000002711EEDA500>,) 11 eva 12 13 14 15 16 #输出的__closure__为None :不是闭包函数 17 name = 'egon' 18 def func2(): 19 def inner(): 20 print(name) 21 print(inner.__closure__) 22 return inner 23 24 f2 = func2() 25 f2() 26 27 28 None 29 egon
闭包函数的嵌套
1 def wrapper(): 2 money = 1000 3 def func(): 4 name = 'eva' 5 def inner(): 6 print(name,money) 7 return inner 8 return func 9 10 f = wrapper() 11 i = f() 12 i()
闭包函数在网络上的应用
1 from urllib.request import urlopen 2 3 def index(): 4 url = "http://www.xiaohua100.cn/index.html" 5 def get(): 6 return urlopen(url).read() 7 return get 8 9 xiaohua = index() 10 content = xiaohua() 11 print(content)
本次小结:
命名空间:
一共有三种命名空间从大范围到小范围的顺序:内置命名空间、全局命名空间、局部命名空间
作用域(包括函数的作用域链):
调用时,如果在自己的空间内有,就用自己的。如果没有就使用大范围的。不能从大范围中用小范围的。
函数的嵌套:
嵌套调用
嵌套定义:定义在内部的函数无法直接在全局被调用
函数名的本质:
就是一个变量,保存了函数所在的内存地址
闭包:
内部函数包含对外部作用域而非全剧作用域名字的引用,该内部函数称为闭包函数