python-day5-裝飾器補充、模塊、字符串格式化和序列化

裝飾器補充之雙層裝飾器

 1 user_info = {}
 2 
 3 
 4 def check_login(func):
 5     def inner(*args, **kwargs):
 6         if user_info.get('is_login', None):
 7             ret = func(*args, **kwargs)
 8             return ret
 9         else:
10             print('請先登陸...')
11     return inner
12 
13 
14 def check_user_type(func):
15     def inner(*args, **kwargs):
16         if user_info.get('user_type', None) == 1:
17             ret = func(*args, **kwargs)
18             return ret
19         else:
20             print('無權限查看...')
21     return inner
22 
23 
24 def login():
25     user = input('請輸入用戶名: ')
26     if user == 'admin':
27         user_info['is_login'] = True
28         user_info['user_type'] = 1
29     else:
30         user_info['is_login'] = True
31         user_info['user_type'] = 2
32 
33 @check_login
34 @check_user_type
35 def index():
36     """
37     管理員的功能
38     :return:
39     """
40     print('index')
41 
42 @check_login
43 def home():
44     """
45     普通用戶的功能
46     :return:
47     """
48     print('home')
49 
50 
51 def main():
52     while True:
53         int = input('1. 登陸    2.查看信息     3.超級管理員\n>>>')
54         if int == '1':
55             login()
56         elif int == '2':
57             home()
58         elif int == '3':
59             index()
60 
61 
62 main()
View Code

注意:雙層裝飾器的執行過程html

  • 解釋器是從下往上依次加載裝飾器,以上面代碼爲例,解釋器先將check_user_type和原函數index()加載到內存,而後將check_user_type的inner函數返回給check_login裝飾器。
  • 執行時,先執行最外層的check_login裝飾器,而後執行check_user_type裝飾器。
  • 執行時,若是第一個裝飾器if條件不成立,那麼第二個裝飾器不會執行。
  • 執行時,若是第一個裝飾器if條件成立,那麼繼續執行第二個裝飾器。

字符串格式化

目前python支持百分號和format來完成字符串格式化的操做,百分號是2.0版本的。format方式是3.0版本的。python

format支持的格式比百分號方式多。算法

一、百分號方式json

1 str = "my name is %s, age is %d"
2 print(str%('john', 23))

%[(name)][flags][width].[precision]typecode數據結構

  • (name)      可選,用於選擇指定的key
  • flags          可選,可供選擇的值有:
    • +       右對齊;正數前加正好,負數前加負號;
    • -        左對齊;正數前無符號,負數前加負號;
    • 空格    右對齊;正數前加空格,負數前加負號;
    • 0        右對齊;正數前無符號,負數前加負號;用0填充空白處
    • width         可選,佔有寬度
    • .precision   可選,小數點後保留的位數
    • typecode    必選
      • s,獲取傳入對象的__str__方法的返回值,並將其格式化到指定位置
      • r,獲取傳入對象的__repr__方法的返回值,並將其格式化到指定位置
      • c,整數:將數字轉換成其unicode對應的值,10進制範圍爲 0 <= i <= 1114111(py27則只支持0-255);字符:將字符添加到指定位置
      • o,將整數轉換成 八  進製表示,並將其格式化到指定位置
      • x,將整數轉換成十六進制表示,並將其格式化到指定位置
      • d,將整數、浮點數轉換成 十 進製表示,並將其格式化到指定位置
      • e,將整數、浮點數轉換成科學計數法,並將其格式化到指定位置(小寫e)
      • E,將整數、浮點數轉換成科學計數法,並將其格式化到指定位置(大寫E)
      • f, 將整數、浮點數轉換成浮點數表示,並將其格式化到指定位置(默認保留小數點後6位)
      • F,同上
      • g,自動調整將整數、浮點數轉換成 浮點型或科學計數法表示(超過6位數用科學計數法),並將其格式化到指定位置(若是是科學計數則是e;)
      • G,自動調整將整數、浮點數轉換成 浮點型或科學計數法表示(超過6位數用科學計數法),並將其格式化到指定位置(若是是科學計數則是E;)
      • %,當字符串中存在格式化標誌時,須要用 %%表示一個百分號

    注:Python中百分號格式化是不存在自動將整數轉換成二進制表示的方式app

