萬惡之源 - Python裝飾器及內置函數

裝飾器

聽名字應該知道這是一個裝飾的東西,咱們今天就來說解一下裝飾器,有的鐵子們應該據說,有的沒有據說過.沒有關係我告訴大家這是一個很神奇的東西python

這個有多神奇呢? 咱們先來複習一下閉包算法

def func1():
​
    name = "alex"
​
    def func2():
​
        print(name)
​
        # 閉包
​
    func2()
​
func1()

  

這就是閉包,那剛剛說的很神奇的東西呢?,爲何又說閉包了呢? 機智的鐵子們已經猜到,裝飾器和閉包是有點關係的,是滴沒錯.數組

那什麼是裝飾器呢?裝飾器是幹什麼的呢?數據結構

裝飾器的本質其實就是閉包閉包

如今你在公司,領導讓你寫一個函數,來測試另外一個函數的執行效率,你怎麼作?ssh

我先告訴你們一個查看時間的東西函數

time.time() 獲取都是一個字符串

咱們能夠經過這個來計算執行時間工具

def func():
    print('嘻嘻更健康')
import time
start_time = time.time()
time.sleep(0.1)
func()
end_time = time.time()
print('----> 執行效率%s'%(end_time - start_time))

上面你已經寫完了,可是你應該放在函數中,這樣減小重複代碼,可讀性好,ok繼續作。學習

def func():
    print('嘻嘻更健康')
def timmer(f):
    start_time = time.time()
    time.sleep(0.1)
    f()
    end_time = time.time()
    print('----> 執行效率%s'%(end_time - start_time))

好你又寫完了,可是執行以前的函數只是func(),而你寫玩了這個以後,還得加一步timmer(func),若是要是領導讓你測試500個函數的執行效率呢?好,你又進一步改,以下測試

func()
f1 = func  # func
func = timmer  # timmer
func(f1)
將他的執行結果改了一下,這樣看似func(f1)與原來的調用差很少,可是加了好幾步,並且添加了f1參數。。。

如今你請教了我,我說來,寫個裝飾器就能解決。

def timmer(f):
    def inner():
        start_time = time.time()
        time.sleep(0.1)
        f()
        end_time = time.time()
        print('----> 執行效率%s' % (end_time - start_time))
    return inner
func = timmer(func)  # inner
func() # inner()

這樣,就寫好了,這是最簡單的裝飾器,裝飾任何函數,只須要加一句func = timmer(func)

#簡單的裝飾器
def func():
    print('嘻嘻更健康')
def timmer(f):
    def inner():
        start_time = time.time()
        time.sleep(0.1)
        f()
        end_time = time.time()
        print('----> 執行效率%s' % (end_time - start_time))
    return inner
func = timmer(func)  # inner
func() # inner()

可是Python認爲你這個仍是不簡單,因此Python給你提供了一個更見的方式就是語法糖。

#語法糖 @  
​
def timmer(f):
​
    def inner():
​
        start_time = time.time()
​
        time.sleep(0.1)
​
        f()
​
        end_time = time.time()
​
        print('----> 執行效率%s' % (end_time - start_time))
​
    return inner
​
@timmer  # func = timmer(func) 
語法糖的用意

@裝飾器函數 == 從新定義被裝飾函數=裝飾器函數(被裝飾函數)

def func():
    print('嘻嘻更健康')
func() # inner()

內置函數(下午講解)

什麼是內置函數?就是python幫咱們提供的一個工具,拿過直接用就行,好比咱們的print,input,type,id等等.截止到python3.6.2版本

中一共提供了68個內置函數.他們就是python直接提供給咱們的,有一些咱們已經用過了.有一些尚未用過.還有一咱們須要學完面向對象才能繼續學習.今天咱們認識一下python的內置函數

做用域相關

  locals() 返回當前做用域中的名字

  globals() 返回全局做用域中的名字

迭代器相關

  range() 生成數據

  next() 迭代器向下執行一次,內部實際使用了next()方法返回迭代器的下一個項目

  iter() 獲取迭代器,內部實際使用的是iter()方法來獲取迭代器

字符串類型代碼的執行

eval() 執行字符串類型的代碼,並返回最終結果

