1. 程式人生 > >Python學習記錄day5

Python學習記錄day5

process its 定義 return 不能 自己 多層裝飾器 環比 方式

1.多層裝飾器

多層裝飾器的原理是,裝飾器裝飾函數後,其實也是一個函數,這樣又可以被裝飾器裝飾。 編譯是從下至上進行的,執行時是從上至下進行。

#!/usr/bin/env python
# _*_coding:utf-8_*_
‘‘‘
 * Created on 2016/11/29 20:38.
 * @author: Chinge_Yang.
‘‘‘

USER_INFO = {}


# USER_INFO[‘is_login‘] = True
# USER_INFO[‘user_type‘] = 2


def check_login(func):
    def inner(*args, **kwargs):
        if USER_INFO.get("is_login", None):
            ret = func(*args, **kwargs)
            return ret
        else:
            print("請登錄")

    return inner


def check_admin(func):
    def inner(*args, **kwargs):
        if USER_INFO.get(‘user_type‘, None) == 2:
            ret = func(*args, **kwargs)
            return ret
        else:
            print(‘無權限查看‘)

    return inner


@check_login
@check_admin
def index():
    """
    管理員的功能
    :return:
    """
    print(‘Index‘)


@check_login
def home():
    """
    普通用戶功能
    :return:
    """
    print("home")


def login():
    user = input("請輸入用戶名:")
    if user == "admin":
        USER_INFO["is_login"] = True
        USER_INFO["user_type"] = 2
    else:
        USER_INFO["is_login"] = True
        USER_INFO["user_type"] = 1


def main():
    while True:
        inp = input("1.登錄;2.查看信息;3.超級管理員管理\n >>>")
        if inp == "1":
            login()
        elif inp == "2":
            home()
        elif inp == "3":
            index()
        elif inp == "q":
            exit()


main()

2.字符串格式化

Python的字符串格式化有兩種方式: 百分號方式、format方式

百分號的方式相對來說比較老,而format方式則是比較先進的方式,企圖替換古老的方式,目前兩者並存。[PEP-3101]
This PEP proposes a new system for built-in string formatting operations, intended as a replacement for the existing ‘%‘ string formatting operator.

1.百分號方式

%[(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)
    f, 將整數、浮點數轉換成浮點數表示,並將其格式化到指定位置(默認保留小數點後6位)
    F,同上
    g,自動調整將整數、浮點數轉換成浮點型或科學計數法表示(超過6位數用科學計數法),並將其格式化到指定位置(如果是科學計數則是e;)
    G,自動調整將整數、浮點數轉換成浮點型或科學計數法表示(超過6位數用科學計數法),並將其格式化到指定位置(如果是科學計數則是E;)
    %,當字符串中存在格式化標誌時,需要用 %%表示一個百分號

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

常用格式化:

tpl = "i am %s" % "ygqygq2"
 
tpl = "i am %s age %d" % ("ygqygq2", 27)
 
tpl = "i am %(name)s age %(age)d" % {"name": "ygqgyq2", "age": 27}
 
tpl = "percent %.2f" % 99.97623
 
tpl = "i am %(pp).2f" % {"pp": 123.425556, }
 
tpl = "i am %.2f %%" % {"pp": 123.425556, }

2.Format方式

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

  • 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位)

常用格式化:

tpl = "i am {}, age {}, {}".format("seven", 18, ‘alex‘)
  
tpl = "i am {}, age {}, {}".format(*["seven", 18, ‘alex‘])
  
tpl = "i am {0}, age {1}, really {0}".format("seven", 18)
  
tpl = "i am {0}, age {1}, really {0}".format(*["seven", 18])
  
tpl = "i am {name}, age {age}, really {name}".format(name="seven", age=18)
  
tpl = "i am {name}, age {age}, really {name}".format(**{"name": "seven", "age": 18})
  
tpl = "i am {0[0]}, age {0[1]}, really {0[2]}".format([1, 2, 3], [11, 22, 33])
  
tpl = "i am {:s}, age {:d}, money {:f}".format("seven", 18, 88888.1)
  