經常使用格式化ide

 1 tpl = "i am %s" % "john"
 2  
 3 tpl = "i am %s age %d" % ("john", 18)
 4  
 5 tpl = "i am %(name)s age %(age)d" % {"name": "john", "age": 18}
 6  
 7 tpl = "percent %.2f" % 99.97623
 8  
 9 tpl = "i am %(pp).2f" % {"pp": 123.425556, }
10  
11 tpl = "i am %.2f %%" %123.425556
View Code

    

format方式函數

1 str = "my name is {0}, age is {1}"
2 print(str.format('john',25))

[[fill]align][sign][#][0][width][,][.precision][type]this

    • fill           【可選】空白處填充的字符
    • align        【可選】對齊方式(需配合width使用)
      • <,內容左對齊
      • >,內容右對齊(默認)
      • =,內容右對齊,將符號放置在填充字符的左側,且只對數字類型有效。 即便:符號+填充物+數字
      • ^,內容居中
    • sign         【可選】有無符號數字
      • +,正號加正,負號加負;
      •  -,正號不變,負號加負;
      • 空格 ,正號空格,負號加負;
    • #            【可選】對於二進制、八進制、十六進制,若是加上#,會顯示 0b/0o/0x,不然不顯示
    • ,            【可選】爲數字添加分隔符,如:1,000,000
    • width       【可選】格式化位所佔寬度
    • .precision 【可選】小數位保留精度
    • type         【可選】格式化類型
      • 傳入」 字符串類型 「的參數
        • s,格式化字符串類型數據
        • 空白,未指定類型,則默認是None,同s
      • 傳入「 整數類型 」的參數
        • b,將10進制整數自動轉換成2進製表示而後格式化
        • c,將10進制整數自動轉換爲其對應的unicode字符
        • d,十進制整數
        • o,將10進制整數自動轉換成8進製表示而後格式化;
        • x,將10進制整數自動轉換成16進製表示而後格式化(小寫x)
        • X,將10進制整數自動轉換成16進製表示而後格式化(大寫X)
      • 傳入「 浮點型或小數類型 」的參數
        • e, 轉換爲科學計數法(小寫e)表示,而後格式化;
        • E, 轉換爲科學計數法(大寫E)表示,而後格式化;
        • f , 轉換爲浮點型(默認小數點後保留6位)表示,而後格式化;
        • F, 轉換爲浮點型(默認小數點後保留6位)表示,而後格式化;
        • g, 自動在e和f中切換
        • G, 自動在E和F中切換
        • %,顯示百分比(默認顯示小數點後6位)

經常使用格式化:spa

 1 tpl = "i am {}, age {}, {}".format("john", 25, 'john')
 2   
 3 tpl = "i am {}, age {}, {}".format(*["john", 25, 'john'])
 4   
 5 tpl = "i am {0}, age {1}, really {0}".format("john", 25)
 6   
 7 tpl = "i am {0}, age {1}, really {0}".format(*["john", 25])
 8   
 9 tpl = "i am {name}, age {age}, really {name}".format(name="john", age=25)
10   
11 tpl = "i am {name}, age {age}, really {name}".format(**{"name": "john", "age": 25})
12   
13 tpl = "i am {0[0]}, age {0[1]}, really {0[2]}".format(['john', 25, 'john'], [11, 22, 33])
14   
15 tpl = "i am {:s}, age {:d}, money {:f}".format("john", 25, 88888.1)
16   
17 tpl = "i am {:s}, age {:d}".format(*["john", 25])
18   
19 tpl = "i am {name:s}, age {age:d}".format(name="john", age=25)
20   
21 tpl = "i am {name:s}, age {age:d}".format(**{"name": "john", "age": 25})
22  
23 tpl = "numbers: {:b},{:o},{:d},{:x},{:X}, {:%}".format(15, 15, 15, 15, 15, 15.87623, 2)
24  
25 tpl = "numbers: {:b},{:o},{:d},{:x},{:X}, {:%}".format(15, 15, 15, 15, 15, 15.87623, 2)
26  
27 tpl = "numbers: {0:b},{0:o},{0:d},{0:x},{0:X}, {0:%}".format(15)
28  
29 tpl = "numbers: {num:b},{num:o},{num:d},{num:x},{num:X}, {num:%}".format(num=15)

更多格式化操做:https://docs.python.org/3/library/string.html

生成器和迭代器

一、生成器Generators

生成器是一個有生成數據能力的對象。函數中若是用到了yield語法,那麼這個函數就是一個生成器

特色:

  • 生成器是一個函數,並且函數的參數都會保留,生成器返回的數據是可迭代的對象。
  • 迭代到下一次的調用時,所使用的參數都是第一次所保留下的,便是說,在整個全部函數調用的參數都是第一次所調用時保留的,而不是新建立的

yield 生成器的運行機制:

  • 當你問生成器要一個數時,生成器會執行,直至出現 yield 語句,生成器把 yield 的參數給你,以後生成器就不會往下繼續運行。 當你問他要下一個數時,他會從上次的狀態。開始運行,直至出現yield語句,把參數給你,以後停下。如此反覆,直至退出函數。

yield的使用

  • 當你定義一個函數,使用了yield關鍵字時,這個函數就是一個生成器,它的執行會和其餘普通的函數有不少不一樣,函數返回的是一個對象,而不是你日常 所用return語句那樣,能獲得結果值。若是想取得值,那得調用next()函數或者迭代器。
 1 def xf():
 2     yield 1
 3     yield 2
 4     yield 3
 5 
 6 ret = xf()
 7 print(ret.__next__())
 8 print(ret.__next__())
 9 print(ret.__next__())
10 print(ret.__next__())
11 
12 結果:
13 
14 1
15 2
16 3
17   File "/Users/TheOne/PycharmProjects/s13/day5/day5-課上/module.py", line 15, in <module>
18     print(ret.__next__())
19 StopIteration

 

二、迭代器Iterators

迭代器是訪問集合元素的一種方式。迭代器對象從集合的第一個元素開始訪問,直到全部的元素被訪問完結束。迭代器只能往前不會後退,不過這也沒什麼,由於人們不多在迭代途中日後退。

優勢:

  • 對於原生支持隨機訪問的數據結構(如tuple、list),迭代器和經典for循環的索引訪問相比並沒有優點,反而丟失了索引值(可使用內建函數enumerate()找回這個索引值)。但對於沒法隨機訪問的數據結構(好比set)而言,迭代器是惟一的訪問元素的方式。
  • 迭代器的一大優勢是不要求事先準備好整個迭代過程當中全部的元素。迭代器僅僅在迭代到某個元素時才計算該元素,而在這以前或以後,元素能夠不存在或者被銷燬。這個特色使得它特別適合用於遍歷一些巨大的或是無限的集合,好比幾個G的文件,或是斐波那契數列等等
  • 迭代器更大的功勞是提供了一個統一的訪問集合的接口,只要定義了__iter__()方法對象,就可使用迭代器訪問

說明:for循環內部就是使用了next方法實現了遍歷

 

遞歸

 1 def fo(arg):
 2     arg += 1
 3     if arg >= 5:
 4         print(arg)
 5     else:
 6         return fo(arg)
 7 fo(1)
 8 
 9 結果:
10 5
View Code

若是函數包含了對其自身的調用,該函數就是遞歸的。

這裏插入一些關於遞歸的網方解釋,由於我是從網上搜到的這些內容:
(1)遞歸就是在過程或函數裏調用自身;
(2)在使用遞歸策略時,必須有一個明確的遞歸結束條件,稱爲遞歸出口。

遞歸算法通常用於解決三類問題:
(1)數據的定義是按遞歸定義的。(好比Fibonacci函數)
(2)問題解法按遞歸算法實現。(回溯)
(3)數據的結構形式是按遞歸定義的。(好比樹的遍歷,圖的搜索)   

遞歸的缺點:遞歸算法解題的運行效率較低。在遞歸調用的過程中系統爲每一層的返回點、局部量等開闢了棧來存儲。遞歸次數過多容易形成棧溢出等。

參考:http://www.cnblogs.com/balian/archive/2011/02/11/1951054.html

模塊

爲何要有模塊?

如今,咱們寫一些小項目時,都喜歡把全部的函數都放在一個文件裏面(.py)。那麼若是之後寫大型項目,涉及到的函數可能有幾百幾千個,那個時候咱們若是要更改某個函數的函數功能。缺點以下:

  • 查找不便
  • 單個文件代碼太多,不宜更改。雜亂無章。

爲了解決上面的難題,就用到了模塊,模塊和普通的程序同樣,只不過模塊文件中存放的所有都是業務處理的惟一功能,好比。用戶操做的函數寫在一個文件中,後臺管理類的函數放在一個文件中。在主程序須要用到的時候,直接導入模塊,執行對應的函數功能便可。優勢以下:

  • 易維護,方便代碼管理
  • 查找方便。

 

導入模塊的依據

模塊的導入都是針對當前執行程序的目錄而言的,python會先到當前程序執行的目錄去查找模塊,若是找不到,會接着到python定義的幾個目錄中去查找。若是還找不到,那麼就會報錯。

 1 import sys
 2 for i in sys.path:
 3     print(i)
 4 結果:
 5 /Users/TheOne/PycharmProjects/s13/day5/day5-課上
 6 /Users/TheOne/PycharmProjects/s13
 7 /Library/Frameworks/Python.framework/Versions/3.5/lib/python35.zip
 8 /Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5
 9 /Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/plat-darwin
10 /Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/lib-dynload
11 /Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages
View Code

python將全部的查找路徑都放到了sys.path中以列表的方式保存,若是咱們想到除以上路徑外的其它地方加載模塊,那麼將模塊的目錄append到sys.path中便可。

 

模塊名稱的重要性

爲了不自定義模塊和系統或第三方模塊的name衝突,在自定義模塊的時候,要儘可能避開系統模塊名 。或者爲自定義模塊賦予別名。

 

模塊的導入方法

  一、若是在同一目錄下:

    import 模塊名

  二、在當前目錄下的其它目錄

    from 目錄名  import 模塊名

  三、導入模塊並命名別名

    from 目錄名 import 模塊名 as 別名

序列化

json(適合全部程序語言,能夠跨語言平臺,用來在不一樣語言平臺中交換數據。json只支持基本數據類型,即字符串,字典,列表,元素,數字等)

功能:

  • 將python的數據類型系列化成字符串(由於字符串是各語言平臺都支持的數據類型,所以。使用字符串來在各平臺中傳遞數據)
  • 將字符串反序列化成python的數據類型
  • 將python數據序列化到文件中
  • 從文件中將數據反序列化到python
 1 將python數據類型序列化成字符串
 2 
 3 import json
 4 dic = {'name':'john','age':25}
 5 print(dic, type(dic))
 6 ret = json.dumps(dic)
 7 print(ret, type(ret))
 8 結果:
 9 {'age': 25, 'name': 'john'} <class 'dict'>
10 {"age": 25, "name": "john"} <class 'str'>
11 
12 將字符串反序列化成python數據類型
13 import json
14 dic = '{"name":"john","age":25}'
15 print(dic, type(dic))
16 ret = json.loads(dic)
17 print(ret, type(ret))
18 結果:
19 {"name":"john","age":25} <class 'str'>
20 {'age': 25, 'name': 'john'} <class 'dict'>
View Code

注意:將字符串反序列化成python數據類型,必定要用單引號,不然報錯。由於,在其餘語言平臺,單引號的叫字符,雙引號的叫字符串

 1 將python數據序列化到文件中
 2 import json
 3 dic = {"name":"john","age":25}
 4 json.dump(dic, open('db', 'w'))
 5 
 6 從文件中反序列化到python
 7 ret = json.load(open('db', 'r'))
 8 print(ret, type(ret))
 9 結果:
10 {'name': 'john', 'age': 25} <class 'dict'>
View Code

 

pickle(支持python中的任意數據類型,基本數據類型和對象等。只能在python中使用,不支持跨語言平臺使用)

功能和json同樣,只不過pickle在序列化時,將python數據轉換成了pickle的特定格式。

功能:

  • 將python數據序列化到文件中
  • 從文件中將數據反序列化到python
  • 支持字節的方式,即打開文件時,使用wb和rb模式
  • 將python數據類型序列化成pickle特定格式
  • 將pickle格式序列化成python數據類型

 

time&datetime模塊

#_*_coding:utf-8_*_
import time
import datetime
 
print(time.clock()) #返回處理器時間,3.3開始已廢棄
print(time.process_time()) #返回處理器時間,3.3開始已廢棄
print(time.time()) #返回當前系統時間戳
print(time.ctime()) #輸出Tue Jan 26 18:23:48 2016 ,當前系統時間
print(time.ctime(time.time()-86640)) #將時間戳轉爲字符串格式
print(time.gmtime(time.time()-86640)) #將時間戳轉換成struct_time格式
print(time.localtime(time.time()-86640)) #將時間戳轉換成struct_time格式,但返回 的本地時間
print(time.mktime(time.localtime())) #與time.localtime()功能相反,將struct_time格式轉回成時間戳格式
#time.sleep(4) #sleep
print(time.strftime("%Y-%m-%d %H:%M:%S",time.gmtime()) ) #將struct_time格式轉成指定的字符串格式
print(time.strptime("2016-01-28","%Y-%m-%d") ) #將字符串格式轉換成struct_time格式
 
#datetime module
 
print(datetime.date.today()) #輸出格式 2016-01-26
print(datetime.date.fromtimestamp(time.time()-864400) ) #2016-01-16 將時間戳轉成日期格式
current_time = datetime.datetime.now() #
print(current_time) #輸出2016-01-26 19:04:30.335935
print(current_time.timetuple()) #返回struct_time格式
 
#datetime.replace([year[, month[, day[, hour[, minute[, second[, microsecond[, tzinfo]]]]]]]])
print(current_time.replace(2014,9,12)) #輸出2014-09-12 19:06:24.074900,返回當前時間,但指定的值將被替換
 
str_to_date = datetime.datetime.strptime("21/11/06 16:30", "%d/%m/%y %H:%M") #將字符串轉換成日期格式
new_date = datetime.datetime.now() + datetime.timedelta(days=10) #比如今加10天
new_date = datetime.datetime.now() + datetime.timedelta(days=-10) #比如今減10天
new_date = datetime.datetime.now() + datetime.timedelta(hours=-10) #比如今減10小時
new_date = datetime.datetime.now() + datetime.timedelta(seconds=120) #比如今+120s
print(new_date)

 

loggin模塊

不少程序都有記錄日誌的需求,而且日誌中包含的信息即有正常的程序訪問日誌,還可能有錯誤、警告等信息輸出,python的logging模塊提供了標準的日誌接口,你能夠經過它存儲各類格式的日誌,logging的日誌能夠分爲 debug()info()warning()error() and critical() 5個級別,下面咱們看一下怎麼用。

loggin模塊級別

Level When it’s used
DEBUG Detailed information, typically of interest only when diagnosing problems.
INFO Confirmation that things are working as expected.
WARNING An indication that something unexpected happened, or indicative of some problem in the near future (e.g. ‘disk space low’). The software is still working as expected.
ERROR Due to a more serious problem, the software has not been able to perform some function.
CRITICAL A serious error, indicating that the program itself may be unable to continue running.

若是想把日誌寫到文件裏,也很簡單

1 import logging
2  
3 logging.basicConfig(filename='example.log',level=logging.INFO)
4 logging.debug('This message should go to the log file')
5 logging.info('So should this')
6 logging.warning('And this, too')
 
 

其中下面這句中的level=loggin.INFO意思是,把日誌紀錄級別設置爲INFO,也就是說,只有比日誌是INFO或比INFO級別更高的日誌纔會被紀錄到文件裏,在這個例子, 第一條日誌是不會被紀錄的,若是但願紀錄debug的日誌,那把日誌級別改爲DEBUG就好了。

1 logging.basicConfig(filename='example.log',level=logging.INFO)

 

感受上面的日誌格式忘記加上時間啦,日誌不知道時間怎麼行呢,下面就來加上!

1 import logging
2 logging.basicConfig(format='%(asctime)s %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p')
3 logging.warning('is when this event was logged.')
4  
5 #輸出
6 12/12/2010 11:46:36 AM is when this event was logged.

 

若是想同時把log打印在屏幕和文件日誌裏,就須要瞭解一點複雜的知識 了

The logging library takes a modular approach and offers several categories of components: loggers, handlers, filters, and formatters.

  • Loggers expose the interface that application code directly uses.
  • Handlers send the log records (created by loggers) to the appropriate destination.
  • Filters provide a finer grained facility for determining which log records to output.
  • Formatters specify the layout of log records in the final output.
 1 import logging
 2  
 3 #create logger
 4 logger = logging.getLogger('TEST-LOG')
 5 logger.setLevel(logging.DEBUG)
 6  
 7  
 8 # create console handler and set level to debug
 9 ch = logging.StreamHandler()
10 ch.setLevel(logging.DEBUG)
11  
12 # create file handler and set level to warning
13 fh = logging.FileHandler("access.log")
14 fh.setLevel(logging.WARNING)
15 # create formatter
16 formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
17  
18 # add formatter to ch and fh
19 ch.setFormatter(formatter)
20 fh.setFormatter(formatter)
21  
22 # add ch and fh to logger
23 logger.addHandler(ch)
24 logger.addHandler(fh)
25  
26 # 'application' code
27 logger.debug('debug message')
28 logger.info('info message')
29 logger.warn('warn message')
30 logger.error('error message')
31 logger.critical('critical message')
相關文章
相關標籤/搜索