print(eval('2+8'))
結果:
10
​
n = 8
print(eval('n + 10'))
結果:
18

exec() 執行字符串類型的代碼 

exec('''
for i in range(10):
    print(i)
''')
​
# 咱們按照python可以識別的語法寫代碼,此次寫入的是字符串也能夠執行
​
​
exec(''' 
​
def func():
    print("444")
​
func()    
​
''')
​
結果:
444  

經過上邊的測試發現,只要是exec就沒有返回值,eval就是有返回值的 

輸入和輸出相關

  input() 獲取用戶輸入的內容

  print() 打印 輸出

print裏的sep

print('alex','wusir','baoyuan')
print('alex','wusir','baoyuan',sep='|')
​
# 結果:
# alex wusir baoyuan
# alex|wusir|baoyuan
​
print默認sep是一個空格,我們打印出來的是以空格分開的,咱們修改了sep打印出來的就是以管道符分開的

print裏的end

print('alex')
print('alex')
print('alex')
# 結果:
# alex
# alex
# alex
​
​
print('alex',end='')
print('alex',end='')
print('alex',end='')
# 結果:
# alexalexalex
print 默認end是一個\n,打印出來的效果是有換行功能,我們改爲空字符串,打印出來的效果就是一行顯示

內存相關

  hash() 獲取對象的哈希值(int.str,bool,tuple)

print(hash((1,2,4)))
print(hash('你好'))
print(hash(111))
print(hash(False))

  id() 獲取到對象的內存地址

name = 'alex'
print(id(name))
​
結果:2376700908072

文件操做相關

  open() 用於打開一個文件,建立一個文件句柄

模塊相關

import() 導入,引入

import time
​
print(time.time())

幫助

  help() 函數用於查看函數或模塊用途的詳細說明

help(input)
​
結果:
Help on built-in function input in module builtins:
​
input(prompt=None, /)
    Read a string from standard input.  The trailing newline is stripped.
    
    The prompt string, if given, is printed to standard output without a
    trailing newline before reading input.
    
    If the user hits EOF (*nix: Ctrl-D, Windows: Ctrl-Z+Return), raise EOFError.
    On *nix systems, readline is used if available.

調用相關

  callable() 用於檢查一個對象是不是可調用的,若是返回True,object有可能調用失敗,要是返回False,那調用絕對就完犢子

def func():
​
    pass
​
name = 'meet'
​
print(callable(func))  結果 True
print(callable(name))  結果 Fasle

查看內存屬性

  dir() 查看對象的內置屬性,方法,訪問的是對象的dir()方法

print(dir(input))
​
# 結果:
# ['__call__', '__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__name__', '__ne__', '__new__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__self__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__text_signature__']
基礎數據類型相關

數字相關:  

  bool() 將給定的數據轉換成bool值,若是不給值.返回False

print(bool())
結果:
False

  int() 將給定的數據轉換成int值,若是不給值,返回0

print(int())
結果:
0

 float() 將給定的數據轉換成float值,也就上次小數

print(float())
結果:
0.0

  compilex() 建立一個複數,第一個參數爲實部,第二個參數爲虛部.或者第一個參數直接用字符串來描述複數

print(complex(120))
結果:
120+0j

進制轉換:

  bin() 將給的參數轉換成二進制

  otc() 將給的參數轉換成八進制

  hex() 將給的參數轉換成十六進制

數字運算:

  abs() 求絕對值

print(abs(-100))
結果:
100  

  divmod() 返回商和餘數

print(divmod(20,6))
結果:
(3, 2)
第一個參數是商,第二參數是餘數

  round() 四捨五入

print(round(3.56))
結果:
4
print(round(3.56,1))
結果:
3.6
後邊的參數是指定小數點後邊的數字進行四捨五入,我們指定的數字要小於我們小時候點後邊的位數

  pow(a,b) 求a的b次冪,若是有個三次參數,則求萬次冪後對第三方個數取餘

print(pow(2,4))
結果:
16
print(pow(2,4,3))
結果:
1
三個參數 前來個參數是求2的3次冪,第三個參數是這個總和去除3而後獲取的是餘數

  sum() 求和

print(sum([1,2,3,4,5]))
結果:
15   參數必須是可迭代對象
  min() 求最小值