tpl = "i am {:s}, age {:d}".format(*["seven", 18])
  
tpl = "i am {name:s}, age {age:d}".format(name="seven", age=18)
  
tpl = "i am {name:s}, age {age:d}".format(**{"name": "seven", "age": 18})
 
tpl = "numbers: {:b},{:o},{:d},{:x},{:X}, {:%}".format(15, 15, 15, 15, 15, 15.87623, 2)
 
tpl = "numbers: {:b},{:o},{:d},{:x},{:X}, {:%}".format(15, 15, 15, 15, 15, 15.87623, 2)
 
tpl = "numbers: {0:b},{0:o},{0:d},{0:x},{0:X}, {0:%}".format(15)
 
tpl = "numbers: {num:b},{num:o},{num:d},{num:x},{num:X}, {num:%}".format(num=15)

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

3.叠代器和生成器

1.叠代器

叠代器是訪問集合元素的一種方式。叠代器對象從集合的第一個元素開始訪問,直到所有的元素被訪問完結束。叠代器只能往前不會後退,不過這也沒什麽,因為人們很少在叠代途中往後退。另外,叠代器的一大優點是不要求事先準備好整個叠代過程中所有的元素。叠代器僅僅在叠代到某個元素時才計算該元素,而在這之前或之後,元素可以不存在或者被銷毀。這個特點使得它特別適合用於遍歷一些巨大的或是無限的集合,比如幾個G的文件

特點:

訪問者不需要關心叠代器內部的結構,僅需通過next()方法不斷去取下一個內容
不能隨機訪問集合中的某個值 ,只能從頭到尾依次訪問
訪問到一半時不能往回退
便於循環比較大的數據集合,節省內存

>>> a = iter([1,2,3,4,5])
>>> a
<list_iterator object at 0x101402630>
>>> a.__next__()
1
>>> a.__next__()
2
>>> a.__next__()
3
>>> a.__next__()
4
>>> a.__next__()
5
>>> a.__next__()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

2.生成器

一個函數調用時返回一個叠代器,那這個函數就叫做生成器(generator);如果函數中包含yield語法,那這個函數就會變成生成器;

def func():
    print(11)
    yield 1
    print(22)
    yield 2
    print(33)
    yield 3
    print(44)
    yield 4

上述代碼中:func是函數稱為生成器,當執行此函數func()時會得到一個叠代器。

>>> temp = func()
>>> temp.__next__()
11
1
>>> temp.__next__()
22
2
>>> temp.__next__()
33
3
>>> temp.__next__()
44
4
>>> temp.__next__()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

4.函數遞歸

在函數內部,可以調用其他函數。如果一個函數在內部調用自身本身,這個函數就是遞歸函數。

def func(n):
    n += 1
    if n >= 4:
        return "end"
    return func(n)

res = func(1)
print(res)

遞歸函數的優點是定義簡單,邏輯清晰。理論上,所有的遞歸函數都可以寫成循環的方式,但循環的邏輯不如遞歸清晰。

使用遞歸函數需要註意防止棧溢出。

詳細請看廖雪峰的官方網站中遞歸函數

5.模塊

為了編寫可維護的代碼,我們把很多函數分組,分別放到不同的文件裏,這樣,每個文件包含的代碼就相對較少,很多編程語言都采用這種組織代碼的方式。在Python中,一個.py文件就稱之為一個模塊(Module)。
模塊分為三種:
* 自定義模塊
* 第三方模塊
* 內置模塊

1.使用模塊有什麽好處?

1. 最大的好處是大大提高了代碼的可維護性。
2. 使用模塊還可以避免函數名和變量名沖突。

2.導入模塊

單模塊:import
嵌套在文件夾下:
from xxx import xxx
from xxx import as ooo

3.第三方模塊

pip3安裝(pip安裝)
pip3 install requests
源碼安裝
curl -OL https://github.com/kennethreitz/requests/tarball/master

解壓後,進入目錄

python setup.py install

6.序列化

