s14 第4天 关于python3.0编码 函数式编程 装饰器 列表生成式 生成器 内置方法

python3 编码默认为unicode,unicode和utf-8都是默认支持中文的。python

 

若是要python3的编码改成utf-8,则或者在一开始就声明全局使用utf-8算法

 

#_*_coding:utf-8_*_编程

 

或者将字符串单独声明:app

 

a = "中文".encode("utf-8")ssh

 

 

 

函数式编程函数式编程

 

函数式编程中的函数指代的是数学中的函数。函数

 

函数式编程输入若是肯定,则输出必定是肯定的。函数中并无不少逻辑运算工具

 

python是一个面向对象的语言,只是一部分支持函数式编程。编码

 

 

装饰器:spa

 

定义:本质是一个函数,装饰其余函数,为其余函数增长附加功能

 

原则:

一、不能修改被装饰的函数的源代码

二、不能修改被装饰的函数的调用方式

 

实现装饰器的知识准备:

一、函数即"变量"

定义函数的过程实际是将函数体以字符串的形式保存进内存的过程,当函数()时才是调用执行函数。

所以函数的定义:

def 函数名():

  函数体

 

实际等价于

 

函数名= “函数体”

 

所以函数名就是一个变量名。

 

能够做为一个参数传递给另外一个函数

 

二、高阶函数

 

a:把一个函数名当作实际参数传递给另外一个函数

能够在不修改函数的源代码的状况下实现新功能

 

def bar():

    print("in the bar")

 

def new_func(func):

    print("new_func")

    func()

    print("after")

 

原来调用:bar()

新功能调用为:new_func(bar) ,就增长新功能了,可是改变了原函数的调用方法

 

b:返回值中包含函数名

不修改原函数的调用方式状况下实现新功能

def bar():

    print("in the bar")

 

def new_func(func):

    print("new_func")

    func()

    print("after")

    return func

bar = new_func(bar)

bar()     # 为改变原函数的调用方式

 

返回结果

new_func   # new_func功能

in the bar # new_func功能

after # new_func功能

in the bar # bar功能

 

 

 

 

三、嵌套函数

在一个函数的函数体内用def去定义一个新函数

 

高阶函数+嵌套函数 => 装饰器

 

装饰器的写法:

 

一、普通装饰器

 

def bar():

    print("in the bar")

 

def test(func):

    def  new_func():

    print("new_func")

    func()

    print("after")

    return new_func

 

 

@test

bar()  

 

二、装饰器传递参数:

 

def bar():

    print("in the bar")

 

def test(func)

    def new_func(*args,**kwargs):

        print("new_func")

        func(*args,**kwargs)

        print("after")

    return new_func

 

 

@test

bar("liubo",30)

 

 

三、装饰器带参数,便可以在装饰器内作一些判断:

 

 

import time

 

 

def decorator(type):

    def outer(func):

        if type=="1":

            definner(*args,**kwargs):

                start_time=time.time()

                ret=func(*args,**kwargs)

                stop_time=time.time()

                print("func running time is %s" % (stop_time-start_time))

                return ret

            return inner

        else:

            def inner(*args,**kwargs):

                print("your input is wrong")

            return inner

    return outer

 

 

print("请输入type:")

type=input(">>>")

 

 

@decorator(type)

def f1(name,age):

    time.sleep(3)

    print("your name is{},age is{}".format(name,age))

 

 

f1("liubo",30)

 

 

 

列表生成式

 

a = [i*2 for i in range(10)]

 

生成的a为

 

