一:生成器
1.为什么需要生成器?
•
通过列表生成式,我们可以直接创建一个列表,受到内存限
制,列表容量肯定是有限的;
•
创建一个包含 100 万个元素的列表,占用很大的存储空间;
2.生成器是什么?
• 在循环的过程中不断推算出后续的元素呢?这样就不必创
建完整的 list,从而节省大量的空间。在 Python 中,这种一
边循环一边计算的机制,称为生成器(Generator)
3.怎么创建生成器?
- 把一个列表生成式的 [] 改成 ()
- 使用g.next()方法依次读取元素(麻烦)
- 使用 for 循环(推荐)
4.yield工作原理:
调用g.next()方法时时, 执行函数,遇到yield就停止执行;
再次执行g.next()方法时, 从yield停止的地方继续执行;
5.怎么访问生成器的内容
- g.next()
- for循环;
def fib(max):
n, a, b = 0, 1, 1
while n < max:
yield a # 执行函数时, 遇到yield就停止执行;再次执行函数时, 从yield停止的地方继续执行;
n += 1
a, b = b, a+b
g = fib(10)
g.next()
g.next()
g.next()
6.生成器的其他应用
- 无缓冲区的生产者-消费者模型: java, php, python
- 有缓冲区的生产者-消费者模型: java, php, python
(消费) =======【商店】======== (生产)
import time
import random
# 有yield关键字的函数称为生成器函数;
def consumer(name):
print "%s准备取购买包子......." %(name)
while True:
kind = yield
print "消费者[%s]购买了[%s]口味的包子" %(name, kind)
def producer(name):
# c1和c2是生成器;
c1 = consumer("王凯")
c2 = consumer("刘泳")
# 第一次执行函数;
c1.next()
c2.next()
print "厨师[%s]正在制作包子......" %(name)
for i in ['特辣', '麻辣']:
# 停止0~1秒之间的随机数,用来模拟生产包子;
time.sleep(random.random())
print "【%s】正在生产[%s]口味的包子!" %(name, i)
c1.send(i)
c2.send(i)
producer("fentiao")
生成器与文本处理
对于大型文件的每一行执行相应操作;
consumer函数有=yield, 是生成器函数;
def consumer():
while True:
line = yield # c.next()停止在这一行;
print line.upper() # 打印被操作的文件每一行内容;
producer函数有=yield, 是生成器函数;
def producer():
with open('/etc/passwd') as f: # 打开/etc/passwd文件, 返回一个f的文件对象;
for i in f: # 查看文件内容, for i in f, 依次查看文件的每一行; # i: 第一行文件内容, 2, 3,4
yield i
print i
c = consumer() # c是生成器;
c.next() # 通过next方法执行consumer函数, 遇到yield停止;
for line in producer(): # producer()是生成器; 生成器是可迭代的, 可以for循环; # 24行的i给line
c.send(line)
迷你聊天机器人
def chat_robot():
res = ''
while True:
received = yield res
if "name" in received or "姓名" in received:
res = "你好, 我是微软小冰"
elif "年龄" in received or 'age' in received:
res = "18"
else:
res = "我还在学习中, 不清楚你在说什么."
Chat = chat_robot()
# Chat.next()
next(Chat)
while True:
send_data = raw_input("A>>:")
recv_data = Chat.send(send_data)
print "微软小冰>>:%s" %(recv_data)
# g.next() | next(g): 运行生成器函数, 遇到yield停止; 再次next(), 从yield停止的地方继续执行;
# g.send(): 给生成器函数传值, 实现与生成器的交互, 在函数的yield前面可以通过一个变量接收值;
# close:关闭生成器, 不能再调用next方法, 否则报错StopIteration;
# throw:
"""
g = (i**2 for i in range(10))
g
Out[3]: <generator object <genexpr> at 0x3a5e500>
g.next()
Out[4]: 0
g.next()
Out[5]: 1
g.next()
Out[6]: 4
g.close()
g.next()
Traceback (most recent call last):
File "/usr/lib/python2.7/site-packages/IPython/core/interactiveshell.py", line 2882, in run_code
exec(code_obj, self.user_global_ns, self.user_ns)
File "<ipython-input-8-7dbbdfed0980>", line 1, in <module>
g.next()
StopIteration
生成器的throw方法
throw方法:给生成器发送一个异常;
def fun():
while True:
yield 'a'
yield 'b'
g = fun()
print next(g)
g.throw(StopIteration)
什么是异常?
# NameError,ZeroDivisionError,IndexError,KeyError
二:高级函数
1.什么是高级函数
变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另
一个函数作为参数,这种函数就称之为高阶函数。
# def fun(f):
# return f()
#
# def hello():
# return "hello world"
#
# print fun(hello)
# def fun():
# def hello():
# return "hello world"
# return hello
# f = fun()
# print f()
2.map函数
map() 函数接收两个参数,一个是函数,一个是序列, map 将传入的函数依
次作用到序列的每个元素,并把结果作为新的 list 返回。
不需要 map() 函数,写一个循环,也可以计算出结果.
map() 作为高阶函数,把运算规则抽象了.
# def f(x):
# return x**2
#
# # map函数至少需要两个参数, 第一个参数是函数名, 第2个参数是序列(str, list, tuple);
# # map的功能: 把序列中的每一个元素作为参数, 传给函数进行处理;
# print map(f, [1,2,3,4,5])
# print map(int, ['1', '2', '3', '4'])
3.reduce函数
reduce 把一个函数作用在一个序列[x1, x2, x3…]上,这个函数必须接
收两个参数,reduce 把结果继续和序列的下一个元素做累积计算。
def add(x, y):
return x + y
# reduce函数至少需要两个参数, 第一个参数是函数名<注意, 函数名必须传递两个参数>, 第2个参数是序列(str, list, tuple);
# reduce的功能: 把序列中的前2个元素作为参数(add(1,2)), 传给函数进行处理;然后将add(1,2)的结果作为参数, 继续传递add(add(1,2),3);
print reduce(add, range(1, 1001)) # add(add(add(1,2),3),4)
4.filter函数
filter() 也接收一个函数和一个序列。和 map() 不同的时,
filter() 把传入的函数依次作用于每个元素,然后根据返回值是 True
还是 False 决定保留还是丢弃该元素。
# filter函数至少需要两个参数, 第一个参数是函数名<注意, 函数的返回值必须是True或者False>, 第2个参数是序列(str, list, tuple);
# filter的功能: 把序列中执行函数的返回值为True的保留, 为False的丢弃;
def isodd(x):
return x % 2 == 0
print filter(isodd, range(1, 10))
找出指定范围的所有素数;
def isPrime(num):
# 2是最小的质数;
if num == 2: return True
# 负数或者能被2整除的数, 不是质数;
if num <= 1 or num%2 == 0: return False
for i in range(3,num,2): ## 3~num-1
# 如果num能被1或者它本身的其他数整除, 则不是质数;
if num % i == 0:
return False
# 一直从3~num-1判断, 都没有被整除, 则是质数;
else:
return True
print filter(isPrime, range(1, 101))
阶乘
def fun(x, y):
return x * y
# 1000阶乘的结果
res = reduce(fun, range(1, 1001))
print res
#统计阶乘结果有多少个0;
res_s = str(res)
print res_s.count('0')
名称规范
names = ['adam', 'LISA', 'barT', 12]
def title(x):
if isinstance(x, str):
return x.title()
return x
# else:
# return x
print map(title, names)
删除素数
def isPrime(num):
# 2是最小的质数;
if num == 2: return True
# 负数或者能被2整除的数, 不是质数;
if num <= 1 or num%2 == 0: return False
for i in range(3,num,2): ## 3~num-1
# 如果num能被1或者它本身的其他数整除, 则不是质数;
if num % i == 0:
return False
# 一直从3~num-1判断, 都没有被整除, 则是质数;
else:
return True
def isNotPrime(num):
return not isPrime(num)
print filter(isNotPrime, range(1, 101))
5.sorted函数
- • 排序也是在程序中经常用到的算法。 无论使用冒泡排序还是快速 排序,排序的核心是比较两个元素的大小。通常规定如下:
x < y, return -1
x == y, return 0
x > y, return 1
li.sort(): 只针对于列表排序;
sorted():
import random
li = range(100)
# 打乱序列的顺序;
random.shuffle(li)
# print li
# 默认情况, 由小到大进行排序;
print sorted(li)
# reverse=True时, 由大到小进行排序;
print sorted(li, reverse=True)
# # cmp如果a>b, 返回1; a=b, 返回0; a<b, 返回-1;
# print cmp(1, 2)
# print cmp(2, 1)
# print cmp(1, 1)
users = ['abx', 'Alice', 'bob', 'Harry', 'hub']
def ignore_case_cmp(x, y):
return cmp(x.lower(), y.lower())
# cmp=后面跟的函数要求:
# 1). 函数需要传递两个参数;
# 2). 函数要么返回1, -1或者0;
print sorted(users, cmp=ignore_case_cmp)
典例
goods = [
['computer', 230, 4000],
['apple', 2000, 4],
['xiaomi', 23, 1999],
['mp3', 2, 40]
]
# 把goods[0]传给 key=lambda x: x[2]; 4000
# 把goods[1]传给 key=lambda x: x[2]; 4
# 把goods[2]传给 key=lambda x: x[2]; 1999
# 把goods[3]传给 key=lambda x: x[2]; 40
# # 找出价格最高的商品名称;
# price_sort_goods = sorted(goods, key=lambda x: x[2])
# print price_sort_goods[-1][0]
#
# 找出商品数量最少的商品名称和商品数量;
count_sort_goods = sorted(goods, key = lambda x:x[1])
print count_sort_goods
# print count_sort_goods[0][:2]
#
# goods_dict = {
# '001': {
# 'name': 'computer',
# 'price': 4000,
# 'count': 20,
# },
# '002': {
# 'name': 'apple',
# 'price': 2,
# 'count': 100
# },
# '003': {
# 'name': 'xiaomi',
# 'price': 2999,
# 'count': 10
# }
# }
#
# # 找出价格最高的商品名称;
# price_sort_goods_dict = sorted(goods_dict.values(), key=lambda x: x['price'])
# print price_sort_goods_dict[-1]['name']
#
# # 找出商品数量最少的商品名称和商品数量;
# count_sort_goods_dict = sorted(goods_dict.values(), key=lambda x: x['count'])
# print count_sort_goods_dict[0]['name'], count_sort_goods_dict[0]['count']
6.匿名函数
def add(x, y):
return x + y
print add(1, 2)
匿名函数的格式: lambda 形式参数:返回值
f = lambda x, y: x + y
print f(2, 3)
求10的阶乘;
print reduce(lambda x, y: x * y, range(1, 11))
求1~10之间所有的偶数;
print filter(lambda x: x % 2 == 0, range(1, 11))
匿名函数的默认参数;
f = lambda x, y=2: x ** y
print f(2)
print f(2, 4)
匿名函数的可变参数;
f = lambda *args: sum(args)
print f(1,2,2,43,4)
print f(1,2,2)
匿名函数的关键字参数;
f = lambda **kwargs: kwargs.keys()
print f(name="fentiao", age=5)
携程2018笔试编程题: 题目内容看群图片
nums = [0, 7, 0, 1, 2, 1, 5,1, 7, 8, 0, 67, 1, 3, 4]
默认排序时; 0, 1
print sorted(nums, key=lambda x: 0 if x == 0 else 1, reverse=True)
三:装饰器
1.什么是装饰器
装饰器就是用来装饰函数。
• 想要增强原有函数的功能; • 但不希望修改now()函数的定义; • 在代码运行期间动态增加功能的方式;
•定义的装饰器实质是返回函数的高阶函数。(试试下面的装饰器)
import time
def timeIt(func):
def warp(arg):
start = datetime.datetime.now()
func(arg)
end = datetime.datetime.now()
cost = end - start
print "execute %s spend %s" % (func.__name__,cost.total_seconds())
return warp
@timeIt # 这里是 python 提供的一个语法糖
def func(arg):
time.sleep(arg)
func(3)
import time
import random
def Timer(f):
def wrapper():
start_time = time.time()
f()
end_time = time.time()
print "程序运行时间为%s" %(end_time-start_time)
return wrapper
@Timer
def fun1():
print "fun1....."
time.sleep(random.random())
@Timer
def fun2():
print "fun2....."
time.sleep(random.random())
def fun3():
print "fun3....."
time.sleep(random.random())
fun1()
fun2()
fun3()
# 此处省略100个函数
闭包: 在函数里面嵌套一个函数
装饰器: 器,指的就是函数; 用来装饰函数的函数;
产品经理, 开发人员
import time
# def addWelcome():
# # print "七一建党节快乐!"
# start_time = time.time()
# return start_time
#
#
#
# def afterWelcome():
# end_time = time.time()
# return end_time
# def saveMoney():
# start_time = addWelcome()
# print "存钱......"
# end_time = afterWelcome()
# print end_time-start_time
def Timer(f): # f = saveMoney
def wrapper():
start_time = time.time()
f() # saveMoney()
end_time = time.time()
print "%s执行时间为%s" %(f.__name__, end_time-start_time)
return wrapper #
@Timer # saveMoney = Timer(saveMoney) # saveMoney = wrapper
def saveMoney():
print "存钱......"
saveMoney() #
@Timer # transferMoney = Timer(transferMoney)
def transferMoney():
print "转账......"
transferMoney()
# print saveMoney.__name__
# transferMoney()
# 编写装饰器is_admin, 如果是管理员用户, 则执行函数, 如果不是管理员, 则报错;
def is_admin(f):
def wrapper(name):
if name == 'admin':
f(name)
else:
print "Error: not admin user"
return wrapper
@is_admin
def fun(name):
print "fun......"
fun('admin')
装饰器模版
import time
import functools
def Timer(f): # f=add
# 为什么装饰器中嵌套函数? 为了不改变原有函数的调用方式;
@functools.wraps(f)
def wrapper(*args, **kwargs):
"""\twrapper\t"""
start_time = time.time()
tmp = f(*args, **kwargs) # add(*args, **kwargs)
end_time = time.time()
print end_time-start_time
return tmp
return wrapper
@Timer
def add(*args):
return sum(args)
print add(1,2,3,4,5,56)
@Timer #login = Timer(login)
def login():
"""\tlogin\t"""
print "login......"
解析装饰器
import time
def Timer(fun): # fun=login
def wrapper(*args, **kwargs): # *args, **kwargs是接收值; args = (user, passwd)
start_time = time.time()
fun(*args, **kwargs) # *args, **kwargs是对于元组和字典解包;
end_time = time.time()
print "%s runs %ss" %(fun.__name__, end_time-start_time)
return wrapper # 返回wrapper
@Timer # login=Timer(login) ====> login=wrapper
def login(name, passwd):
if name=='root' and passwd == 'redhat':
print "login ok"
else:
print "login fail"
login('root', 'westos') # wrapper('root', 'westos')
装饰器_原有属性保留
# 想要被装饰的函数保留原有属性, 必须对装饰器;里面嵌套的函数加@functools.wrap(f)
import time
import functools
def Timer(f): # f=add
# 为什么装饰器中嵌套函数? 为了不改变原有函数的调用方式;
@functools.wraps(f)
def wrapper(*args, **kwargs):
"""\twrapper\t"""
start_time = time.time()
tmp = f(*args, **kwargs) # add(*args, **kwargs)
end_time = time.time()
print end_time-start_time
return tmp
return wrapper
@Timer
def add(*args):
return sum(args)
print add(1,2,3,4,5,56)
@Timer #login = Timer(login)
def login():
"""\tlogin\t"""
print "login......"
login()
# 默认情况下, 装饰的函数, 名称和帮助文档是wrapper的;
# 如何保留原有函数的所有属性? 对包装的函数加一个装饰器 @functools.wraps(f);
print login.__name__
print login.__doc__
#
# def fun():
# """ fun: 打印信息"""
# print "fun....."
# # 打印函数名;
# print fun.__name__
# # 打印函数的帮助文档;
# print fun.__doc__
获取函数参数
# is_admin:判断调用函数的用户是否为管理员admin;
# 如果是admin, 执行函数;
# 如果不是admin,则报错;
import inspect
def is_admin(f):
def wrapper(*args, **kwargs):
# inspect.getcallargs将串的参数封装为一个字典,
# 字典的key值为形式参数,value值为真正传的值;
fun_args = inspect.getcallargs(f, *args, **kwargs)
print fun_args
# fun_args = {'username': 'admin', 'money': 100}
if fun_args.get('username') != 'admin':
# if kwargs.get('username') != 'admin':
return "不是admin用户"
return f(*args, **kwargs)
return wrapper
@is_admin # transfer = is_admin(transfer)
def transfer(username, money):
print "%s transfer %s......." % (username, money)
transfer('admin', 100)
示例
编写#装饰器required_ints, 条件如下:
1). 确保函数接收到的每一个参数都是整数; # 如何判断变量的类型? type(s), isinstance(s,str)
2). 如果参数不是整形数, 抛出异常raise TypeError(“参数必须为整形”)
“”“
import functools
def required_ints(f):
@functools.wraps(f)
def wrapper(*args, **kwargs):
# args:元组; 判断元组里面的每一个元素是否为整数;
# kwargs:字典, 判断字典的每一个value值是否为整形数;
for arg in args + tuple(kwargs.values()):
if not isinstance(arg, int):
raise TypeError("参数必须为整形") # 抛出异常
# 当判断完所有的参数, 没有一个不是整形,则执行被装饰的函数;
else:
return f(*args, **kwargs)
return wrapper
@required_ints
def add(*args):
return sum(args)
print add(1,2,3,67,89, 1.0)
装饰器包含参数
import functools
# 如果要给装饰器传参数, 如何操作?
def required_type(*args_type):
def required(f):
@functools.wraps(f)
def wrapper(*args, **kwargs):
# args:元组; 判断元组里面的每一个元素是否为整数;
# kwargs:字典, 判断字典的每一个value值是否为整形数;
for arg in args + tuple(kwargs.values()):
if not isinstance(arg, args_type):
raise TypeError("参数必须为%s" %(args_type)) # 抛出异常
# 当判断完所有的参数, 没有一个不是整形,则执行被装饰的函数;
else:
return f(*args, **kwargs)
return wrapper
return required
@required_type(int, float)
def add(*args):
return sum(args)
@required_type(str)
def data(*args):
return [i.title() for i in args]
装饰器总结
1. 编写装饰器的框架:
import functools
def 装饰器名称(f):
@functools.wraps(f)
def wrapper(*args, **kwargs):
pass
return wrapper
2. pass里面需要的几个框架: 装饰器里面内容
2-1.
执行函数之前做的操作
res = f(*args, **kwargs)
执行函数之前做的操作
return res
2-2.
if 满足条件:
执行函数
res = f(*args, **kwargs)
return res
else:
print "报错"
3. 装饰器的装饰器
@装饰器名称 # 函数名 = 装饰器名称(函数名)
def 函数名():
pass
函数名() # 实质在调用wrapper函数
4.
@functools.wrap(f)
inspect.getcallargs() inspect.getcallargs将串的参数封装为一个字典
四:模块
1.什么是模块
在 Python 中,一个.py文件就称之为一个模块(Module)。
- •大大提高了代码的可维护性;
- •编写代码不必从零开始。当一个模块编写完毕,就可以被其他地方引用;
import sys
def test():
args = sys.argv
if len(args) == 1:
print 'Hello world'
elif len(args) == 2:
print 'Hello %s!' %args[1]
else:
print 'Too many arguments!'
if __name__ == '__main__':
test()
调用模块时用import xxx
2.模块的分类
内置模块
from future import print_function
from future import division
import random
import time
import os
from collections import Iterable
自定义模块
import add
直接调用模块里面的变量名;
print add.a
直接调用模块里面的函数;
第一个add: 模块名
第二个add: 函数名
print add.add(1,2,3,4,5)
第三方模块: 别人写的优秀的python代码,上传到pypi;
eg: itchat, 使用时, 必须pip install itchat
import itchat
第三方模块安装:
1). pip install 第三方模块名称
2). pycharm里面设置中可以安装;
python模块的默认搜索路径的查找方式:
import sys
print sys.path
添加默认的搜索路径到列表最后;
sys.path.append(‘/home/kiosk’)
print sys.path
添加默认的搜索路径到列表最前面;
sys.path.insert(0, ‘/home/kiosk/Desktop’)
print sys.path
3.导入模块
- 建议优先使用第一种方式;
- import 模块名
import add
print add.a
print add.add(1,2,3,4)
2.
from 模块名 import 变量名
from 模块名 import 函数名
from add import a
from add import add
print a
print add(1,2,3,4)
- 不建议使用, 会导致命名空间的污染;
from add import *
b = 10
print a
print add(1,2,3)
print b
导入模块的过程就是加载模块吗内容并执行的过程;
import add
如果不同的人编写的模块名相同怎么办?
为了避免模块名冲突,Python 又引入了按目录来组织模块的方法,称为包(Package)包
创建包的步骤:
创建一目录为包名;
在该文件夹下创建init.py文件存放包的信息,该文件
可以为空;
根据需要存放脚本文件,已编译的扩展及子包;
可以用import,import as,from import等语句导入模块
和包;
五:文件操作
文件读写
• Python 内置了读写文件的函数,用法和 C 是兼容的。 • 操作系统不允许普通的程序直接操作磁盘,所以,读写文件就是请求操
作系统打开一个文件对象(又称文件描述符),然后,通过操作系统提供的接 口从这个文件对象操作;
1)打开文件
f = open(‘/root/hello’)
print f #f是文件对象
如果文件不存在, open() 函数就会抛出一个 IOError 的错误,并且
给出错误码和详细的信息告诉你文件不存在;
2)阅读模式
f.read()
如果文件打开成功,接下来,调用 read() 方法可以一次读取文件的
全部内容;
3)关闭文件
f.close()
文件使用完毕后必须关闭,因为文件对象会占用操作系统的资源。
读取文件的一行内容, 以字符串返回;
print f.readline()
print f.readline()
print f.readline()
读取文件每一行内容, 以列表方式返回;
print f.readlines()
print f.write(‘hello’)
文件对象是可迭代的, 如果只是几百兆的文件直接read方法读取;
如果xG文件, 建议使用for循环遍历, 底层是迭代器, 节省内存;
# for i in f:
# print i.rstrip()
• 二进制文件
要读取二进制文件,比如图片、视频等等,用 ‘rb’ 模式打开文件即可
f = open(‘/root/test.jpg’, ‘rb’)
f.read()
‘\xff\xd8\xff\xe1\x00\x18Exif\x00\x00…’ # 十六进制表示的字节
open函数的模式
r 以读的方式打开,定位到文件开头 , 默认的 mode
r+ 以读写的方式打开,定位文件开头 , 可以写入内容到文件
w 以写的方式打开,打开文件的时候会清空文件的内容,并且不能读
w+ 以读写的方式打开,定位到文件头,并且打开文件的时候也会清空文件的内容
a 以写的方式打开,定位到文件的末尾,是一个追加的操作 , 但并不允许读
a+ 以读写的方式打开,定位到文件的末尾,追加的方式。
在使用以上 mode 打开文件的时候,如果增加了b 模式,表示以二进制方式打开
文件的其它操作
- f.flush()函数,将缓冲区的内容写入到硬盘中
- f.seek(offset[,whence]),offset 表示移动多少字节, whence 为 1 的时候表
示相对于当前位置移动的;当 2 的时候从文件的末尾往后移动,但不一定所有 的平台都支持;默认为 0 表示从文件开头往后移动 - f.tell()函数,返回当前文件指针的偏移量:文件的其它操作
- fileno() 函数,返回当前的文件描述符,一个数字
- isatty() 函数,当前打开的文件是否是一个终端设备
- closed 属性,当前文件是否关闭 ,|True,False, f.closed
- file 对象是一个迭代器:
- next() 方法 , 一行一行的读 , 每次读取一行
with语法
一般情况打开一个文件,经过操作之后,都要显式的执行xx.close() 将文件关
闭 .with 用于需要打开、关闭成对的操作,可以自动关闭打开对象 .
with expression as obj:# 将打开的对象赋值给 obj
expression
obj 的作用域只在 with 语句中
with语句会在代码块执行结束自动关闭文件对象;
with open('/etc/passwd') as f:
f.read()
print "in with:", f.closed
print "out with:", f.closed