装饰器,生成器,迭代器,内置函数,软件目录
装饰器(也叫语法糖)
- 定义:装饰器本质是函数,用于装饰其他函数,为其他函数添加附加功能。
- 原则:1.不能修改被装饰函数的源代码;2.不能修改被修改函数的调用方式
- 知识储备:1.函数即变量;2.高阶函数;3.嵌套函数;4.高阶函数+嵌套函数+闭包=装饰器
- 自己写一个装饰器:
无参数装饰器
import time
def timer(func):#装饰器函数
def deco(*args,**kwargs):#传入可变长参数,适应不同函数
start_time = time.time()
res = func(*args,**kwargs)#将参数传给原有函数
stop_time = time.time()
print("the func run time is %s" %(stop_time - start_time))
return res#将原有函数的结果进行返回
return deco
def test_1(name):#原有函数
time.sleep(1)
print("%s in the test_1" %(name))
test_1 = timer(test_1)
test_1("zzh") #实际上在执行deco(),但表面上未改变test1的调用方式
###################################
#将写法改为@写法,则变成装饰器
@timer #其中,@timer就等效于test_1 = timer(test_1) = deco的写法
test_1("zzh")
### 结果:zzh in the test_1
### the func run time is 1.0000958442687988
有参数装饰器
import time
def timer(timeout=0):
def decorator(func):
def wrapper(*args,**kwargs):
start=time.time()
func(*args,**kwargs)
stop=time.time()
print 'run time is %s ' %(stop-start)
print timeout
return wrapper
return decorator
@timer(2)#test = timer(2)传入参数并返回decorate
def test(list_test):
for i in list_test:
time.sleep(0.1)
print '-'*20,i
#timer(timeout=10)(test)(range(10))
test(range(10))
生成器(generator)
- 通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。
- 所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器:generator。 即定义了一种迭代规则,但是未生成存储在内存中。
生成器定义:
- 方法一:只要把一个列表生成式的[]改成(),就创建了一个generator:
g = (x*x for x in range(10))#<generator object <genexpr> at 0x1022ef630>
- 方法二:
def fib(max):#定义生成器
n,a,b = 0,0,1
while n<max:
yield b #只要把原有输出改成yield就成生成器了
a,b = b ,a+b
n = n+1
return 'done'
g=fib(10)#g即是一个定义好的生成器
生成器迭代:
- 生成器只有在调用时才会生成,相应的,若需要取下一个,只能一个一个按顺序进行迭代才可获取。
- 生成器可使用
for num in g:
或者g.__next__()
或者next(g)
的函数进行迭代生成 - 生成器向后迭代:
g.__next__()
#生成器只能使用next方法不断向后迭代,且不可前溯。当生成器中无法再取出数据时,会向外抛出一个异常。通过抓住异常,即可判断结束。 - 进行异常处理代码:
while True: #死循环
try: #尝试下列代码
x = next(g) #获取迭代器的下一个值
print('g:',x) #打印该值
except StopIteration as e: #如果出现Stoplteration的异常时
print('Generator return value:',e.value) #打印异常和返回值
break
- 生成器send方法:
def consumer(name):#定义一个装饰器
print("%s 准备吃包子啦!" %name)
while True:
baozi = yield #当遇到yield,暂停并跳出
print("包子[%s]来了,被[%s]吃了!" %(baozi,name))
zzh = consumer("zzh")
zzh.__next__()
zzh.send("韭菜馅")##send调用yield,并给他传值
zzh 准备吃包子啦!
包子[韭菜馅]来了,被[zzh]吃了!
迭代器
- 可以直接作用于for循环的数据类型有以下几种:1.集合数据类型,如list、tuple、dict、set、str等;2.generator,包括生成器和带yield的generator function。这些可以直接作用于for循环的对象统称为__可迭代对象:Iterable__。
- 可以使用isinstance()判断一个对象是否是Iterable对象。
from collections import Iterable#导入的是Iterable
isinstance([], Iterable) ##注意这里是 Iterable,判断是不是可迭代对象
###True
- 可以被next()函数调用并不断返回下一个值的对象称为__迭代器:Iterator__。
- 可以使用isinstance()判断一个对象是否是Iterator对象:
from collections import Iterator#导入的是Iterator
isinstance((x for x in range(10)), Iterator) ##注意这里是 Iterator,判断是不是迭代器对象
###True
- 生成器对象都是可迭代对象,但如list、dict、str等是可迭代对象却不是生成器对象
- 可以使用iter()函数把list、dict、str等Iterable变成Iterator。如:
isinstance(iter('abc'), Iterator)
#True
内置方法
内置参数详解 :
https://docs.python.org/3/library/functions.html?
abs(x)
或x.__abs__()
:#取绝对值all(iterable)
:如果列表中所有元素均为真,返回真;只要有一个为假,返回假any(iterable)
:如果列表中有任何一个元素为真,返回真;全为假,则返回假,空列表也为假ascii(iterable)
:将元素转换为对应的ASCII码bin(x)
:将填入的十进制数转为二进制bool(x)
:判断填入的bool值是否为真bytes("abcde",encoding = 'utf-8')
:将字符串用utf-8编码,转为byte类型,且不可修改b=bytearray("abcde",encoding = 'utf-8')
:将字符串用utf-8编码,转为byte类型,但是可以修改其元素,如b[1]=100
修改第二个元素的字符callable(iterable)
:判断一个元素是否是可调用的cha(98)
:查询对应ASCII的字符‘b’ord('b')
:查询字符对应的ASCII码 #98dict(**kwarg)
:生成一个字典dir([object])
:查询对象具有哪些可用的方法divmod(5,2)
:整数除法取余,返回商和余数,#(2,1)list(enumerate(['one','two','three']))
:返回一个可迭代对象(如序列)的下标和元素的元组#[(0, 'one'), (1, 'two'), (2, 'three')]eval('1+2')
:把一个字符串变成一个字典,返回值是求表达式的结果#3exec("print('hello')")
:将字符串变成代码进行编译运行 #hellofilter(lambda n : n>5 , range(10))
:#能够从一组数据中过滤出一些想要的数据来map(lambda n : n*n , range(10))
:对输入的值按照用户要求进行处理,再覆盖掉原来的值。等效于[i*i for i in range(10)]
print("I am {name}".format(name = "zzh"))
:格式化输出frozenset([1,2,3,4])
:将集合(如列表)变成一个不可变集合print(globals())
:返回当前程序中的所有变量,以字典形式返回,变量名和值hash(object)
:计算一个对象的哈希值hex(12)
:将数据转化为十六进制#0xcinput("name:")
:标准输入,括弧中为提示信息len(s)
:获取对象的长度print(locals())
:打印函数内部的局部变量max([1,2,3,4,5])
:返回列表中的最大值min([1,2,3,4,5])
:返回列表中的最小值next()
:生成器的调用方法oct(12)
:十进制转八进制#0o14pow(3,3)
:求幂,3的3次幂=27print("I am zzh")
:将对象打印到文本流文件中range(1,10,2)
:输出一个序列(开始,停止,步长)reversed(seq)
:反转一个可迭代对象,如反转一个数组round(1.3342 , 2)
:保留两位小数 #1.33slice(2,5,1)
:切片,从2切到5,步长为1sorted(iterable)
:对iterate中的项目进行排序并返回一个新的列表sum()
:从左到右开始,计算数据的总和type()
:查看对象的数据类型print(zip([1,2,3],['a','b','c']))
:对于元素进行拼接__import__("模块名")
:导入模块,模块名为字符串,等效于import 模块名
软件目录规划
假设你的项目名为foo
Foo/
|-- bin/
| |-- foo
|
|-- foo/
| |-- tests/
| | |-- __init__.py
| | |-- test_main.py
| |
| |-- __init__.py
| |-- main.py
|
|-- docs/
| |-- conf.py
| |-- abc.rst
|
|-- setup.py
|-- requirements.txt
|-- README
- bin/: 存放项目的一些可执行文件,当然你可以起名script/之类的也行。
- foo/: 存放项目的所有源代码。(1) 源代码中的所有模块、包都应该放在此目录。不要置于顶层目录。(2) 其子目录tests/存放单元测试代码; (3) 程序的入口最好命名为main.py。
- docs/: 存放一些文档。
- setup.py: 安装、部署、打包的脚本。
- requirements.txt: 存放软件依赖的外部Python包列表。
- README: 项目说明文件。
- 如果我是一个包下的foo.py,如何通过代码去调用另一个路径下的main.py,例子如下:
import os,sys
print(__file__)#获得当前文件的相对路径
print(os.path.abspath(__file__))#通过相对路径获得绝对路径
print(os.path.dirname(os.path.abspath(__file__)))#以当前绝对路径向上退一级
#再向上一级获得整个文件即Foo的绝对路径,并进行存储
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(BASE_DIR)#将文件目录加入到环境变量中
import foo#再引用foo包,则不会出现报错
参考:
https://blog.51cto.com/egon09/1836763
https://www.cnblogs.com/alex3714/articles/5765046.html