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)

相關文章
相關標籤/搜索