print(min([1,2,3,4,5]))
結果:
1    參數必須是可迭代對象

  max() 求最大值

print(max([1,2,3,4,5]))
結果:
5    參數必須是可迭代對象

數據結構相關

列表和元祖

  list() 將一個可迭代對象轉換成列表

  tuple() 將一個可迭代對象轉換成元祖

  reversed() 將一個序列反轉,返回反轉序列的迭代器

print(list(reversed('你好啊')))
結果:
['啊', '好', '你']

字符串相關:

  str() 將數據轉化成字符串

  format() 與具體數相關,用於計算各類小數,精算等

字符串

# 字符串
# print(format('meet','<20'))   #左對齊
# print(format('meet','>20'))   #右對齊
# print(format('meet','^20'))   #居中
​
結果:
meet                
                meet
        meet        

數值 本身練習

#數值
print(format(3,'b'))    # 二進制
print(format(97,'c'))   # 轉換成unicodezif
print(format(11,'d'))   #十進制
print(format(56))       #和d同樣
print(format(11,'n'))   #十進制
print(format(11,'o'))   #八進制
​
print(format(11,'x'))  # 十六進制(小寫字母)
print(format(11,'X'))  # 十六進制(大寫字母)
​
# 浮點數
​
print(format(1234567890,'e'))  #科學計算法,默認使用6位
print(format(123456789,'0.2e'))# 科學計算,保留2位小數(小寫)
print(format(123456789,'0.2E'))# 科學計算,保留2位小數(大寫)
print(format(1.23456789,'f')) #小數點計數法,保留6位小數
print(format(1.23456789,'0.2f')) # 小數點計數法,保留2位數
print(format(1.23456789,'0.10f')) # 小數點計數法,保留2位數
print(format(1.23456789e+1000,'F')) # 小數點計數法

bytes() 把字符串轉換成bytes類型

s = '你好武大'
​
bs = s.encode('utf-8')
print(bs)
​
結果:b'\xe4\xbd\xa0\xe5\xa5\xbd\xe6\xad\xa6\xe5\xa4\xa7'
​
s1 = bs.decode('utf-8')
print(s1)
​
結果: 你好武大
​
bs = bytes(s,encoding='utf-8')
print(bs)
​
結果: b'\xe4\xbd\xa0\xe5\xa5\xbd\xe6\xad\xa6\xe5\xa4\xa7'
把字符串編碼成utf-8

bytearray() 返回一個新字節數組,每一個元素的值的範圍是0~256對應的是ascii碼錶

ret = bytearray('meet',encoding='utf-8')
print(ret)
print(ret[0])
​
結果:
bytearray(b'meet')
109

memoryview() 查看bytes的內存地址

s = memoryview('麻花藤'.encode('utf-8'))
print(s)
​
# 結果:
# <memory at 0x000001F332E0E288>

ord() 輸入字符找帶字符編碼的位置

print(ord('a'))
print(ord('中'))
print(ord('國'))
​
結果:
97
20013
22269
​
對應的是當前編碼 

chr() 輸入位置數字找出對應的字符

print(chr(97))  # 找到對應位置的字符
print(chr(20013))  # 找到對應位置的字符
​
# 結果:
a
中

ascii() 是ascii碼中的返回值 不是就返回\u

print(ascii('a'))  判斷字符串在不在ascii碼錶中
print(ascii('中'))  
​
結果:
'a'
'\u4e2d'     若是不存在就返回\u...

repr() 返回一個對象本質的形式

name = 'alex'
print(repr(name))   #返回這個對象本質的表示形式
​
結果:
'alex'
​
name = '我叫%r'
print(name%'meet')   %r 用的就是repr
結果:
我叫'meet'

數據集合

  dict() 建立一個字典

d = dict(k='v',key1='v2')
print(d)
結果:
{'k': 'v', 'key1': 'v2'}

  set() 建立一個集合

s = set([1,2,4,5,6])
print(s)
結果:
{1, 2, 4, 5, 6}

其餘相關

  len() 返回一個對象的元素個數

  enumerate() 獲取枚舉對象

lst = ['alex','wusir','taibai']
​
for i,k in enumerate(lst):
    print('這是序號',i)
    print('這是元素',k)