Python中用於序列化的兩個模塊

  • json 用於【字符串】和【python基本數據類型】間進行轉換
  • pickle 用於【python特有的類型】和【python基本數據類型】間進行轉換

Json模塊提供了四個功能:dumps、dump、loads、load
pickle模塊提供了四個功能:dumps、dump、loads、load

json相關用法:

import json

dict = {‘k1‘: ‘v1‘}
print(dict, type(dict))
# 將python基本數據類型轉換成字符串形式
res = json.dumps(dict)
print(res, type(res))

{‘k1‘: ‘v1‘} <class ‘dict‘>
{"k1": "v1"} <class ‘str‘>

import json

# 將python字符串形式轉換成基本數據類型
s1 = ‘{"k1": 123}‘
dict = json.loads(s1)   # 反序列化時,一定要使用 ""
print(dict, type(dict))

{‘k1‘: 123} <class ‘dict‘>

import json

li = [11,22,33]
json.dump(li,open(‘test.txt‘,‘w‘))

li = json.load(open(‘test.txt‘,‘r‘))
print(type(li),li)

pickle相關用法:

import pickle

li = [11,22,33]
r = pickle.dumps(li)
print(r)

res = pickle.loads(r)
print(res)

b‘\x80\x03]q\x00(K\x0bK\x16K!e.‘
[11, 22, 33]

li = [11,22,33]
pickle.dump(li, open(‘test4.txt‘, ‘wb‘))

res = pickle.load(open(‘test4.txt‘, ‘rb‘))
print(res)

[11, 22, 33]

json和pickle對比:
1. json更適合跨語言,字符串,基本數據類型
2. pickle更適合python所有類型的序列化操作

7.time & datetime模塊

#_*_coding:utf-8_*_
__author__ = ‘Alex Li‘

import time


# print(time.clock()) #返回處理器時間,3.3開始已廢棄 , 改成了time.process_time()測量處理器運算時間,不包括sleep時間,不穩定,mac上測不出來
# print(time.altzone)  #返回與utc時間的時間差,以秒計算# print(time.asctime()) #返回時間格式"Fri Aug 19 11:14:16 2016",
# print(time.localtime()) #返回本地時間 的struct time對象格式
# print(time.gmtime(time.time()-800000)) #返回utc時間的struc時間對象格式

# print(time.asctime(time.localtime())) #返回時間格式"Fri Aug 19 11:14:16 2016",
#print(time.ctime()) #返回Fri Aug 19 12:38:29 2016 格式, 同上



# 日期字符串 轉成  時間戳
# string_2_struct = time.strptime("2016/05/22","%Y/%m/%d") #將 日期字符串 轉成 struct時間對象格式
# print(string_2_struct)
# #
# struct_2_stamp = time.mktime(string_2_struct) #將struct時間對象轉成時間戳
# print(struct_2_stamp)



#將時間戳轉為字符串格式
# print(time.gmtime(time.time()-86640)) #將utc時間戳轉換成struct_time格式
# print(time.strftime("%Y-%m-%d %H:%M:%S",time.gmtime()) ) #將utc struct_time格式轉成指定的字符串格式





#時間加減
import datetime

# print(datetime.datetime.now()) #返回 2016-08-19 12:47:03.941925
#print(datetime.date.fromtimestamp(time.time()) )  # 時間戳直接轉成日期格式 2016-08-19
# print(datetime.datetime.now() )
# print(datetime.datetime.now() + datetime.timedelta(3)) #當前時間+3天
# print(datetime.datetime.now() + datetime.timedelta(-3)) #當前時間-3天
# print(datetime.datetime.now() + datetime.timedelta(hours=3)) #當前時間+3小時
# print(datetime.datetime.now() + datetime.timedelta(minutes=30)) #當前時間+30分


#
# c_time  = datetime.datetime.now()
# print(c_time.replace(minute=3,hour=2)) #時間替換

8.logging模塊  

很多程序都有記錄日誌的需求,並且日誌中包含的信息即有正常的程序訪問日誌,還可能有錯誤、警告等信息輸出,python的logging模塊提供了標準的日誌接口,你可以通過它存儲各種格式的日誌,logging的日誌可以分為 debug(), info(), warning(), error() and critical() 5個級別,下面我們看一下怎麽用。
最簡單用法

import logging
 
logging.warning("user [alex] attempted wrong password more than 3 times")
logging.critical("server is down")

WARNING:root:user [alex] attempted wrong password more than 3 times
CRITICAL:root:server is down

看一下這幾個日誌級別分別代表什麽意思

LevelWhen 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.

  

如果想把日誌寫到文件裏,也很簡單

import logging
 
logging.basicConfig(filename=‘example.log‘,level=logging.INFO)
logging.debug(‘This message should go to the log file‘)
logging.info(‘So should this‘)
logging.warning(‘And this, too‘)

其中下面這句中的level=loggin.INFO意思是,把日誌紀錄級別設置為INFO,也就是說,只有比日誌是INFO或比INFO級別更高的日誌才會被紀錄到文件裏,在這個例子, 第一條日誌是不會被紀錄的,如果希望紀錄debug的日誌,那把日誌級別改成DEBUG就行了。

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

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

import logging
logging.basicConfig(format=%(asctime)s %(message)s‘, datefmt=‘%m/%d/%Y %I:%M:%S %p‘)
logging.warning(‘is when this event was logged.‘)

12/12/2010 11:46:36 AM is when this event was logged.

日誌格式

%(name)sLogger的名字
%(levelno)s 數字形式的日誌級別
%(levelname)s 文本形式的日誌級別
%(pathname)s 調用日誌輸出函數的模塊的完整路徑名,可能沒有
%(filename)s 調用日誌輸出函數的模塊的文件名
%(module)s 調用日誌輸出函數的模塊名
%(funcName)s 調用日誌輸出函數的函數名
%(lineno)d 調用日誌輸出函數的語句所在的代碼行
%(created)f 當前時間,用UNIX標準的表示時間的浮 點數表示
%(relativeCreated)d 輸出日誌信息時的,自Logger創建以 來的毫秒數
%(asctime)s 字符串形式的當前時間。默認格式是 “2003-07-08 16:49:45,896”。逗號後面的是毫秒
%(thread)d 線程ID。可能沒有
%(threadName)s 線程名。可能沒有
%(process)d 進程ID。可能沒有
%(message)s 用戶輸出的消息

如果想同時把log打印在屏幕和文件日誌裏,就需要了解一點復雜的知識 了

Python 使用logging模塊記錄日誌涉及四個主要類,使用官方文檔中的概括最為合適:
1. logger提供了應用程序可以直接使用的接口;
2. handler將(logger創建的)日誌記錄發送到合適的目的輸出;
3. filter提供了細度設備來決定輸出哪條日誌記錄;
4. formatter決定日誌記錄的最終輸出格式。

logger
每個程序在輸出信息之前都要獲得一個Logger。Logger通常對應了程序的模塊名,比如聊天工具的圖形界面模塊可以這樣獲得它的Logger:
LOG=logging.getLogger(”chat.gui”)
而核心模塊可以這樣:
LOG=logging.getLogger(”chat.kernel”)

Logger.setLevel(lel):指定最低的日誌級別,低於lel的級別將被忽略。debug是最低的內置級別,critical為最高
Logger.addFilter(filt)、Logger.removeFilter(filt):添加或刪除指定的filter
Logger.addHandler(hdlr)、Logger.removeHandler(hdlr):增加或刪除指定的handler
Logger.debug()、Logger.info()、Logger.warning()、Logger.error()、Logger.critical():可以設置的日誌級別

handler
handler對象負責發送相關的信息到指定目的地。Python的日誌系統有多種Handler可以使用。有些Handler可以把信息輸出到控制臺,有些Logger可以把信息輸出到文件,還有些 Handler可以把信息發送到網絡上。如果覺得不夠用,還可以編寫自己的Handler。可以通過addHandler()方法添加多個多handler
Handler.setLevel(lel):指定被處理的信息級別,低於lel級別的信息將被忽略
Handler.setFormatter():給這個handler選擇一個格式
Handler.addFilter(filt)、Handler.removeFilter(filt):新增或刪除一個filter對象

每個Logger可以附加多個Handler。接下來我們就來介紹一些常用的Handler:
1) logging.StreamHandler
使用這個Handler可以向類似與sys.stdout或者sys.stderr的任何文件對象(file object)輸出信息。它的構造函數是:
StreamHandler([strm])
其中strm參數是一個文件對象。默認是sys.stderr
2) logging.FileHandler
和StreamHandler類似,用於向一個文件輸出日誌信息。不過FileHandler會幫你打開這個文件。它的構造函數是:
FileHandler(filename[,mode])
filename是文件名,必須指定一個文件名。
mode是文件的打開方式。參見Python內置函數open()的用法。默認是’a‘,即添加到文件末尾。
3) logging.handlers.RotatingFileHandler
這個Handler類似於上面的FileHandler,但是它可以管理文件大小。當文件達到一定大小之後,它會自動將當前日誌文件改名,然後創建 一個新的同名日誌文件繼續輸出。比如日誌文件是chat.log。當chat.log達到指定的大小之後,RotatingFileHandler自動把 文件改名為chat.log.1。不過,如果chat.log.1已經存在,會先把chat.log.1重命名為chat.log.2。。。最後重新創建 chat.log,繼續輸出日誌信息。它的構造函數是:
RotatingFileHandler( filename[, mode[, maxBytes[, backupCount]]])
其中filename和mode兩個參數和FileHandler一樣。
maxBytes用於指定日誌文件的最大文件大小。如果maxBytes為0,意味著日誌文件可以無限大,這時上面描述的重命名過程就不會發生。
backupCount用於指定保留的備份文件的個數。比如,如果指定為2,當上面描述的重命名過程發生時,原有的chat.log.2並不會被更名,而是被刪除。
4) logging.handlers.TimedRotatingFileHandler
這個Handler和RotatingFileHandler類似,不過,它沒有通過判斷文件大小來決定何時重新創建日誌文件,而是間隔一定時間就 自動創建新的日誌文件。重命名的過程與RotatingFileHandler類似,不過新的文件不是附加數字,而是當前時間。它的構造函數是:
TimedRotatingFileHandler( filename [,when [,interval [,backupCount]]])
其中filename參數和backupCount參數和RotatingFileHandler具有相同的意義。
interval是時間間隔。
when參數是一個字符串。表示時間間隔的單位,不區分大小寫。它有以下取值:
S 秒
M 分
H 小時
D 天
W 每星期(interval==0時代表星期一)
midnight 每天淩晨