[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

 

改列表生成器等价于

 

a = []

 

for i in range(10):

    a.append(i*2)

 

print(a)

 

列表生成器可使代码很简洁,任何针对i的for循环均可以写为[i的处理 for循环]的格式

 

当连续调用2次列表生成器对同一个列表时,结果并不会叠加2次的数据,而是第二次的数据会覆盖第一次的数据

 

a = [i*2 for i in range(10)]

a = [i*3 for i in range(10)]

print(a)

 

结果

 

[0, 3, 6, 9, 12, 15, 18, 21, 24, 27]

 

 

生成器:

若是执行一个循环的结果很是巨大,而咱们只用其中一部份内容,那么多余的数据就是无用的。所以咱们须要一种工具在执行循环时,每次循环生成一个数据,而以前的数据会释放,然后面的数据并无生成,不会占地方。这种工具就是生成器。

 

上面提到的列表生成式,实际就是在生成时就将列表里的元素所有加载进内存的。

 

若是:(i*2 for i in range(10)),这样就变成了一个生成器,当输入这个命令时,内存中并无生成任何元素,只是增长了一个生成器

 

所以获取生成器中的元素就不能用相似列表的切片的方式获取。

 

生成器只有在调用时才会生成相应的数据,调用可使用for循环来生成,也可使用__next__()方法获取下一个元素。而生成器只有调用时保留当前值,所以生成器没法取上一个值。实际for循环就是在for内部反复的调用next方法

 

 

如何生成一个生成器?

 

一个裴波那契数列的生成器:

 

def fib(max):

    n,a,b = 0,0,1

    while n < max:

        yield b

        a,b = b,a+b

        n+=1

    return "---done----"

 

f = fib(10) # 建立生成器
 

此时f就是一个生成器,那么我要应用这个函数中元素就须要使用next的方式调用。

 

print(f.__next__())

print(f.__next__())

print(f.__next__())

 

从上面的例子咱们能够看到,生成器就是在函数中出现了yield关键字的函数,当函数运行时,遇到yield函数会暂停,而且返回yield后面的值,这样每次咱们调用__next__()方法时,程序都会返回当前运行的结果。而return的内容就是异常时产生的消息

 

生成器的好处

 

一、节约内存外

二、能够中断数据的生成去作其余的事,而后再返回到生成器中

 

print(f.__next__())

print("....") # 中断生成器

print(f.__next__()) # 再次进入生成器

print("xxx") #再次中断生成器

print(f.__next__())

 

 

经过__next__()方法,当超过了生成器的元素数量时,就会以异常结束,异常的提示就是程序最后返回的值

 

StopIteration: ----done----        # 异常

 

那么若是须要避免这个异常,则须要将异常抓出

 

g = fib(6)

while True:

    try:  # 若是正常,则尝试循环

        x = next(g)

        print("g:",x)

    except StopIteration as e:    # 若是出现了StopIteration ,则按下面执行

        print("Generator retrun value:",e.value)  # e.value就是出错的返回值,此处为"---done----"

        break

 

调用一个生成器

 

def f1():

    x = 0

    while x < 10:

        yield x  # 第一次调用next会生成0

        x += 1 # 第二次next会先加1 而后输出1

 

f2 = f1()    # 首先定义f2,调用f1函数。此时至关于从f2进入了f1函数

print(f2.__next__())  # 以后的每次调用都是从f2 = f1()这里进入的,所以会依次输出0-4

print(f2.__next__())

print(f2.__next__())

print(f2.__next__())

print(f2.__next__())

 

 

若是以下

 

print(f1().__next__())  # 这样至关于每次都是从f1重新进入,所以每次输出都是0。由于每次都是从新调用函数

print(f1().__next__())

print(f1().__next__())

print(f1().__next__())

print(f1().__next__())

 

 

 

在调用生成器的函数中,除了next方法,还有一个send方法。

 

next方法仅仅是唤醒生成器的yield,让他开始生成元素,可是若是yield没有返回值,则返回值为None。

 

send方法唤醒yield,同时给yield传递值。

 

例如

 

在生成器函数中

 

baozi = yield

 

上面这个函数,取一个变量等于yield,程序 运行到此会暂停,可是yield为空,所以若是我用next方法下面调用baozi这个变量,值为空。

 

可是若是我在调用send方法,则这个值就会被send发送进来。

 

def cus(name)

    print("%s 开始吃包子" % name)

    baozi = yield # 包子赋值给yield,可是并无返回值,这里的做用是停下来同时接收send的值给baozi

    print("%s 的包子已经被我吃了" % baozi) # 此处却须要调用baozi这个变量。

 

那么若是我须要baozi这个变量有值,就须要这样调用:

 

c = cus("liubo")  # 建立生成器并命名为c

 

c.__next__() # 首先要让生成器运行到yield。

 

c.send("韭菜馅") # 调用send方法,将"韭菜馅"这个字符串传递给yield,并向下执行

 

生成器单线程的并行效果 执行案例

 

import time

def cus(name):

    print("%s 开始吃包子" % name)

    while True:

        baozi = yield # 包子赋值给yield,可是并无返回值

        print("{}:{} 个包子已经被我吃了".format(name,baozi)) # 此处却须要调用baozi这个变量。

 

def producer(name):

    c1 = cus("c1") # 建立生成器

    c2 = cus("c2")

    c1.__next__() # 让生成器执行到yield,同时也打印cus函数的第一句话,表明c1已准备好

    c2.__next__()

    for i in range(1,4):

 

        time.sleep(1)

        print("{}:我作了2个包子".format(name))

        time.sleep(1)

        c1.send(i) # 将i传递给c1,i将会被传递给baozi变量以便打印

 

        time.sleep(1)

        c2.send(i)

 

producer("liubo")

 

上述程序,将使一个厨师和两个食客三个程序同时运行(但实际是串行的)

 

 

 

迭代器

 

可直接做用于for循环的数据类型:

 

一、集合数据类型,例如list,tuple,dict,set,str等

二、生成器,包括带yield的生成器

 

能够直接做用于for循环的对象统称为可迭代对象,Iterable

 

能够被__next__()函数调用并不断返回下一个值的对象统称为迭代器 Iterator

 

可使用isinstance(),判断一个对象是否为Iterable对象

 

form collections import Iterator

 

isinstance((x for x in range(10)),Iterator) # isinstance(对象,类型) 判断对象是否为特定类型

 

可迭代对象不必定是迭代器(list,tuple,dict),可是可使用iter()函数将其变为迭代器

 

a = [11,22,33] # 可迭代对象 不是迭代器

 

b = iter(a) # 就是一个迭代器了,能够用b.__next__()调用下一个元素

 

 

迭代器在python表明一个数据流,是一个惰性运算,即只有当用到这个值时才生成这个值,所以迭代器能够表明一个无穷大的序列。

 

可迭代对象在建立之初即须要建立全部的元素,迭代器的长度是未知的,可是可迭代对象的长度倒是已知的。所以可迭代对象不能是迭代器,只能经过iter()函数转换。

 

 

内置方法

 

内置方法

功能

案例

 

abs(x)

取一个数的绝对值

 

 

all(iterable)

若是可迭代对象中的全部元素都是True,则返回镇;不然返回False

print(all([0,1,-3]))
    返回为False,由于0非真,若是print(all[1,2,3])),则返回真,由于全部元素都为真

 

