python基础-3 集合 三元运算 深浅拷贝 函数 Python作用域
上节课总结
1 运算符
in
字符串 判断 : “hello” in "asdasfhelloasdfsadf"
列表元素判断:"li" in ['li', 'ok']
字典key判断:key in dic.keys()
2 基本的数据类型
1 类名() 其实就是执行类的 __init__ 2 3 int() 4 __init__(self,args,base=10) 5 6 int 7 a. 创建方式 两种 8 n1 = 123 # 根据int类,创建了一个对象 9 n2 = int(123) # 根据int类,创建了一个对象 类的实例化就是对象 10 b. int内部优化 11 1、n1 和 n2 的内存地址相同 12 n1 = 123 13 n2 = n1 14 2、按理说 n1 和 n2 的内存地址不相同 15 n1 = 123 16 n2 = 123 17 但是Python内部做了优化, 18 -5 ~ 257 以内的数,按照 2 的方式写时,都是指向同一个内存 19 n1 = 123 20 n2 = 123 21 除此以外的数,都是n1 和 n2 的内存地址不相同 python源码可以改取值范围 22 n1 = 123123 23 n2 = 123123 24 3、id查看对象的内存地址 25 n1 = 123 26 i1 = id(n1) 27 print(i1) 28 或者 29 i1 = id(123) 30 print(i1) 31 32 c. int长度限制 33 -2**31 ~ 2 **31 -1 34 -2**63 ~ 2**63 - 1 35 数字后有L 代表长整型 36 python 2.2之后,超过int的最大长度后,会自动转换成long类型,long类型无长度限制 37 38 python 3之后,int自己就无长度限制了 39 40 41 str, 42 a. 创建方式 43 s1 = "alex" 44 s1 = str('alex') 45 s1 = str('alex') #传参 字节和编码,可以加上编码方式 46 b. 特有功能 47 # 两端去除空格 48 # s1.strip() 49 50 # 以 .. 开头 51 # s1.startswith() 52 53 # 找子序列 "12","h" 54 # s1.find() 55 56 # 将字符串中的某子序列替换成 指定的值 57 # s1.replace() 58 59 # 变大写 60 # s1.upper() 61 62 # 是。。。吗? 63 # s1.isalpha() 64 65 c. 公共功能 66 索引:只能取一个元素 67 切片:取多个元素 68 len: 69 len("汉字") 70 3.5 ==》 字符 (utf-8 中 规定1个汉字3个字节,但是3版本中 1个汉字就是一个字符,不是字节。所以这里len是2) 71 2.7==》 字节(utf-8 中 规定1个汉字3个字节,所以这里len是6) 72 for: 73 3.5 ==》 字符 (3 版本中 循环汉字字符串不是字节,而是按照字符来进行循环的) 74 2.7==》 字节(2版本总循环汉字是以字节来循环的) 75 76 编码、for bytes方法:转换成字节 77 3版本python中 汉字字符串循环不是按照字节循环,而是按照字符循环。 78 name = "李露" 79 for i in name: 80 print(i) #循环打印每个汉字而不是字节 81 bytes_list = bytes(i, encoding='utf-8') #将汉字转成字节,编码是utf-8 82 print(bytes_list) 83 for b in bytes_list: 84 #1、3.5 for循环时候,循环的每一个元素是 “字符” 85 #2、字符 =》 字节 86 bytes_list = bytes("字符串",encoding='utf-8') 87 88 # utf-8 -> 3字节 1个汉字 89 # gbk -》 2字节 1个汉字 90 print(bytes_list) # 默认每一个字节都是16进制表示 91 for b in bytes_list: 92 print(b) # 默认每一个字节都是10进制表示 93 94 3、10进制的数字 ==》 2进制 95 len 96 id 97 bin(10进制的数字) 98 d、 bytes和str的转换 将字节转换成字符串 bytes方法 99 a = "李露" 100 # 将字符串转换成字节 101 b1 = bytes(a, encoding='utf-8') 102 print(b1) 103 b2 = bytes(a, encoding='gbk') 104 print(b2) 105 # 将字节转换成字符串 106 107 newa1 = str(b1, encoding="utf-8") 108 print(newa1) 109 110 newa2 = str(b2, encoding='gbk') 111 print(newa2) 112 113 114 ########### 115 x = str() 116 # 创建字符串 117 # 转换成字符串,字节,编码 118 m = bytes() 119 # 创建字节 120 # 转换成字节,字符串,要编程什么编码类型的字节 121 122 python进制转换 123 hex 可以 十进制转16进制 二进制转16进制 结果都是字符串 124 >>> hex(0b10) 125 '0x2' 126 >>> hex(10) 127 '0xa' 128 bin 可以十进制转2进制 16进制转2进制 结果都是字符串 129 >>> bin(10) 130 '0b1010' 131 >>> bin(0x2) 132 '0b10' 133 int 可以16进制转换十进制 2进制转换十进制 134 >>> int(0xe) 135 136 >>> int(0b100) 137 138 139 140 list 141 可变元素的“集合” 142 143 ----------- 144 str -> 创建字符串,或者将其他的转换成字符串 145 ------------------------------------------ 146 list -> 创建列表,将其他元素转换成列表 147 148 a. 创建和转换 149 1、创建 150 li = [11,22,33,4] 151 li = list() 152 li = list([11,22,33,4]) 153 2、转换 注:放可迭代的 凡是可以for循环的都可以迭代。 字符串 元组 字典 列表本身 都可以迭代 154 s1 = "李露" 155 # for,字符 ==> 可迭代 156 l1 = list(s1) # for循环,将循环的每一个元素,当做列表的元素 157 # ["李", "露"] 158 print(l1) 159 160 # 元组 转换成列表 161 # t2 = ("alex", "laonanhai", "seven") 162 # l2 = list(t2) 163 # print(l2) 164 165 # 字典 转换成列表 166 # dic = {'k1': "alex", "k2": 'seven'} 167 # l3 = list(dic.items()) 168 # print(l3) 169 # 字符串,元组,字典 =》 列表 170 171 b. 列表特有功能 172 # 追加 173 # li.append() 174 # 清除 175 # li.clear() 176 # 扩展自己,用另外一个可迭代的对象,扩充到自己内部 177 # str,list,dict,tuple 178 # s = "李露" 179 # li.extend(s) 180 # print(li) 181 # 翻转,自己内部元素翻转 182 # li.reverse() 183 # 向指定位置插入指定元素 184 # li.insert(1, "X") 185 c. 公共功能 186 li = ["alex", "eric", 'seven', 123] 187 索引:li[2] 188 切片:li[2:3] 189 del 190 enumerate 191 for 192 len 193 join 194 d. 多层列表 字典取值 195 li = ["alex", "eric", 'seven', 123] 196 li = [ "alex" , 123, {"k1":"v1", "k2": {"vv": (11,22,123), "ii": 456}}] 197 198 li[2] --> {"k1":"v1", "k2": {"vv": 123, "ii": 456}} 199 li[2]['k2'] ==> {"vv": 123, "ii": 456} 200 li[2]['k2']["vv"] ==> (11,22,123) 201 li[2]['k2']["vv"][2] 202 203 元组 tuple 转换时候放可迭代的,即可以for循环取的类型。 比如 字符串 列表 字典都可以循环 204 a. 创建和转换 205 t = (11,22,33) 206 t = tuple((11,22,33)) 207 t = tuple([]) # 字符串,列表,字典 208 b. 特有方法 209 count 210 index 211 c. 嵌套(元素不可修改) 注:如果元素是列表或者字典则可以修改 212 t = (11,22,33) 213 t = (11,22,["alex", {"k1": "v1"}]) 214 215 216 e. 元组的特性,不可修改,谁不可被修改 #如果元素是列表或者字典可以修改 217 元组,儿子不能变 218 元组,儿子不能变,孙子,... 219 220 整理: 元组 字符串 特性总结 221 一般字符串,执行一个功能,生成一个新内容,原来内容不变 222 list,tuple,dict,执行一个功能,自身进行变化 223 224 上节总结 基本数据类型
********************** 列表一句转变成字典 li = [11,12,13] dic = dict(enumerate(li,10)) print(11) print(dic) ********************** 2 版本 print(dic.keys()) 直接返回 一个列表 3 版本 print(dic.keys()) 返回的是一个类 ********************** fromkeys(seq,value=None) 解释: 默认不写value的话,所有的值为None n = dict.fromkeys(['k1', 'k2'], []) #默认逗号后面不给的话,key对应的value都是None n['k1'].append(2) #我们修改逗号后面的空列表元素 打印 所有key的value也会修改 print(n) n['k1'] = 3 # 而单独修改key的value的话,只有 这个key的value改了,而其他的key对应的value都不变 print(n) n = dict.fromkeys() #默认逗号后面不给的话,key对应的value都是None print(n)
1、set 集合
set集合,是一个无序且不重复的元素集合
1 class set(object): 2 """ 3 set() -> new empty set object 4 set(iterable) -> new set object 5 6 Build an unordered collection of unique elements. 7 """ 8 def add(self, *args, **kwargs): # real signature unknown 9 """ 10 Add an element to a set,添加元素 11 12 This has no effect if the element is already present. 13 """ 14 pass 15 16 def clear(self, *args, **kwargs): # real signature unknown 17 """ Remove all elements from this set. 清楚内容""" 18 pass 19 20 def copy(self, *args, **kwargs): # real signature unknown 21 """ Return a shallow copy of a set. 浅拷贝 """ 22 pass 23 24 def difference(self, *args, **kwargs): # real signature unknown 25 """ 26 Return the difference of two or more sets as a new set. A中存在,B中不存在 27 28 (i.e. all elements that are in this set but not the others.) 29 """ 30 pass 31 32 def difference_update(self, *args, **kwargs): # real signature unknown 33 """ Remove all elements of another set from this set. 从当前集合中删除和B中相同的元素""" 34 pass 35 36 def discard(self, *args, **kwargs): # real signature unknown 37 """ 38 Remove an element from a set if it is a member. 39 40 If the element is not a member, do nothing. 移除指定元素,不存在不保错 41 """ 42 pass 43 44 def intersection(self, *args, **kwargs): # real signature unknown 45 """ 46 Return the intersection of two sets as a new set. 交集 47 48 (i.e. all elements that are in both sets.) 49 """ 50 pass 51 52 def intersection_update(self, *args, **kwargs): # real signature unknown 53 """ Update a set with the intersection of itself and another. 取交集并更更新到A中 """ 54 pass 55 56 def isdisjoint(self, *args, **kwargs): # real signature unknown 57 """ Return True if two sets have a null intersection. 如果没有交集,返回True,否则返回False""" 58 pass 59 60 def issubset(self, *args, **kwargs): # real signature unknown 61 """ Report whether another set contains this set. 是否是子序列""" 62 pass 63 64 def issuperset(self, *args, **kwargs): # real signature unknown 65 """ Report whether this set contains another set. 是否是父序列""" 66 pass 67 68 def pop(self, *args, **kwargs): # real signature unknown 69 """ 70 Remove and return an arbitrary set element. 71 Raises KeyError if the set is empty. 移除元素 72 """ 73 pass 74 75 def remove(self, *args, **kwargs): # real signature unknown 76 """ 77 Remove an element from a set; it must be a member. 78 79 If the element is not a member, raise a KeyError. 移除指定元素,不存在保错 80 """ 81 pass 82 83 def symmetric_difference(self, *args, **kwargs): # real signature unknown 84 """ 85 Return the symmetric difference of two sets as a new set. 对称交集 86 87 (i.e. all elements that are in exactly one of the sets.) 88 """ 89 pass 90 91 def symmetric_difference_update(self, *args, **kwargs): # real signature unknown 92 """ Update a set with the symmetric difference of itself and another. 对称交集,并更新到a中 """ 93 pass 94 95 def union(self, *args, **kwargs): # real signature unknown 96 """ 97 Return the union of sets as a new set. 并集 98 99 (i.e. all elements that are in either set.) 100 """ 101 pass 102 103 def update(self, *args, **kwargs): # real signature unknown 104 """ Update a set with the union of itself and others. 更新 """ 105 pass 106 107 set 集合class
示例
1 #!/usr/bin/env python 2 # _*_ coding:utf-8 _*_ 3 4 a={1:2,4:5} 5 b=set(a) 6 7 b.add(111111) 8 b.clear() 9 print(b) 10 11 n = {11,22,33} 12 b = {22,66} 13 c = {11} 14 15 # n中有的b中没有的赋值给新的变量 打印 16 new_n = n.difference(b) 17 print(new_n) 18 19 #n中有的 b中没有的 更新到n 20 # n.difference_update(b) 21 # print(n) 22 23 # 将迭代的序列加入 24 n.update("al") 25 n.update([1,3,4]) 26 print(n) 27 28 #n存在的b不存在的 b存在n不存在的 组合一起输出 29 ret=n.symmetric_difference(b) 30 ret2 = n.symmetric_difference({11,22,33}) 31 print(ret) 32 print("=========") 33 # n存在的b不存在的 b存在n不存在的 组合一起 更新到前面的集合 34 n.symmetric_difference_update(b) 35 print(n) 36 37 # 是否是子集 不是返回false 是的话True 38 ret = n.issubset(c) # n是不是c的子 39 print(ret) 40 ret1 = c.issubset(n) # c是不是n的子 41 print(ret1) 42 ret2 = n.issuperset(c) # n是不是c的父 43 print(ret2) 44 45 46 # pop discard remove 三个删除的区别 47 48 #pop 删除同时可以获取到该值 49 ret = n.pop() #由于集合是无序的,所以pop删除也是无序的 50 print(ret) 51 # discard 删除集合元素,如果元素不存在 返回False 不报错 52 n.discard(11) 53 print(n) 54 #remove 删除集合元素 如果元素不存在 报错 55 #n.remove(99) 56 57 z = {11,22,33} 58 p = {44} 59 60 z.intersection(p) #取交集并更新到z中 61 print(z)
练习
1 !/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 # s1=set() #创建空的set集合 4 # s2={11,22,33,44,55} #直接创建set集合 5 # print(s2) 6 # l1=[11,22,33,44,22,11] 7 # l2=(11,22,11,22,333) 8 # l3="123" 9 # s3=set([11,22,33,22]) #传送可迭代的对象,转换成set集合 10 # s4=set(l3) 11 # print(set(l2)) 12 13 se={11,22,33,55} 14 print(se) 15 se.add(44) #添加 16 print(se) 17 se.clear() #清除所有元素 18 print(se) 19 be={11,22,33} 20 ce={22,55} 21 print(be.difference(ce))#找be中存在。ce中不存在的set集合,返回值 22 print(ce.difference(be))#找ce中存在,be中不存在的set集合,返回值 23 be.difference_update(ce)#找be中存在,ce中不存在的,更新自己 24 print(be) 25 ae={11,22,33,444,555} 26 ae.discard(444) #移除元素,如果没有的话不报错 27 ae.remove(555)#移除元素,没有的话报错 28 print(ae) 29 ee={11,22,33,555} 30 fe={22,555,666,7,7665} 31 print(ee.intersection(fe)) #取A和B的交集,返回新值。原来的A和B不变,取交集,新创建一个set 32 ee.intersection_update(fe) #A和B的交集,不返回值,直接更新自己成这个交集,取交集,修改原来set 33 print(ee) 34 je={11,212,33,515} 35 ke={22,555,666,7,7665} 36 print(je.isdisjoint(ke))#判断A和B有没有交集,有交集返回False,么有交集返回True 37 me={11,212,33,515} 38 ne={11,33} 39 print(ne.issubset(me))#判读A是否是B的子序列。是否是子集 40 print(me.issuperset(ne))#判读A是否是B的父序列。是否是父集 41 oe={11,212,33,55} 42 print(oe.pop()) #随机取一个值,去掉,并且可以返回这个值 43 print(oe) 44 pe={11,22,33,555} 45 qe={22,555,666,7,7665} 46 print(pe.difference(qe)) 47 print(qe.difference(pe)) 48 print(pe.symmetric_difference(qe))#将不共有的元素,组成一个set集合,差集,创建新对象 49 pe.symmetric_difference_update(qe)#将不共有的元素,组成一个set集合,并更新原有集合,差集,改变原来 50 print(pe) 51 re={11,22,33,555} 52 se={22,555,666,7,7665} 53 print(re.union(se))#A和B合并到一起,并集 54 me={22,555,666,545422} 55 me.update([22,9,8])#更新,多个元素,集合、元组,set 56 print(me)
2、三目运算符
三元运算(三目运算),是对简单的条件语句的缩写。
1 # 书写格式 2 3 result = 值1 if 条件 else 值2 4 5 # 如果条件成立,那么将 “值1” 赋值给result变量,否则,将“值2”赋值给result变量
1 name = "eric" if 1 == 1 else "alex" 2 print("==",name)
3、深浅拷贝
1、对于 数字 和 字符串 而言,赋值、浅拷贝和深拷贝无意义,因为其永远指向同一个内存地址。
1 import copy 2 # ######### 数字、字符串 ######### 3 n1 = 123 4 # n1 = "i am alex age 10" 5 print(id(n1)) 6 # ## 赋值 ## 7 n2 = n1 8 print(id(n2)) 9 # ## 浅拷贝 ## 10 n2 = copy.copy(n1) 11 print(id(n2)) 12 13 # ## 深拷贝 ## 14 n3 = copy.deepcopy(n1) 15 print(id(n3))
2、其他基本数据类型
对于字典、元祖、列表 而言,进行赋值、浅拷贝和深拷贝时,其内存地址的变化是不同的。
1、赋值
赋值,只是创建一个变量,该变量指向原来内存地址,如:
1 n1 = {"k1": "wu", "k2": 123, "k3": ["alex", 456]} 2 n2 = n1
2、浅拷贝
浅拷贝,在内存中只额外创建第一层数据
1 import copy 2 3 n1 = {"k1": "wu", "k2": 123, "k3": ["alex", 456]} 4 5 n3 = copy.copy(n1)
3、深拷贝
深拷贝,在内存中将所有的数据重新创建一份(排除最后一层,即:python内部对字符串和数字的优化)
1 import copy 2 3 n1 = {"k1": "wu", "k2": 123, "k3": ["alex", 456]} 4 5 n4 = copy.deepcopy(n1)
4、函数
1、背景
1 def 函数名(参数): 2 3 ... 4 函数体 5 ... 6 返回值
- def:表示函数的关键字
- 函数名:函数的名称,日后根据函数名调用函数
- 函数体:函数中进行一系列的逻辑计算,如:发送邮件、计算出 [11,22,38,888,2]中的最大数等...
- 参数:为函数体提供数据
- 返回值:当函数执行完毕后,可以给调用者返回数据。
- 1、return xxx None
- 2、一旦遇到return,函数内部的return一下不执行
2.1 返回值
1 def 发送短信(): 2 3 发送短信的代码... 4 5 if 发送成功: 6 return True 7 else: 8 return False 9 10 11 while True: 12 13 # 每次执行发送短信函数,都会将返回值自动赋值给result 14 # 之后,可以根据result来写日志,或重发等操作 15 16 result = 发送短信() 17 if result == False: 18 记录日志,短信发送失败...
1 # ######### 定义函数 ######### 2 3 # name 叫做函数func的形式参数,简称:形参 4 def func(name): 5 print name 6 7 # ######### 执行函数 ######### 8 # 'wupeiqi' 叫做函数func的实际参数,简称:实参 9 func('wupeiqi')
默认参数
1 def func(name, age = 18): 2 3 print "%s:%s" %(name,age) 4 5 # 指定参数 6 func('wupeiqi', 19) 7 # 使用默认参数 8 func('alex') 9 10 注:默认参数需要放在参数列表最后
动态参数1
1 动态参数,参数转成元组 2 def func(*args): 3 4 print args 5 6 7 # 执行方式一 8 func(11,33,4,4454,5) 9 10 # 执行方式二 11 li = [11,2,2,3,3,4,54] 12 func(*li)
如果 元素参数是一个列表呢?我们把列表传入输出的一个元素是列表,但是我们想把列表的每个元素当一个参数。调用的时候加*
1 #!/usr/bin/env python 2 # _*_ coding:utf-8 _*_ 3 4 a=[1,3,4] 5 def fuc(*args): 6 #print(args) 7 return args 8 ret=fuc(a) 9 print(ret) 10 11 结果: 12 C:\Python35\python3.exe E:/py_test/s4/s5.py 13 ([1, 3, 4],) 14 15 16 17 #!/usr/bin/env python 18 # _*_ coding:utf-8 _*_ 19 20 a=[1,3,4] 21 def fuc(*args): 22 #print(args) 23 return args 24 ret=fuc(*a) 25 print(ret) 26 C:\Python35\python3.exe E:/py_test/s4/s5.py 27 (1, 3, 4)
动态参数2
1 def func(**kwargs): 2 3 print args 4 5 6 # 执行方式一 7 func(name='wupeiqi',age=18) 8 9 # 执行方式二 10 li = {'name':'wupeiqi', age:18, 'gender':'male'} 11 func(**li) 12 13 动态参数2 :**kwargs 14 15 **kwargs 意指可以传入多个元素以key= value key的格式是按照变量名的命名规范为标准的
如果 元素参数是一个字典呢?我们把列表传入输出的一个元素是字典,但是我们想把字典的每个key value当一个参数。调用的时候加** 只加*是key
1 #!/usr/bin/env python 2 # _*_ coding:utf-8 _*_ 3 4 a={"k1":2,"k2":3} 5 def fuc(**args): 6 #print(args) 7 return args 8 ret=fuc(**a) 9 print(ret) 10 11 C:\Python35\python3.exe E:/py_test/s4/s5.py 12 {'k1': 2, 'k2': 3}
动态参数3
1 def func(*args, **kwargs): 2 3 print args 4 print kwargs 5 6 万能参数
1 #!/usr/bin/env python 2 # _*_ coding:utf-8 _*_ 3 a={"k1":2,"k2":3} 4 b=[1,2,3] 5 def fuc(*args,**kwargs): 6 #print(args) 7 return args,kwargs 8 ret=fuc(*b,**a) 9 print(ret) 10 11 12 C:\Python35\python3.exe E:/py_test/s4/s5.py 13 ((1, 2, 3), {'k2': 3, 'k1': 2})
扩展:发送邮件实例
1 #!/usr/bin/env python 2 # _*_ coding:utf-8 _*_ 3 __author__ = 'liujianzuo' 4 5 6 def email(p,text,subject): 7 import smtplib 8 from email.mime.text import MIMEText 9 from email.utils import formataddr 10 11 ret = True 12 try: 13 14 msg = MIMEText(text, 'plain', 'utf-8') 15 msg['From'] = formataddr(["武沛齐",'wptawy@126.com']) 16 msg['To'] = formataddr(["走人",'424662508@qq.com']) 17 msg['Subject'] = subject 18 19 server = smtplib.SMTP("smtp.126.com", 25) 20 server.login("wptawy@126.com", "WW.3945.59") 21 server.sendmail('wptawy@126.com', [p,], msg.as_string()) 22 server.quit() 23 except: 24 ret = False 25 return ret 26 27 28 r1=email("1223995142@qq.com","python test email +===","subject==pyhon") 29 if r1: 30 print("发生成功") 31 else: 32 print("发送失败")
3、全局变量、局部变量
函数外的变量定义的全局变量,在函数内部修改不了,因为,函数内部需要global一下否则在函数内部只能是局部变量,只是变量名跟全局变量相同而已
1 #全局变量一般以大写命名,局部变量以小写命名 2 #全局变量 3 p=234 4 def f1(): 5 #局部变量 6 a=123 7 p=999 #全局变量在内部被修改。只在内部起作用 8 global p #应用到全局变量。 9 print(p) 10 print(a) 11 def f2(): 12 #局部变量 13 a=456 14 print(p) 15 print(a) 16 f1() 17 f2() 18 output:
999
123
999
456
19 总结 20 全局变量: 21 大写 22 修改,global 23 局部变量: 24 小写,仅仅在代码块中能用
Python作用域
命名空间和作用域
命名空间一共分为三种:
全局命名空间
局部命名空间
内置命名空间
*内置命名空间中存放了python解释器为我们提供的名字:input,print,str,list,tuple...它们都是我们熟悉的,拿过来就可以用的方法。
三种命名空间之间的加载与取值顺序:
加载顺序:内置命名空间(程序运行前加载)->全局命名空间(程序运行中:从上到下加载)->局部命名空间(程序运行中:调用时才加载)
取值顺序:
在局部调用:局部命名空间->全局命名空间->内置命名空间
在全局调用:全局命名空间->内置命名空间
综上所述,在找寻变量时,从小范围,一层一层到大范围去找寻。
作用域
作用域就是作用范围,按照生效范围可以分为全局作用域和局部作用域。
全局作用域:包含内置名称空间、全局名称空间,在整个文件的任意位置都能被引用、全局有效
局部作用域:局部名称空间,只能在局部范围内生效
globals和locals方法
print(globals()) print(locals())
def func(): a = 12 b = 20 print(locals()) print(globals()) func()
output:
{'a': 12, 'b': 20}
{'__name__': '__main__', '__doc__': '\n装饰器\ndef outer(func):\n def inner():\n print("123")\n r=func()\n print("456")\n return r\n return inner\n\n@outer\ndef index():\n print(1)\n return 111\n\na=index()\nprint(a)\n', '__package__': None, '__builtins__': <module 'builtins' (built-in)>, '__spec__': None, '__file__': 'E:/py/55/learn-python/oldboy/temp.py', '__cached__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000026197831518>, 'func': <function func at 0x00000261977E9158>}
在局部调用locals和globals
global关键字,nonlocal关键字。
global:
1,声明一个全局变量。
2,在局部作用域想要对全局作用域的全局变量进行修改时,需要用到 global(限于字符串,数字)。
def func(): global a a = 3 func() print(a) count = 1 def search(): global count count = 2 search() print(count)
output:
3
2
global关键字举例
ps:对可变数据类型(list,dict,set)可以直接引用不用通过global。
li = [1,2,3] dic = {'a':'b'} def change(): li.append('a') dic['q'] = 'g' print(dic) print(li) change() print(li) print(dic)
output:
{'q': 'g', 'a': 'b'}
[1, 2, 3, 'a']
[1, 2, 3, 'a']
{'q': 'g', 'a': 'b'}
对于可变数据类型的应用举例
nonlocal:
1,不能修改全局变量。
2,在局部作用域中,对父级作用域(或者更外层作用域非全局作用域)的变量进行引用和修改,并且引用的哪层,从那层及以下此变量全部发生改变。
def add_b(): b = 42 def do_global(): b = 10 print(b) def dd_nonlocal(): nonlocal b b = b + 20 print(b) dd_nonlocal() print(b) do_global() print(b) add_b()
output:
10
30
30
42
nonlocal关键字举例
函数的嵌套和作用域
函数的嵌套调用
def max2(x,y): m = x if x>y else y return m def max4(a,b,c,d): res1 = max2(a,b) res2 = max2(res1,c) res3 = max2(res2,d) return res3 # max4(23,-7,31,11)
output:
31
函数的嵌套定义
def f1(): print("in f1") def f2(): print("in f2") f2() f1() ########### def f1(): def f2(): def f3(): print("in f3") print("in f2") f3() print("in f1") f2() f1()
output:
in f1
in f2
in f1
in f2
in f3
函数的嵌套定义
函数的作用域链:小范围作用域可以使用大范围的变量,但是反之不行,他是单向的。
def f1(): a = 1 def f2(): def f3(): print(a) f3() f2() f1() ################ def f1(): a = 1 def f2(): a = 2 f2() print('a in f1 : ',a) f1()
output:
1
a in f1 : 1
作用域链应用举例
函数名的本质
函数名本质上就是函数的内存地址。
1.可以被引用
def func(): print('in func') f = func print(f)
output:
<function func at 0x0000014DD0FB9158>
2.可以被当作容器类型的元素
def f1(): print('f1') def f2(): print('f2') def f3(): print('f3') l = [f1,f2,f3] d = {'f1':f1,'f2':f2,'f3':f3} #调用 l[0]() d['f2']() 加了括号就是执行
output:
f1
f2
可以当做容器类型的元素
3.可以当作函数的参数和返回值
def f1(): print('f1') def func1(argv): argv() return argv f = func1(f1) f()
output:
f1
f1
可以当做函数的参数和返回值
第一类对象(first-class object)指 1.可在运行期创建 2.可用作函数参数或返回值 3.可存入变量的实体。
闭包
def func(): name = '太白金星' def inner(): print(name)
闭包函数:
内部函数包含对外部作用域而非全剧作用域变量的引用,该内部函数称为闭包函数
#函数内部定义的函数称为内部函数
由于有了作用域的关系,我们就不能拿到函数内部的变量和函数了。如果我们就是想拿怎么办呢?返回呀!
我们都知道函数内的变量我们要想在函数外部用,可以直接返回这个变量,那么如果我们想在函数外部调用函数内部的函数呢?
是不是直接就把这个函数的名字返回就好了?
这才是闭包函数最常用的用法
def func(): name = 'eva' def inner(): print(name) return inner f = func() f()
output:eva
判断闭包函数的方法__closure__
#输出的__closure__有cell元素 :是闭包函数 def func(): name = 'eva' def inner(): print(name) print(inner.__closure__) return inner f = func() f() #输出的__closure__为None :不是闭包函数 name = 'egon' def func2(): def inner(): print(name) print(inner.__closure__) return inner f2 = func2() f2()
def wrapper(): money = 1000 def func(): name = 'eva' def inner(): print(name,money) return inner return func f = wrapper() i = f() i()
eva 1000 闭包嵌套
from urllib.request import urlopen def but(): content = urlopen("http://www.cnblogs.com/jin-xin/articles/8259929.html").read() def get_content(): return content return get_content fn = but() content = fn() # 获取内容 print(content.decode('utf-8')) #中文显示 content2 = fn() # 重新获取内容 print(content2.decode('utf-8')) 闭包的网络应用
练习题
1、简述普通参数、指定参数、默认参数、动态参数的区别
1 """ 2 普通参数:单个是单个,多个是多个,有多少个,调用的时候就要传几个,按照顺序赋值, 3 默认参数:只能放在 普通参数后面,不能放到前面 ,不给值的话,就用默认的参数值 4 指定参数:不按照顺序,想指定给谁就给谁。 5 动态参数:*args *kwargs 当然不一定非要叫args 规范而已。*args这些参数自动组装成一个元组,**kwargs自动组装层字典 即调用的时候 传列表 key value 6 """
2、写函数,计算传入字符串中【数字】、【字母】、【空格] 以及 【其他】的个数
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 st=raw_input("str:") 5 def count_str(a): 6 sz=zm=kg=qt=0 7 # temp=str(a) 8 for i in a: 9 # print i 10 if i.isdigit(): 11 sz+=1 12 elif i.isalpha(): 13 zm+=1 14 elif i.isspace(): 15 kg+=1 16 else: 17 qt+=1 18 return (sz,zm,kg,qt) 19 jg=count_str(st) 20 print jg
3、写函数,判断用户传入的对象(字符串、列表、元组)长度是否大于5。
1 def obj_len(args): 2 if isinstance(args,str) or isinstance(args,list) or isinstance(args,tuple): 3 if len(args)>5: 4 return True 5 else: 6 return False 7 else: 8 return None 9 st="jkljkjlj" 10 lis=[11,22,33,44,55] 11 tup=(11,22,33,44,55,66) 12 print obj_len(st),obj_len(lis),obj_len(tup)
4、写函数,检查用户传入的对象(字符串、列表、元组)的每一个元素是否含有空内容。
1 def has_space(args): 2 if isinstance(args,str) or isinstance(args,list) or isinstance(args,tuple): 3 for i in args: 4 if i == " ": 5 return True 6 break 7 else: 8 return False 9 else: 10 return None 11 st="jkljkjlj" 12 lis=[11,22,33,44,55," "] 13 tup=(11,22,33,44,55,66," ") 14 print has_space(st),has_space(lis),has_space(tup)
5、写函数,检查传入列表的长度,如果大于2,那么仅保留前两个长度的内容,并将新内容返回给调用者。
1 # def fun(args): 2 # if len(args)>2: 3 # ret=args[0:2] 4 # return ret 5 # else: 6 # return args 7 # # return args 也可以不写else直接这样写 8 # inp=[11,22,33,44,55] 9 # print fun(inp) 10 11 -------------------- 12 def fun2(args): 13 if len(args)>2: 14 del args[2:] 15 li=[11,22,33,444,55] 16 fun2(li) 17 print li
6、写函数,检查获取传入列表或元组对象的所有奇数位索引对应的元素,并将其作为新列表返回给调用者。
1 def fun(x): 2 ret=x[1::2] 3 return ret 4 inp=[11,22,33,44,55] 5 print fun(inp)
7、写函数,检查传入字典的每一个value的长度,如果大于2,那么仅保留前两个长度的内容,并将新内容返回给调用者。
dic
=
{
"k1"
:
"v1v1"
,
"k2"
: [
11
,
22
,
33
,
44
]}
PS:字典中的value只能是字符串或列表
1 dic = {"k1": "v1v1", "k2": [11,22,33,44],"k3":"ca","k4":[11,22]} 2 def fun(x): 3 di={} 4 for i,j in x.items(): 5 # print i,j 6 if len(j)>2: 7 di[i] = j[:2] 8 else: 9 di[i] = j 10 return di 11 ret=fun(dic) 12 print ret
8、写函数,利用递归获取斐波那契数列中的第 10 个数,并将该值返回给调用者。