all() 可迭代對象中所有是True,結果纔是True

lst = [1,2,3,4,True,0,False]
lst1 = [1,2,3,4,True]
print(all(lst))
​
print(all(lst1))
​
結果:
False
True

any() 可迭代對象中有一個是True,就是True 

lst = [1,2,3,4,True,0,False]
lst1 = [1,2,3,4,True]
print(any(lst))
​
print(any(lst1))
​
結果:
False
True

zip() 函數用於將可迭代的對象做爲參數,將對象中對應的元素打包成一個個元祖,

而後返回由這些元祖組成的內容,若是各個迭代器的元素個數不一致,則按照長度最短的返回

lst1 = [1,2,3]
lst2 = ['a','b','c','d']
lst3 = (11,12,13,14,15)
​
for i in zip(lst1,lst2,lst3):
    print(i)
​
結果:
(1, 'a', 11)
(2, 'b', 12)
(3, 'c', 13) 

lambda

匿名函數,爲了解決一些簡單的需求而設計的一句話函數

def func(n):
    return n**n
print(func(4))
 
f = lambda x: x**x
print(f(4))
 
結果:
256
256

lambda表示的是匿名函數,不須要用def來聲明,一句話就能夠聲明出一個函數

語法:

  函數名 = lambda 參數:返回值

注意:

  1.函數的參數能夠有多個,多個參數之間用逗號隔開

  2.匿名函數無論多複雜.只能寫一行.且邏輯結束後直接返回數據

  3.返回值和正常的函數同樣,能夠是任意數據類型,可是隻能一個,不能返回多個.

匿名函數並非說必定沒有名字,這裏前面的變量就是一個函數名,說他是匿名緣由是咱們經過

name查看的時候是沒有名字的.統一都叫作lambda.在調用的時候沒有什麼特別之處

像正常的函數調用既可

sorted

排序函數

語法:sorted(iterable,key=None,reverse=False)

iterable : 可迭代對象

key: 排序規則(排序函數),在sorted內部會將可迭代對象中的每個元素傳遞給這個函數的參數.根據函數運算的結果進行排序

reverse :是不是倒敘,True 倒敘 False 正序

lst = [1,3,2,5,4]
lst2 = sorted(lst)
print(lst)    #原列表不會改變
print(lst2)   #返回的新列表是通過排序的
 
 
lst3 = sorted(lst,reverse=True)
print(lst3)   #倒敘
 
結果:
[1, 3, 2, 5, 4]
[1, 2, 3, 4, 5]
[5, 4, 3, 2, 1]

字典使用sorted排序

dic = {1:'a',3:'c',2:'b'}
print(sorted(dic))   # 字典排序返回的就是排序後的key
 
結果:
[1,2,3]

和函數組合使用

# 定義一個列表,而後根據一元素的長度排序
lst = ['天龍八部','西遊記','紅樓夢','三國演義']
 
# 計算字符串的長度
def func(s):
    return len(s)
print(sorted(lst,key=func))
 
# 結果:
# ['西遊記', '紅樓夢', '天龍八部', '三國演義']

和lambda組合使用

lst = ['天龍八部','西遊記','紅樓夢','三國演義']
 
print(sorted(lst,key=lambda s:len(s)))
 
結果:
['西遊記', '紅樓夢', '天龍八部', '三國演義']
 
 
lst = [{'id':1,'name':'alex','age':18},
    {'id':2,'name':'wusir','age':17},
    {'id':3,'name':'taibai','age':16},]
 
# 按照年齡對學生信息進行排序
 
print(sorted(lst,key=lambda e:e['age']))
 
結果:
[{'id': 3, 'name': 'taibai', 'age': 16}, {'id': 2, 'name': 'wusir', 'age': 17}, {'id': 1, 'name': 'alex', 'age': 18}]

filter

篩選過濾

語法: filter(function,iterable)

function: 用來篩選的函數,在filter中會自動的把iterable中的元素傳遞給function,而後根據function返回的True或者False來判斷是否保留此項數據

iterable:可迭代對象

lst = [{'id':1,'name':'alex','age':18},
        {'id':1,'name':'wusir','age':17},
        {'id':1,'name':'taibai','age':16},]
 