any(iterable)

若是可迭代对象中有一个元素为真,则返回真。与all相对

 

 

ascii(object)

将一个对象在acsii中的对应打印出来

 

 

不经常使用

bin(x)

将一个十进制转换为二进制

bin(255)

输出0b11111111

 

bool(x)

返回一个值的真假,空和0都为假

 

 

bytearray(str,encoding)

默认状况下,字符串和二进制类型都是不容许修改的,可是bytearray是能够修改的

b =   bytearray("abcde",encoding ="utf-8")
    b[1] = 50

print(b)

输出:a2cde,在这里第二个元素b就被替换为acsii表中第50个元素了。在这种状况下我使用b[1]的方式获取的并不是b,而是b在ascii中对应的序号。

 

可是若是直接用b =   byte("abcde",encoding   ="utf-8"),则针对某个元素的修改实际都是新建这个列表或字符串,而不是在原来的基础上修改

不经常使用

callable()

判断一个对象是否能够调用,即对象是否能够在最后加()

def   test:pass

print(callable(test))

 

输出 True

 

chr(i)

输入一个数字,返回acsii表中对应的元素

char(97)

输出"a"

 

ord()

输入一个元素,返回ascii表中对应的序号

ord("a")

输出97

 

classmethod(func)

 

 

 

compile

