python学习之路基础篇(第四篇)
一、课程内容回顾
1.python基础
2.基本数据类型 (str|list|dict|tuple)
3.将字符串“老男人”转换成utf-8
s = "老男人" ret = bytes(s,encoding="utf-8") print(ret) ret1 = bytes(s,encoding="gbk") print(ret1) #程序运行结果如下: b'\xe8\x80\x81\xe7\x94\xb7\xe4\xba\xba' b'\xc0\xcf\xc4\xd0\xc8\xcb'
4.函数的小误区
请观察下面一段代码,猜猜运行结果是什么?
li = [11,22,33,44,55,] def f1(arg): arg.append(66) li = f1(li) print(li)
大多数人都认为返回结果是[11,22,33,44,55,66],有个别人认为结果是None,亲,你认为的运行结果是什么,是其中之一么,还是别的?
#正确的答案是:None
li = [11,22,33,44,55,] def f1(arg): arg.append(66) li = f1(li) print(li) 程序运行结果: None
有的人还是不理解,结果怎么回事None呢,应该是[11,22,33,44,55,66]才对呀,别着急,听我慢慢说,我们来看下面的一段代码:
li = [11,22,33,44,55,] def f1(arg): arg.append(66) return arg li = f1(li) print(li) 程序运行结果: [11, 22, 33, 44, 55, 66]
看到这儿,大部分人已经明白了,或许还有一小部分还是不太理解,大家想一想,学习函数的时候,如果我们想要获取程序的执行结果,通过显示的return进行返回,如果没有指定的话,函数的默认返回值是None,我们在接着说第一段代码的 li = f1(li),此处是将程序的返回结果赋值给li,而我们知道程序的默认返回值是None,再将其值赋值给li,所以li的也是None,当我们执行print(li)将li的值给打印出来的时候,输出结果当然是None,现在应该知道为什么上一段代码的执行结果是None了吧。
说明:这段代码主要考察的是一个知识点:函数的默认返回值是None
5.返回值为False
常见的有:空列表:[] 空元组:() 空字典:{} 空集合:set() None 数字0 空格 “ ”
6.看了试卷上的几个题目,涉及的相关知识点
- 集合的交集
- 将字符串转换成utf-8
- False
- 内置函数:any all bool abs
二、内置函数
1.callable():判断传入的参数是否可以被调用
#定义一个函数 def f1(): print(123) #定义一个变量 s1 = 'hello' #判断f1和s1是否可以被调用 print(callable(f1)) print(callable(s1)) 程序运行结果: True False
2.chr() ord() :数字和字母之间的转换
#chr:将数字转换成字母(ASCII) let = chr(65) #ord:将字母转换成数字(ASCII) num = ord('C') print(let) print(num) 程序运行结果如下: A 67
3.random():生成随机数
#random.randrange(1,10):随机生成1-9之间的任何一个数字
#random.random():随机生成0-1之间的小数
import random ret = random.randrange(1,10) print(ret) ret1 = random.random() print(ret1) 程序运行结果: 8 0.22612376370730292
4.compile() |eval() |exec()
compile():把字符串编译成python代码,然后由exec()来执行
其内部实现的机制: 1.通过open读取文件内容,然后放到内存中 2.python内部把字符串---->编译---->特殊代码 3.执行代码 s = "print(123)" r = compile(s,"<string>","exec") #编译,把字符串编译成python代码 exec(r) #执行python代码
其中,compile中的第三个参数有三种: single:单行执行程序 eval:把字符串转换成python表达式 exec:编译成和python代码一样的内容 程序执行结果如下: print(123) 123
eveal():执行函数,把字符串转换成python表达式后再执行,并获取运算结果,默认有返回值
exec():执行函数,接收字符串或者是python代码,如果是python代码直接执行,如果是字符串先转换成python代码再执行
s1 = '7+9+8' r = eval(s1) print(r) exec('7+9+8') 程序运行结果: 24
5.dir()|help()
dir():快速查看对象提供了哪些方法
help():查看帮助
help(list):查看list类的详细的属性和方法
print(dir(list))
程序执行结果如下:
['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
6.divmod()
divmod():返回值有两个,一个是商,一个是余数
#典型应用 共97条记录,每页显示10条,需要多少页
r = divmod(97,10) print(r) print(r[0]) print(r[1]) 程序运行结果如下: (9, 7) 9 7
7.enumerate():枚举
dic1 = {"mouse":65,"clothes":200,"shoes":500} for key in enumerate(dic1): print(key) 程序运行结果如下: (0, 'clothes') (1, 'mouse') (2, 'shoes')
8.isinstance():判断对象是否是某个类的实例
s = [11,22,33] r = isinstance(s,list) print(r) 程序运行结果如下: True
9.filter():将符合条件的元素过滤出来
需求:找出列表中大于33的所有元素 1.利用已有的知识来实现 li = [11,22,33,44,55,] full = [] for i in range(5): if li[i] > 33: full.append(li[i]) print(full) 程序运行结果如下: [44, 55] 2.使用filter内置函数来实现
#内部实现机制
filter内部,循环第二个参数可迭代的对象
result = []
for item in 第二个参数:
r = 第二个参数item
if r:
result.append(r)
return result
#用法:filter(函数或者是None,可迭代的对象(列表,字典,字符串))
#用法:filter(None,可迭代的对象)
li = [11,22,33,{},(),""]
ret = filter(None,li)
print(ret)
程序运行结果如下:
[11,22,33]
#用法:filter(函数,可迭代的对象) def f2(a): if a > 33: return True li = [11,22,33,44,55,66,77,] ret = filter(f2,li) print(list(ret)) 程序运行结果如下: [44, 55, 66, 77] 3.filter和lambda结合使用 f1 = lambda a :a > 33 ret = f1(20) print(ret) ret = f1(90) print(ret) li = [11,33,44,55,66,77,] result = filter(lambda a: a>33,li) print(list(result)) 程序运行结果如下: False True [44, 55, 66, 77]
10.map()
#需求:将列表中每一个元素加100 #1.利用已有的知识来实现 li = [11,22,33,44,55,] def f1(arg): result = [] for i in arg: result.append(i+100) return result ret = f1(li) print(ret) 程序运行结果如下: [111, 122, 133, 144, 155] #2.利用内置函数map来实现 #用法:map(函数,可迭代的对象(可以for循环的对象)) li = [11,22,33,44,55,66,] def f2(arg): return arg + 100 ret = map(f2,li) print(list(ret)) 程序执行结果如下: [111, 122, 133, 144, 155, 166] #2.map和lambda结合使用 li = [11,22,33,44,55,66,] ret = map(lambda a:a + 100,li) print(list(ret)) 程序执行结果如下: [111, 122, 133, 144, 155, 166]
11.globals() locals()
#globals():所有的全局变量 #locals():所有的局部变量 #定义一个全局变量 NAME = 'mohan' #定义一个函数 def show(): a = 123 print(globals()) print(locals()) show() #调用函数 程序运行结果如下: {'__doc__': None, '__spec__': None, 'NAME': 'mohan', 'show': <function show at 0x000000000115CC80>, '__file__': 'D:/PythonS13/Day4/preview/b1.py', '__package__': None, '__cached__': None, '__builtins__': <module 'builtins' (built-in)>, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000000000A05DD8>, '__name__': '__main__'} {'a': 123}
12.hash()
Python中的hash函数用于求取一个字符串或者数值的哈希值,由于Python中任何数据类型都可以转换为字符串,所以我们利用这个函数来进行简单的哈希值计算,比如: print(hash('test')) print(hash(2)) print(str([1,2,3,4])) 也可以求得字典的,但是由于字典本身无序(集合也是如此),所以需要加一些小的变动: print(str(sorted({"k1":"v1"}))) 先将字典排序,而后转为字符串,最后求得哈希值。 倘若是字典嵌套字典,可以对其中的每一个子字典求哈希值,而后求和: #Return hash for a dict which may contain a dict as its value def DHash(Dict): dh=0 for tmp in Dict: if isinstance(Dict[tmp],dict): dh+=hash(tmp)+hash(str(sorted(Dict[tmp],key=lambda d: d[0]))) else: dh+=hash(tmp)+hash(str(Dict[tmp])) return dh 注意: 使用这个函数之前,先看一下help的说明: Return a hash value for the object. Two objects with the same value have the same hash value. The reverse is not necessarily true, but likely. 也就是说,同样的哈希值并不一定对应同样的对象,但大多是,也就是说使用它的时候需要考虑条件是否不是非常严格。
13.len()
#python3既可以按照字节也可以按照字符来进行运算,python2只能按照字节来进行运算 s = "李杰" print(len(s)) s1 = "李杰" b = bytes(s1,encoding="utf-8") print(len(b)) bytes() 程序运行结果如下: 2 -------- python2 6 -------- python3
14.max()|min()|sum()
#内置函数 #max():求最大值 #min():求最小值 #sum():求和 li = [11,22,33,44,88,90] print(max(li)) print(min(li)) print(sum(li)) 程序运行结果如下: 90 11 288
15.memoryview():和内存地址相关的类
16.object():所有类的父类
17.pow():次方,幂
print(2 ** 10) ret = pow(2,8) print(ret) 程序运行结果如下: 1024 256
18.property():特性,面向对象时会具体讲解
19.range():生成随机数
20.repr():执行类的__repr__方法
class Foo(): def __repr__(self): print('123') repr(Foo()) 程序运行结果如下: 123
21:reversed():反转
li = [11,22,33,4,5,7,] ret = sorted(li) print(ret) 程序运行结果如下: [4, 5, 7, 11, 22, 33]
22.round():四舍五入
a = 1.1 b = 2.6 print(round(a)) print(round(b)) 程序运行结果如下: 1 3
23.set():集合
24.slice():切片 python3新增
和字符串的切片是一样的 s1 = "abcdedghijklmnopswerqr" print(s1[0:10:2]) 程序运行结果如下: acegi
25.sorted():排序
li = [1,3,4,2,5,89,43,21] ret = sorted(li) print(ret) 程序运行结果如下: [1, 2, 3, 4, 5, 21, 43, 89]
26.super():面向对象时会进行讲解
27.vars():当前模块可用的变量
28.zip()
l1 = ['li',1,2,3,3] l2 = ['yue',12,22,43,63] l3 = ['mei',11,21,31,83] r = zip(l1,l2,l3) temp = list(r)[0] ret = " ".join(temp) print(ret) 程序运行结果如下: li yue mei
三、yield生成器
1.yield和return的区别:
yield:跳出函数后会记录当前函数的状态,当下次调用的时候从记录的状态开始
return:执行函数时遇到return语句将直接跳出函数
2.对比range 和 xrange 的区别
>>> print range(10) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>> print xrange(10) xrange(10)
如上代码所示,range会在内存中创建所有指定的数字,而xrange不会立即创建,只有在迭代循环时才去创建。
3.自定义生成器
def mrange(arg): seed = 0 while True: seed = seed +1 if seed > arg: return else: yield seed for i in mrange(10): print(i) 程序执行结果如下: 1 2 3 4 5 6 7 8 9 10
四、装饰器
1.什么是装饰器
装饰器是具有特殊含义的函数
- 可以使用装饰器来装饰函数或类
- 使用装饰器可以在不改变原函数的基础上在执行函数前后添加相应操作
- 简单的来说,装饰器就是在不修改原函数的情况下,对原函数进行一层封装
公司有N个业务部门,1个基础平台部门,基础平台负责提供底层的功能,如:数据库操作、redis调用、监控API等功能。业务部门使用基础功能时,只需调用基础平台提供的功能即可。
############### 基础平台提供的功能如下 ############### def f1(): print('f1') def f2(): print('f2') def f3(): print('f3') ........... ........... def f100(): print('f100') ############### 业务部门A 调用基础平台提供的功能 ############### f1() f2() f87() ...... ...... f44() ############### 业务部门B 调用基础平台提供的功能 ############### f1() f2() f82() ...... ...... f94()
需求:产品总监提出要在执行函数后打印日志
解决问题的方法有2种
1.N个业务线部门做修改,添加打印日志的功能
2.基础平台做修改,添加打印日志的问题
第一种方法:设计的业务线比较多,修改起来比较费时费力,一旦修改不慎会造成业务无法正常运行
第二种方法:基础平台做修改相对简单,也不会影响业务的正常运行
############### 基础平台提供的功能如下 ############### def f1(): # 打印日志 print 'f1' def f2(): # 打印日志 print 'f2' def f3(): # 打印日志 print 'f3' ................... .................. def f100(): # 打印日志 print 'f100' ############### 业务部门不变 ############### ### 业务部门A 调用基础平台提供的功能###
f1() f2() f87() ...... ...... f44()
### 业务部门B 调用基础平台提供的功能 ###
f1() f2() f82() ...... ...... f94()
另一种方法:定义一个函数fun1,将要实现的功能添加通过函数体来实现,在基础平台的相关函数中调用fun1
最理想的结果是:在不改变原函数的情况下能够实现打印日志的功能,装饰器正好可以解决这个问题
def outer(func): def inner(): print("打印日志") return inner @outer def f1(): print('f1') @outer def f2(): print('f2') @outer def f3(): print('f3') .......... .......... @outer def f100(): print('f100') f1() f2() #程序执行结果如下: 打印日志 打印日志
装饰器的工作流程:
python执行代码时,是由上到下执行
1.执行到def outer(func):这里把def outer(func)函数加载到内存
2.当执行到@outer的时候会函数f1作为参数传递给outer函数,此时func = f1
3.接下来遇到def inner()时,将函数inner()加载到内存
4.将inner函数作为值返回
5.将inner函数重新赋值给f1,执行f1就相当于执行inner函数
6.执行inner函数,第一步执行func(),即执行原f1函数
7.接下来执行print("打印日志")代码,实现了在函数执行后打印日志的功能
下面以一条业务线调用基础平台功能来说明装饰器是如何工作的
def outer(func): def inner(): func() print("打印日志") return inner #@ + 函数名 #功能 # 1.自动执行outer函数并且将其下面的函数名f1当作参数传递 # 2.将outer函数的返回值,重复赋值给f1 @outer def f1(): print('f1') f1()
1.第一步:遇到关键字def将outer函数加载到内存
2.第二步:遇到@outer则执行outer函数并将其下面的函数f1作为参数进行传递给outer(func),即func=f1
3.第三步:执行outer函数,遇到def关键字将inner函数加载到内存
4.第四步:将inner函数作为返回值进行返回
5.第五步:将inner函数赋值给f1函数,即f1=inner,此时执行f1函数即执行inner函数
6.第六步:执行inner函数
7.第七步:执行func,即执行原函数f1
8.第八步:执行原函数f1
9.第九步:执行print(“打印日志”)
装饰器是否可以有参数呢?当然可以,上面不是说了么,装饰器也是一个函数。它不但可以有一个参数,还可以有多个参数,并且还可以有返回值return。
1.带返回值的装饰器
#装饰器 return def outer(func): def inner(): print('before') r = func() print('after') return r return inner @outer def f1(): print('f1') return '砍你' ret = f1() print(ret) 程序执行结果: before f1 after 砍你
2.带一个参数装饰器
带参数的装饰器 def outer(func): def inner(arg): print('before') r = func(arg) print('after') return r return inner @outer def f1(arg): print(arg) return '砍你' ret = f1('hello') print(ret) 程序执行结果如下: before hello after 砍你
3.带多个参数的装饰器
#多个参数的装饰器,装饰器结合万能参数的使用 def outer(func): def inner(*args,**kwargs): print('before') r = func(*args,**kwargs) print('after') return r return inner @outer def f1(arg): print(arg) return '砍你' @outer def f2(arg1,arg2): print(arg1,arg2) return '砍你' ret = f1('hello') print(ret) ret1 = f2(11,22) print(ret1) 程序执行结果如下: before hello after 砍你 before 11 22 after 砍你
参考文档:http://www.cnblogs.com/luotianshuai/p/4967834.html
http://www.cnblogs.com/wupeiqi/articles/4943406.html