ls = filter(lambda e:e['age'] > 16,lst)
 
print(list(ls))
 
結果:
[{'id': 1, 'name': 'alex', 'age': 18},
 {'id': 1, 'name': 'wusir', 'age': 17}]

map

映射函數

語法: map(function,iterable) 能夠對可迭代對象中的每個元素進映射,分別取執行function

計算列表中每一個元素的平方,返回新列表

lst = [1,2,3,4,5]

def func(s):

    return  s*s

mp = map(func,lst)

print(mp)

print(list(mp))

改寫成lambda

lst = [1,2,3,4,5]

print(list(map(lambda s:s*s,lst)))

計算兩個列表中相同位置的數據的和

lst1 = [1, 2, 3, 4, 5]

lst2 = [2, 4, 6, 8, 10]

print(list(map(lambda x, y: x+y, lst1, lst2)))

結果:

[3, 6, 9, 12, 15]

reduce

from functools import reduce
def func(x,y):
    return x + y

# reduce 的使用方式:
# reduce(函數名,可迭代對象)  # 這兩個參數必須都要有,缺一個不行

ret = reduce(func,[3,4,5,6,7])
print(ret)  # 結果 25
reduce的做用是先把列表中的前倆個元素取出計算出一個值而後臨時保存着,
接下來用這個臨時保存的值和列表中第三個元素進行計算,求出一個新的值將最開始
臨時保存的值覆蓋掉,而後在用這個新的臨時值和列表中第四個元素計算.依次類推

注意:咱們放進去的可迭代對象沒有更改
以上這個例子咱們使用sum就能夠徹底的實現了.我如今有[1,2,3,4]想讓列表中的數變成1234,就要用到reduce了.
普通函數版
from functools import reduce

def func(x,y):

    return x * 10 + y
    # 第一次的時候 x是1 y是2  x乘以10就是10,而後加上y也就是2最終結果是12而後臨時存儲起來了
    # 第二次的時候x是臨時存儲的值12 x乘以10就是 120 而後加上y也就是3最終結果是123臨時存儲起來了
    # 第三次的時候x是臨時存儲的值123 x乘以10就是 1230 而後加上y也就是4最終結果是1234而後返回了

l = reduce(func,[1,2,3,4])
print(l)


匿名函數版
l = reduce(lambda x,y:x*10+y,[1,2,3,4])
print(l)

在Python2.x版本中recude是直接 import就能夠的, Python3.x版本中須要從functools這個包中導入

龜叔本打算將 lambda 和 reduce 都從全局名字空間都移除, 輿論說龜叔不喜歡lambda 和 reduce

最後lambda沒刪除是由於和一我的寫信寫了好多封,進行交流而後把lambda保住了.

參考資料:

https://www.processon.com/view/link/5b4ee15be4b0edb750de96ac

遞歸

在函數中調用函數自己,就是遞歸

def func():

    print('我是誰')

    func()

func()

在python中遞歸的深度最大到998

def func(n):

    print(n)

    n+=1

    func(n)

func(1)

官方文檔表示最大遞歸深度是1000

but in 2.0 the maximum recursion depth can be read and modified using sys.getrecursionlimit()

and sys.setrecursionlimit(). The default value is 1000

遞歸的應用:

  咱們可使用遞歸來遍歷各類樹形結構,好比咱們的文件夾系統.可使用遞歸來遍歷該文件夾中的全部文件

import os

def read(filepath, n):

    files = os.listdir(filepath) # 獲取到當前⽂件夾中的全部⽂件

    for fi in files: # 遍歷⽂件夾中的⽂件, 這⾥獲取的只是本層⽂件名

        fi_d = os.path.join(filepath,fi) # 加⼊⽂件夾 獲取到⽂件夾+⽂件

        if os.path.isdir(fi_d): # 若是該路徑下的⽂件是⽂件夾

            print("\t"*n, fi)

            read(fi_d, n+1) # 繼續進⾏相同的操做

        else:

            print("\t"*n, fi) # 遞歸出⼝. 最終在這⾥隱含着return

#遞歸遍歷⽬錄下全部⽂件

read('../python_s14/', 0)
相關文章
相關標籤/搜索