import logging
 
#create logger
logger = logging.getLogger(‘TEST-LOG‘)
logger.setLevel(logging.DEBUG)
 
 
# create console handler and set level to debug
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)
 
# create file handler and set level to warning
fh = logging.FileHandler("access.log")
fh.setLevel(logging.WARNING)
# create formatter
formatter = logging.Formatter(%(asctime)s - %(name)s - %(levelname)s - %(message)s‘)
 
# add formatter to ch and fh
ch.setFormatter(formatter)
fh.setFormatter(formatter)
 
# add ch and fh to logger
logger.addHandler(ch)
logger.addHandler(fh)
 
# ‘application‘ code
logger.debug(‘debug message‘)
logger.info(‘info message‘)
logger.warn(‘warn message‘)
logger.error(‘error message‘)
logger.critical(‘critical message‘)
import logging

from logging import handlers

logger = logging.getLogger(__name__)

log_file = "timelog.log"
#fh = handlers.RotatingFileHandler(filename=log_file,maxBytes=10,backupCount=3)
fh = handlers.TimedRotatingFileHandler(filename=log_file,when="S",interval=5,backupCount=3)


formatter = logging.Formatter(%(asctime)s %(module)s:%(lineno)d %(message)s‘)

fh.setFormatter(formatter)

logger.addHandler(fh)


logger.warning("test1")
logger.warning("test12")
logger.warning("test13")
logger.warning("test14")

Python學習記錄day5