(code,"文件名",执行方式)

将一个字符串编译为能够被python执行的语句(此时仍未执行)。

其中code是被编译的字符串,文件名是当出错时日志输出的位置,执行方式是但愿被那个命令执行

code = "for i in   range(10)"

c =   complie(code,"","exec")

exec(c)

输出,执行code的代码。此处使用的exec执行命令

 

dict()

生成一个字典

 

 

dir()

能够查询对象的内部方法

dir([])

输出列表的方法

['__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_e

x__', '__repr__',   '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__s

izeof__',   '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'ex

tend', 'index',   'insert', 'pop', 'remove', 'reverse', 'sort']

其中__的是内部方法不可用

 

divmod(a,b)

a和b相除与商和余数

x,y =   divmod(5,2)

print("x=",x)

print("y=",y)

 

输出:

x=2

y=1

 

2为商,1为余数

 

enumerate(iterable,start=0)

将一个可迭代对象序列化,开始的序列为start=中定义的。将可迭代对象中每一个元素与其序号单独造成一个新的元组。每一个元组就能够分片获取。start若是不写,默认从0开始

li = [11,22,33]

for i in enumerate(li,start=1):

    print(i)

 

输出:

(1, 11)

(2, 22)

(3, 33)

 

 

eval(表达式,globals=None,locals=None)

eval()用来将字符串编译为表达式,例如    s = "8*8"  r = eval(s)   , print(r)的时候会返回为64,eval只能执行表达式,eval有返回值,若是用eval(“7+8+9”),是能返回结果的,这点比exec强,对比exec。

x=1

eveal("x+1")

 

输出

 

2

 

exec(object)

exec() 用来执行编译后的代码,和complie何用,先用complie编译,而后用exec执行。exec能够执行全部的python的命令,exec只是执行没有返回值,所以用exec运行一个表达式,是拿不到结果的,例如exec(“7+8+9”),只是执行可是结果是拿不到的。在执行代码的时候exec能够接受代码或者字符串。

 

 

filter(func,iterable)

将可迭代对象的每一个函数带入func中,生成一个迭代器,迭代的元素时func中返回为真的值

def   func1(a):

    if a>22:

        retrun True

b =   filter(func1,[11,22,33,44])

for i   in b:

    print(i)

返回

33

44

 

此处也能够直接跟lambda函数

 

for i   in filter(lambda x : x>22,[11,22,33,44]):

    print(i)

 

返回

33

44

 

 

map(func,iterable)

和filter对比,filter方法将返回为真的值生成新的迭代器。

而map方法则将返回值迭代。

for i   in map(lambda x:x>22,[11,22,33,44])

    print(i)

 

返回

 

False

False

True

True

 

固然就是说map会将func的结果直接返回,若是

for i in map(lambda n : n*2,[11,22,33]):

    print(i)

 

返回

22

44

66

 

import functools
    functools.reduce(func,iterable)

是一个二元操做函数,他用来将一个数据集合(链表,元组等)中的全部数据进行下列操做:用传给reduce中的函数   func()(必须是一个二元操做函数)先对集合中的第1,2个数据进行操做,获得的结果再与第三个数据用func()函数运算,最后获得一个结果。

 

 

import   functools

res =   functools.reduce(lambda x,y:x*y,range(1,10))

print(res)

 

上面的函数的结果就是1*2*3*4.....*9。

如描述里面的func必须是一个二元操做的,那么这里的两个变量就会首先从后面的可迭代对象中取前两个,而后按照要求返回,以后会将返回值与下一个对象操做,知道可迭代对象中全部的元素都被处理。

 

frozenset()

将一个集合变成不可修改的集合。

a = set([])

此时的a能够有pop,clear等方法能够修改这个集合

 

可是若是用 a =   frozenset()

a就不在有这些方法了

 

 

globals()

以字典的形式当前整个代码中的全部变量

 

 

hash()

将一个特定对象进行哈希算法

 

 

hex()

将数字转为十六进制

 

 

locals()

以字典形式打印当前代码中的所有的局部变量

 

 

max()

返回可迭代对象中的最大值

 

 

min()

返回最小值

 

 

next()

从迭代器中返回下一个item

 

 

oct()

将一个数字转为八进制

 

 

pow(x,y)

打印x的y次方的结果

 

 

round(x,y)

x是一个浮点数,y则为保留小数点后多少位,默认y为0即不显示小数,结果会四舍五入

round(1.2323,2)

输出

1.23

 

sorted(排序内容,key="排序依据8")

排序,只能排序int类型的数字。若是排序字典则字典的key必须是int类型

能够将字典排序

a =   {1:11,2:22,5:55,3:33,4:44}

print(sorted(a))

输出会将key排序输出

[1, 2, 3, 4, 5]

 

print(sorted(a.items()))

 

字典.items()这个方法自己会将字典转为元组

输出结果为

按照字典key排序,并将字典的键值对变为元组

[(1, 11), (2, 22),   (3, 33), (4, 44), (5, 55)]

 

若是要按照字典的值排序

print(sort(a.items(),key=lambda   x:x[1]))

 

其中,a.items()会将字典的键值对变为元组,每一个元组的[0]是键,[1]是值

lambda x:x[1] 是将这个元组带入函数,并返回[1]角标即字典的值,

key = lambda x : x[1]表明以字典的值为排序依据

 

返回结果

[(1, 11), (2, 22),   (3, 33), (4, 44), (5, 55)]

 

以值排序,key能够不是int类型

 

a = {"zhangsan":11,"lisi":22,5:55,3:33,4:44}

print(sorted(a.items(),key=lambdax:x[1]))

 

返回结果

 

[('zhangsan', 11),   ('lisi', 22), (3, 33), (4, 44), (5, 55)]

 

sum()

输入列表,将列表求和

 

 

zip(列表a,列表b)

将两个列表的元素一一对应,取列表中元素最少的拼接

 

 

__import__()

正常的import导入模块时后面模块名是一个变量。可是若是模块名是一个字符串,就不能用import。所以须要__import__()

__import__("decorator")

 

 

 

匿名函数

 

函数的目的是为了重复调用,为此创建函数在内存中占用空间,可是若是这个函数仅调用一次这个占用的空间就被浪费了。所以引出了匿名函数。

 

lambda函数即匿名函数,由于这个函数并未像其余函数同样经过def func()的方式建立了一个func的函数,他并无建立函数名,所以当还行一次后就没有对应的变量与之关联,其占用的内存空间也就会被回收。

 

def func(n):
    print(n)

这个函数的lambda写法为

 

lambda n:print(n)

 

执行时能够

 

(lambda n:print(n))(5)

 

a = lambda n : print(n)

a(5)

 

A = lambda n:print(n) # 这里的A是一个函数

A = (lambda n : print(n))(5) # 这里的A是匿名函数的结果,传递了n = 5给匿名函数后的return

 

 

可是lambda只能执行简单的操做,好比三元运算

 

a = lambda n : print("n<3") if n<3 else print("n>3") # 至关于return 返回了一个三目运算

a(5)

 

 

 

软件目录开发规范

 

 

 

 

os.path.dirname()

获取当前目录的上级目录名

os.path.abspath(__file__)

获取当前文件的绝对路径

sys.path.append()

追加环境变量的路径

 

所以若是一个文件的绝对路径为:E:\Atm\bin\atm.py,我须要将E:\Atm路径追加到python模块调用的环境变量中,那么须要这样写

 

base = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

sys.path.append(base)

相关文章
相关标签/搜索