python入門_模塊2

1、random模塊python

(0, 1):random.random()
[1, 10]:random.randint(1, 10)
[1, 10):random.randrange(1, 10)
(1, 10):random.uniform(1, 10)
單例集合隨機選擇1個:random.choice(item)
單例集合隨機選擇n個:random.sample(item, n)
洗牌單列集合:random.shuffle(item)

import random
#模塊地址
print(random) # <module 'random' from 'F:\\安裝包\\Python36\\lib\\random.py'>

#random.random()取值範圍0-1之間的小數,不包含0和1
for i in range(2):
    print(random.random())  #(0,1)
#取值0-2之間,可是random.random()輸出的值都是0-1之間
#0.6179348878875671
#0.7546476092920288


#random.randint()  取值範圍[1,5]:包含1和5
for i in range(5):
    print(random.randint(1,5))  #[1,5]

# random.randrange()  #[1,5)取值範圍1-4,不包含5
for i in range(5):
    print(random.randrange(1,5))  #[1,4]

# random.uniform()  取值範圍(1,5)之間的小數
for i in range(5):
    print(random.uniform(1,5))  #小數:(1,5)
#     print('%.3f' % random.uniform(1,5))  #%f 能夠定義取值的長度 %.3f取3位小數

#洗牌單列集合:random.shuffle(item)
ls = [1,2,3,4,5]
print(random.shuffle(ls)) #None
print(ls) #對ls隨機排序[4, 5, 2, 3, 1]

#單例集合隨機選擇1個:random.choice(item)
print(random.choice(ls))  # 隨機輸出ls中一個值

#單例集合隨機選擇n個:random.sample(item, n)
print(random.sample(ls,3))  # [2, 4, 3]  不會同時出現2個同樣的數字
練習:驗證碼功能
# 方法一
# count驗證碼位數,根據需求出幾位
import random
def get_code(count):
    code = ""
    # 能產生大小寫字母和數字
    # 進行字符串拼接
    for i in range(count):
        c1 = chr(random.randint(65,90))  #(65,90)  ascii表對應大寫字母,chr對應數字轉換爲字母
        c2 = chr(random.randint(97,122)) #(97,122) ascii表對應小寫字母
        c3 = str(random.randint(0,9))    # 數字

        code += random.choice([c1,c2,c3])
    return code

print(get_code(4))

# 方法二:效率高,只須要循環2個,但邏輯多
def get_code(count):
    code = ""
    for i in range(count):
        r = random.choice([1,2 ,3])
        if r == 1:
            c = chr(random.randint(65,90))
        elif r == 2:
            c = chr(random.randint(97,122))
        else:
            c = str(random.randint(0,9))
        code += c
    return code

print(get_code(6)) # d7H7C3

# 第3中方法:將全部字母數字的選項都寫在一塊兒,每次選中都不會重複
def get_code(count):
    target = "1234567890QWERTYUIOPASDFGHJKLZXCVBNMwqertiuopadsfklzvcxbnm"
    code_list = random.sample(target,count)
    return ''.join(code_list) #3PqXiR82
    return code_list  #['p', '1', 'S', '9', 'c', 's', 'k', 'A']
print(get_code(18))  #Kv47ZiznkPD0eO3I5d

2、序列化模塊正則表達式

# 什麼是序列化:將對象轉化爲字符串
# 什麼是反序列化:將字符串轉化爲對象
# 爲何要序列化:數據的存儲和傳輸都採用的是字符串類型
# 序列化的模塊:json pickle shelve

# json:支持跨語言,用於數據的傳輸
# pickle:支持py的全部數據類型,全部能夠將全部py的對象序列化後存儲
# shelve:支持py的全部數據類型,能夠即時存與取

# 序列化
dump
dumps

# 反序列化
load
loads

三.Json模塊:用於傳輸(多語言支持)shell

什麼是json:就是完成文本序列化獲得的文本字符串,json字符串具備必定的語法規範

1.支持的數據類型:int float str bool dict list null   # json中布爾類型轉換爲小寫,不支持set 和tuple
2.複雜的json都是由{}與[]嵌套造成的數據
3.json字符串只能有一個根: json_str = '{}{}' | '{}[]' | '[][]' | '1null'  # 報錯,都是兩個根
4.json中的str類型必須用""包裹(json字符串中的字符串類型不支持'' """""")
import json

# python對象 序列化 json字符串
data = None
res = json.dumps(data)
print(res)

# json字符串 反序列化 python對象
json_str = '3.14'
json_str = 'true'
json_str = 'null'
json_str = '{}'
json_str = '[]'
json_str = '1, null'  # 有誤,兩個根

json_str = "\"abc\""  #反序列化去引號
json_str = '"abc"'
obj = json.loads(json_str)
print(obj, type(obj))
操做文件:讀()存與寫(取)
#
序列化 obj = {'name': 'Simon', 'age': 17, 'gender': ''} with open('a.txt', 'w', encoding='utf-8') as wf: json.dump(obj, wf, ensure_ascii=False) # ensure_ascii 默認爲True ansci碼;#False跟隨文件編碼utf-8 # json.dump(obj, wf) #{"name": "Simon", "age": 17, "gender": "男"}{"name": "Simon", "age": 17, "gender": "\u7537"} # 文件內容123456:由於wf文件只打開一次,打開的時候操做一次,以後都是寫 # wf.write('123') # wf.write('456') # 反序列化 with open('a.txt', 'r', encoding='utf-8') as rf: obj = json.load(rf) print(obj) # {'name': 'Simon', 'age': 17, 'gender': '男'} # 注:json模塊的序列化與反序列化是一一對應關係 print(json.load(open('a.txt', 'r', encoding='utf-8'))) # {'name': 'Simon', 'age': 17, 'gender': '男'}

4、 pickle模塊:支持全部數據類型(不支持其餘語言,只用於python)編程

import pickle
obj = {'name': 'simon', 'age': 17, 'gender': ''}
res = pickle.dumps(obj)
print(res)
# b'\x80\x03}q\x00(X\x04\x00\x00\x00nameq\x01X\x05\x00\x00\x00simonq\x02X\x03\x00\x00\x00ageq\x03K\x11X\x06\x00\x00\x00genderq\x04X\x03\x00\x00\x00\xe7\x94\xb7q\x05u.'

pickle.dump(obj,open('b.txt','wb'))
#內容: �}q (X   nameqX   simonqX   ageqKX   genderqX   男qu.

# 反序列化
print(pickle.loads(res)) # {'name': 'simon', 'age': 17, 'gender': '男'}
print(pickle.load(open('b.txt', 'rb'))) # {'name': 'simon', 'age': 17, 'gender': '男'}

5、shelve模塊:支持全部數據類型(優化存與取的方式)json

# shelve將dump與load封裝爲一步
import shelve
# 將文件的方法封裝到模塊中,文件後綴本身隨便取的
#新建了3個文件:c.shv.bak c.shv.dat c.shv.dir
shv_tool = shelve.open('c.shv')

# 序列化
# shv_tool['name'] = 'Simon'

# 反序列化
res = shv_tool['name']
print(res) # Simon

shv_tool.close()
# 文件經過shelve對象來關閉,關閉後就不能再取,不然就報錯

#  二次操做:從新打開與關閉
shv_tool = shelve.open('c.shv')
print(shv_tool['name']) # Simon
shv_tool.close()

# 操做方式
with shelve.open('c.shv') as shv_tool:
    print(shv_tool['name']) # Simon

# writeback將反序列化到內存的數據,操做後即時同步到文件中
with shelve.open('c.shv', writeback=True) as shv_tool:
    shv_tool['stus'] = ['Bob', 'Tom']  # 重置
    # print(shv_tool['stus'])  # ['Bob', 'Tom']

    shv_tool['stus'].append('Jobs')  #  將數據取到內存,在內存中添加
    print(shv_tool['stus']) # ['Bob', 'Tom', 'Jobs']

6、shutil:能夠操做權限的處理文件模塊windows

import shutil

# 基於路徑的文件複製:
shutil.copyfile('source_file', 'target_file')
# 絕對路徑:複製後的文件名是須要的
shutil.copyfile(r'C:\shelev.py',r'D:\target.py')

# 基於流的文件複製:
with open('source_file', 'rb') as r, open('target_file', 'wb') as w:
    shutil.copyfileobj(r, w)
    
# 遞歸刪除目標目錄:目錄裏有文件也直接刪除
shutil.rmtree('target_folder')

# 文件移動
shutil.remove('old_file', 'new_file')

# 文件夾壓縮
# file_name: 壓縮後獲得的文件名  format:壓縮格式  archive_path:要壓縮的文件夾路徑
shutil.make_archive('file_name', 'format', 'archive_path')
# 舉例
shutil.make_archive('target/abc', 'zip', 'source') #在target 目錄中將source目錄壓縮到target目錄中名爲abc.zip

# 文件夾解壓
# unpack_file: 解壓的文件  unpack_name:解壓獲得的文件夾名  format:解壓格式
shutil.unpack_archive('unpack_file', 'unpack_name', 'format')
# 舉例
shutil.unpack_archive('target/abc.zip', 'target/xyz', 'zip') #將abc.zip解壓爲xyz文件夾

 7、加密模塊app

# 通常加密解密方法:
# md5加密:不可逆加密
# 碰撞解密:用數據再進行一次加密,與原加密結果作匹配

hashlib模塊加密dom

import hashlib

data = '數據'  # 生成對象
lock_obj = hashlib.md5(data.encode('utf-8'))  # 生產加密鎖對象,傳入加密數據
result = lock_obj.hexdigest()  # 獲取加密後的加密串
print(result)

# update能夠往鎖對象中添加加密數據
lock_obj = hashlib.md5()
lock_obj.update(b'123')
lock_obj.update(b'abc')
lock_obj.update('嘿嘿'.encode('utf-8'))
print(lock_obj.hexdigest())

lock_obj.update(b'000')
print(lock_obj.hexdigest())  # 000 | '123abc嘿嘿000'.encode('utf-8')

print(hashlib.md5('123abc嘿嘿000'.encode('utf-8')).hexdigest())
# 注:要爲新數據提供加密,必定要爲該數據建立一個加密對象
# 加鹽:前提是支持update
# 什麼是加鹽:在原數據前或後添加一些預約的數據,與原數據一塊兒進行加密
# 爲何要加鹽:
# 1.當原數據過於簡單,能夠對其加鹽,提升數據的複雜度
# 2.鹽與數據有必定類似度,混淆對真實數據的提取

data = 'ab_12'
lock_obj = hashlib.md5()
lock_obj.update(b'a12_d')
lock_obj.update(data.encode('utf-8'))
lock_obj.update(b'dd_121')
print(lock_obj.hexdigest())
# a12_dab_12dd_121在數據先後加鹽混淆

# 其餘位數加密
lock_obj = hashlib.sha3_256(b'123')
print(lock_obj.hexdigest())
lock_obj = hashlib.sha3_512(b'123')
lock_obj.update(b'salt')
print(lock_obj.hexdigest())

hmac模塊加密編程語言

import hmac
# 與hashlib的不一樣點:生產鎖對象時必須提升數據參數
lock_obj = hmac.new(b'')
print(lock_obj.hexdigest())

# 支持加鹽 lock_obj
= hmac.new(b'') lock_obj.update(b'salt') print(lock_obj.hexdigest())

 8、logging:日誌模塊ide

# logging記錄項目日誌的模塊
# 記錄日誌:將項目中產生的一些數據,或是信息,或是錯誤再也不輸出到控制檯,而是輸出到文件中,保存這樣信息的文件就稱之爲日誌文件
# 日誌級別
在開始記錄日誌前還須要明確,日誌的級別

隨着時間的推移,日誌記錄會很是多,成千上萬行,如何快速找到須要的日誌記錄這就成了問題

解決的方案就是 給日誌劃分級別
logging模塊將日誌分爲了五個級別,從高到低分別是: 1.info 常規信息
2.debug 調試信息
3.warning 警告信息(默認級別)
4.error 錯誤信息
5.cretical 嚴重錯誤

本質上他們使用數字來表示級別的,從高到低分別是10,20,30,40,50
#1.導入模塊
import logging

#2.輸出日誌
logging.info("info")
logging.debug("debug調試")
logging.warning("warning警告")
logging.error("error錯誤")
logging.critical("critical嚴重錯誤")

# 輸出 WARNING:root:warning
# 輸出 ERROR:root:error
# 輸出 CRITICAL:root:critical

1.logging模塊的基本配置使用:

import logging
import sys

# 2.日誌的基本配置
logging.basicConfig(
    # 輸出級別
    level=logging.INFO,
    # level=10,

    # 輸出位置
    # stream=sys.stderr,  # sys.stdout  往控制檯輸出
    filename='log/my.log',  # 往文件輸出  => 若是須要同時往多個位置輸出,須要handles

    # 輸出格式
    format='%(asctime)s[%(name)s]: %(msg)s',
    datefmt='%Y-%m-%d %H:%M:%S'
)
# my.log日誌:2019-05-16 14:39:32[root]: error msg
# 標準輸入 # print(sys.stdin.readline())

# filename:用指定的文件名建立FiledHandler(後邊會具體講解handler的概念),這樣日誌會被存儲在指定的文件中。
# filemode:文件打開方式,在指定了filename時使用這個參數,默認值爲「a」還可指定爲「w」。
# format:指定handler使用的日誌顯示格式。 
# datefmt:指定日期時間格式。 
# level:設置rootlogger(後邊會講解具體概念)的日誌級別 

#案例:
logging.basicConfig(
    filename="aaa.log",
    filemode="at",
    datefmt="%Y-%m-%d %H:%M:%S %p",
    format="%(asctime)s - %(name)s - %(levelname)s - %(module)s: %(message)s",
    level=10
)

格式化所有可用名稱:

%(name)s:Logger的名字,並不是用戶名,詳細查看
%(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:用戶輸出的消息

2.logging的成員組成

 

logging模塊的四個核心角色:
1.Logger   日誌生成器 產生日誌
2.Filter    日誌過濾器  過濾日誌
3.Handler 日誌處理器 對日誌進行格式化,並輸出到指定位置(控制檯或文件)
4.Formater 處理日誌的格式
import logging

# 1.打印者:自定義的打印者如何配置
log1 = logging.getLogger('logger name')

# 2.輸出位置:兩個文件輸出位置與一個控制檯輸出位置
hd_a = logging.FileHandler('log/a.log', encoding='utf-8')
hd_cmd = logging.StreamHandler()

# 3.輸出格式
fmt1 = logging.Formatter('%(asctime)s 【%(name)s】- %(msg)s')
fmt2 = logging.Formatter('%(asctime)s - %(msg)s')

# 4.打印者添加句柄 - 設置打印者的輸出位置
log1.addHandler(hd_a)
log1.addHandler(hd_cmd)

# 5.將格式綁定給輸出位置(句柄)
hd_a.setFormatter(fmt1)
hd_cmd.setFormatter(fmt2)

# 6.權限控制
log1.setLevel(logging.DEBUG)  # 打印者規定打印級別
hd_a.setLevel(logging.WARNING)  # 不一樣輸出位置(句柄)再能夠二次限定輸出級別
hd_cmd.setLevel(logging.DEBUG)  # 不一樣輸出位置(句柄)再能夠二次限定輸出級別

# 7.不一樣級別輸出信息
log1.debug('debug msg')
log1.info('info msg')
log1.warning('warning msg')
log1.error('error msg')
log1.critical('critical msg')
import logging
# root打印者,用logging.basicConfig來配置
# logging.critical('12345')

# 1.打印者:自定義的打印者如何配置
log1 = logging.getLogger('Owen')
# log1.critical('67890')

log2 = logging.getLogger('Simon')
# log2.critical('00000')

# 2.輸出位置:兩個文件輸出位置與一個控制檯輸出位置
hd_a = logging.FileHandler('log/a.log', encoding='utf-8')
hd_b = logging.FileHandler('log/b.log', encoding='utf-8')
hd_cmd = logging.StreamHandler()  #控制檯輸出

# )) 爲輸出者綁定輸出位置
log1.addHandler(hd_a)
log1.addHandler(hd_b)

log2.addHandler(hd_b)
log2.addHandler(hd_cmd)

# 3.輸出格式
fmt1 = logging.Formatter('%(asctime)s 【%(name)s】- %(msg)s')
fmt2 = logging.Formatter('%(asctime)s - %(msg)s')

# ))將格式綁定給輸出位置(句柄)
hd_a.setFormatter(fmt1)
hd_b.setFormatter(fmt1)
hd_cmd.setFormatter(fmt2)

# 級別控制: 打印者規定打印級別,輸出位置(句柄)再能夠二次限定,級別>=打印者級別
log2.setLevel(logging.DEBUG)
hd_b.setLevel(logging.WARNING)
hd_cmd.setLevel(logging.DEBUG)

log2.debug('debug msg')
log2.info('info msg')
log2.warning('warning msg')
log2.error('error msg')
log2.critical('critical msg')

# 4.輸出
log1.critical('log1 輸出的 critical msg')
log2.critical('log2 輸出的 critical msg')

# 過濾:少用
# logging.Filter
多日誌多級別輸出

 3.logging配置文件項目開發運用

# 1.將打印者,句柄,與格式封裝成配置信息
# 2.加載配置信息
# 3.使用自定義logger,採用的就是配置信息設置的logger

# 優點:1,2兩步是一勞永逸的,後期開發只須要在要記錄日誌的文件中使用自定義logger
# 1、基礎配置:目錄conf/setting.py
LOGGING_DIC = {
    'version': 1,
    'disable_existing_loggers': False, #讓系統的默認配置失效
    'formatters': {
        # 名稱格式定義
        'o_fmt1': {
            'format': '%(asctime)s 【%(name)s】- %(msg)s'
        },
        'o_fmt2': {
            'format': '%(asctime)s - %(msg)s'
        }
    },
    'filters': {},
    'handlers': {
        'o_hd_file': {
            'level': 'WARNING',
            'class': 'logging.handlers.RotatingFileHandler',  # 打印到控制檯
            'formatter': 'o_fmt1',
            'filename': 'log/sys.log',
            'encoding': 'utf-8',
            'maxBytes': 1024*1024*5,  # 日誌大小5M
            'backupCount': 5,   # 文件切分:寫滿一個就更名爲sys1.log,寫滿5個清空從新記錄
        },
        'o_hd_cmd': {
            'level': 'DEBUG',
            'class': 'logging.StreamHandler',  # 打印到控制檯
            'formatter': 'o_fmt2'
        }
    },
    'loggers': {
        'o_owen': {
            'level': 'DEBUG',
            'handlers': ['o_hd_file', 'o_hd_cmd']
        },
        'o_simon': {
            'level': 'DEBUG',
            'handlers': ['o_hd_cmd'],
            # 'propagate': True  # 向更高的level logging傳遞
        }
    }
}

# 2、加載配置
import logging.config
logging.config.dictConfig(LOGGING_DIC)


# 3、使用
log = logging.getLogger('o_simon')
log.critical('信息')

log1 = logging.getLogger('o_owen')
log1.critical('信息')

# 目錄:lib/common.py
from conf.settings import LOGGING_DIC
import logging.config
logging.config.dictConfig(LOGGING_DIC)

def getLogger(name):
    return logging.getLogger(name)
測試:
from lib.common import getLogger
log = getLogger('o_owen')

log.debug('12345')
log.critical('67890')
standard_format = '[%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d]' \
                  '[%(levelname)s][%(message)s]' #其中name爲getlogger指定的名字

simple_format = '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s'

id_simple_format = '[%(levelname)s][%(asctime)s] %(message)s'
logfile_path = "配置文件路徑"

LOGGING_DIC = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'standard': {
            'format': standard_format
        },
        'simple': {
            'format': simple_format
        },
    },
    'filters': {},
    'handlers': {
        #打印到終端的日誌
        'console': {
            'level': 'DEBUG',
            'class': 'logging.StreamHandler',  # 打印到屏幕
            'formatter': 'simple'
        },
        #打印到文件的日誌,收集info及以上的日誌
        'default': {
            'level': 'DEBUG',
            'class': 'logging.handlers.RotatingFileHandler',  # 保存到文件
            'formatter': 'standard',
            'filename': logfile_path,  # 日誌文件
            'maxBytes': 1024*1024*5,  # 日誌大小 5M
            'backupCount': 5, #日誌文件最大個數
            'encoding': 'utf-8',  # 日誌文件的編碼
        },
    },
    'loggers': {
        #logging.getLogger(__name__)拿到的logger配置
        'aa': {
            'handlers': ['default', 'console'],  # 這裏把上面定義的兩個handler都加上,即log數據既寫入文件又打印到屏幕
            'level': 'DEBUG',
            'propagate': True,  # 向上(更高level的logger)傳遞
        },
        # 把key設置爲空
        '': {
            'handlers': ['default', 'console'],  # 這裏把上面定義的兩個handler都加上,即log數據既寫入文件又打印到屏幕
            'level': 'DEBUG',
            'propagate': True,  # 向上(更高level的logger)傳遞
        },
    },
}
標準代碼
#lib/common.py
#日誌功能
import logging.config
from conf import settings

# 在lib 文件夾的common文件中生成日誌對象
#生成日誌對象
def get_logger(name):
    # 先把日誌配置傳給logging
    logging.config.dictConfig(settings.LOGGING_DIC)
    # 生產日誌對象--》接收的是name,根據name打印相應的日誌
    my_logger = logging.getLogger(name)
    return my_logger


# conf/settings.py
import os

# test目錄
BASE_PATH = os.path.dirname(os.path.dirname(__file__))
# test/db目錄
DB_PATH = os.path.join(BASE_PATH, 'db')


# 日誌配置文件
'''
logging 配置
'''
import os
standard_format = '[%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d]' \
                  '[%(levelname)s][%(message)s]' #其中name爲getlogger指定的名字

simple_format = '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s'

id_simple_format = '[%(levelname)s][%(asctime)s] %(message)s'

# 日誌目錄
LOG_PATH = os.path.join(BASE_PATH,'log')
log_filename = 'Atm_Shop.log'

if not os.path.isdir(LOG_PATH):
    os.mkdir(LOG_PATH)

# log文件全路徑
logfile_path = os.path.join(LOG_PATH,log_filename)


LOGGING_DIC = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'standard': {
            'format': standard_format
        },
        'simple': {
            'format': simple_format
        },
    },
    'filters': {},
    'handlers': {
        #打印到終端的日誌
        'console': {
            'level': 'DEBUG',
            'class': 'logging.StreamHandler',  # 打印到屏幕
            'formatter': 'simple'
        },
        #打印到文件的日誌,收集info及以上的日誌
        'default': {
            'level': 'DEBUG',
            'class': 'logging.handlers.RotatingFileHandler',  # 保存到文件
            'formatter': 'standard',
            'filename': logfile_path,  # 日誌文件
            'maxBytes': 1024*1024*5,  # 日誌大小 5M
            'backupCount': 5, #日誌文件最大個數
            'encoding': 'utf-8',  # 日誌文件的編碼
        },
    },
    'loggers': {
        #logging.getLogger(__name__)拿到的logger配置
        'aa': {
            'handlers': ['default', 'console'],  # 這裏把上面定義的兩個handler都加上,即log數據既寫入文件又打印到屏幕
            'level': 'DEBUG',
            'propagate': True,  # 向上(更高level的logger)傳遞
        },
        # 把key設置爲空
        '': {
            'handlers': ['default', 'console'],  # 這裏把上面定義的兩個handler都加上,即log數據既寫入文件又打印到屏幕
            'level': 'DEBUG',
            'propagate': True,  # 向上(更高level的logger)傳遞
        },
    },
}


# 引用
from lib import common
# 獲取銀行日誌功能
bank_log = common.get_logger('bank')

bank_log.info('%s提現%s元成功,手續費爲%s' % (user, money2,money3))
標準代碼2

9、re模塊

# re:正則,全稱正則字符串 - re就是有特殊語法的字符串
# re能夠將有正則語法的字符串解析爲對應的正則對象,用來匹配目標字符串

# 學習re的目的:1.判斷目標字符串是否合法 2.在目標字符串中提取想要的信息(信息匹配規則採用正則)
import re

# 從123abc123中查找1
r1 = re.findall(r'1', '123abc123')
print(r1) # ['1', '1']

r2 = re.findall(r'a', '123abc123ABC', flags=re.I) # re.I 不區分大小寫匹配
print(r2) # ['a', 'A']

# 1.將 r'\d' 丟給_compile獲得能夠匹配數字的 正則對象
# 2.正則對象.findall('目標字符串')
r3 = re.findall(r'\d', '123abc123')
print(r3) # ['1', '2', '3', '1', '2', '3']

re_obj = re.compile(r'\d')  # 將 r'\d' 丟給_compile獲得能夠匹配數字的 正則對象
r4 = re_obj.findall('123abc123')  # 正則對象.findall('目標字符串')
print(r4) # ['1', '2', '3', '1', '2', '3']

正則語法

單個字符語法:

import re

# 1、單個字符語法
# 匹配a
print(re.findall(r'a', '123abc嘿嘿'))  # ['a']

# a或b
print(re.findall(r'a|b', '123abc嘿嘿'))  # ['a', 'b'] 不建議使用
print(re.findall(r'[ab]', '123abc嘿嘿'))  # ['a', 'b'] 建議使用

# 非a非b
print(re.findall(r'[^ab]', '123abc嘿嘿'))  # ['1', '2', '3', 'c', '嘿', '嘿']

# 數字
print(re.findall(r'[0-9]', '12abc嘿嘿12'))  # ['1', '2', '1', '2'] 建議使用
print(re.findall(r'\d', '12abc嘿嘿12'))  # ['1', '2', '1', '2'] 不建議使用

# 字母
print(re.findall(r'[a-zA-Z]', '12abc[嘿嘿ABC'))  # ['a', 'b', 'c', 'A', 'B', 'C']

# 字母數字_經常使用漢字:\w => 建議使用 [a-zA-Z0-9_]
print(re.findall(r'\w', '12abc[_嘿嘿ABC'))  # ['1', '2', 'a', 'b', 'c', '_', '嘿', '嘿', 'A', 'B', 'C']

# 漢字 [\u4e00-\u9fa5]表明漢字
print(re.findall(r'[\u4e00-\u9fa5]', '12abc[_嘿嘿ABC'))  # ['嘿', '嘿']

# 空白字符:\s => 建議使用[ \f\n\r\t\v]
print(re.findall(r'\s', ' \f\n\r\t\v'))  # [' ', '\x0c', '\n', '\r', '\t', '\x0b']

# 非\n的任意字符: .
print(re.findall(r'.', ' \f\n\r\t\v*&_.'))  # [' ', '\x0c', '\r', '\t', '\x0b', '*', '&', '_', '.']

# 只想匹配.字符:\.
print(re.findall(r'\.', ' \f\n\r\t\v*&_.'))  # ['.']

# re.S: 讓.也能匹配\n,就能夠理解爲 . 能夠匹配全部字符
print(re.findall(r'.', ' \f\n\r\t\v*&_.', flags=re.S))

# 取對立面 \d數字 \D非數字  \w=>\W  \s=>\S
print(re.findall(r'\D', '12abc\f嘿嘿12'))  # ['a', 'b', 'c', '\x0c', '嘿', '嘿']

 重複字符語法:

print(re.findall(r'ab', 'abacbabc'))  # ['ab', 'ab']

# 指定個數: 匹配abb
print(re.findall(r'ab{2}', 'aababbabbb'))  # ['abb', 'abb']

# 貪婪匹配: 儘量多的匹配
# a0~2個b: a | ab | abb
print(re.findall(r'ab{,2}', 'aababbabbb'))  # ['a', 'ab', 'abb', 'abb']

# a0~n個b:
print(re.findall(r'ab{0,}', 'aababbabbb'))  # ['a', 'ab', 'abb', 'abbb']

# a1~3個b:
print(re.findall(r'ab{1,3}', 'aababbabbb'))  # ['ab', 'abb', 'abbb']

# *: {0,}
print(re.findall(r'ab*', 'aababbabbb'))  # ['a', 'ab', 'abb', 'abbb']
# +: {1,}
print(re.findall(r'ab+', 'aababbabbb'))  # ['ab', 'abb', 'abbb']
# ?: {,1}
print(re.findall(r'ab?', 'aababbabbb'))  # ['a', 'ab', 'ab', 'ab']

# 非貪婪匹配
print(re.findall(r'ab{1,3}?', 'aababbabbb'))  # ['ab', 'ab', 'ab']

# 重點:非貪婪匹配應用場景,通常都是結合有開頭與結尾的標識
print(re.findall(r'<.{1,}>', '<a><b>msg</b></a>'))  # ['<a><b>msg</b></a>']
# 匹配標籤
print(re.findall(r'<.{1,}?>', '<a><b>msg</b></a>'))  # ['<a>', '<b>', '</b>', '</a>']

# *?: {0,}?
# +?: {1,}?
# ??: {,1}?
print(re.findall(r'<.+?>', '<a><b>msg</b></a>'))  # ['<a>', '<b>', '</b>', '</a>']

 分組語法:

# 引子
print(re.findall(r'(?:ab){2}', 'abbabab'))  # ['abab']

# findall(): 沒有分組狀況下,顯示匹配的結果;若是有分組,顯示分組結果

# 分組:()
# 取消分組:(?:)
# 有名分組:(?P<名字>)

# 案例:
# 匹配連接
print(re.findall(r'www\..+?\.com', 'www.baidu.comabcwww.sina.com'))  # ['www.baidu.com', 'www.sina.com']
# 獲取連接的域名:['baidu', 'sina']
print(re.findall(r'www\.(.+?)\.com', 'www.baidu.comabcwww.sina.com'))  # ['baidu', 'sina']

# 分組編號: 從左往右數左(進行分組編號
# [('www.baidu.com', 'baidu', 'com'), ('www.sina.edu', 'sina', 'edu')]
res = re.findall(r'(www\.(.+?)\.(com|edu))', 'www.baidu.comabcwww.sina.edu')
print(res)
print(res[0][1])

# 取消分組:(?:) 應用於,要將一些數據做爲總體看待,但由不能產生分組
# [('www.baidu.com', 'baidu'), ('www.sina.edu', 'sina')]
res = re.findall(r'(www\.(.+?)\.(?:com|edu))', 'www.baidu.comabcwww.sina.edu')
print(res)

其餘正則方法的使用:

# match:不是全文匹配,必須從頭開始匹配,且只匹配一次
res = re.match(r'(www\.(?P<site_name>.+?)\.(?:com|edu))', 'www.baidu.comwww.sina.edu')
# 能夠經過分組號直接取出分組內容
print(res.group(1))
print(res.group(2))
# print(res.group(0), res)  # 匹配的總體

# 有名分組
print(res.group('site_name'))

# split(): 拆分
print('abc def xyz'.split(' '))
print(re.split(r' ', 'abc def xyz'))
print(re.split(r'[,@ ]', 'abc,def@xyz opq'))


# sub(): 替換
res = re.sub(r'good', 'bed', 'good good day a')
print(res)  # bed bed day a

res = re.sub(r'good', 'bed', 'good good day a', count=1)
print(res)  # bed good day a

res = re.sub(r'good day a', '123', 'good day a!!!')
print(res)  # 123!!!

# 結合分組能夠完成數據的重組
res = re.sub(r'(good) (day) (a)', r'today is \3 \1 \2', 'good day a!!!')
print(res)  # today is a good day!!!
元字符 描述
\ 將下一個字符標記符、或一個向後引用、或一個八進制轉義符。例如,「\n」匹配\n。「\n」匹配換行符。序列「\」匹配「\」而「(」則匹配「(」。即至關於多種編程語言中都有的「轉義字符」的概念。
^ 匹配輸入字行首。若是設置了RegExp對象的Multiline屬性,^也匹配「\n」或「\r」以後的位置。
$ 匹配輸入行尾。若是設置了RegExp對象的Multiline屬性,$也匹配「\n」或「\r」以前的位置。
* 匹配前面的子表達式任意次。例如,zo能匹配「z」,也能匹配「zo」以及「zoo」。等價於{0,}。
+ 匹配前面的子表達式一次或屢次(大於等於1次)。例如,「zo+」能匹配「zo」以及「zoo」,但不能匹配「z」。+等價於{1,}。
{n} n是一個非負整數。匹配肯定的n次。例如,「o{2}」不能匹配「Bob」中的「o」,可是能匹配「food」中的兩個o。
{n,} n是一個非負整數。至少匹配n次。例如,「o{2,}」不能匹配「Bob」中的「o」,但能匹配「foooood」中的全部o。「o{1,}」等價於「o+」。「o{0,}」則等價於「o*」。
{n,m} mn均爲非負整數,其中n<=m。最少匹配n次且最多匹配m次。例如,「o{1,3}」將匹配「fooooood」中的前三個o爲一組,後三個o爲一組。「o{0,1}」等價於「o?」。請注意在逗號和兩個數之間不能有空格。
? 匹配前面的子表達式零次或一次。例如,「do(es)?」能夠匹配「do」或「does」。?等價於{0,1}。
? 當該字符緊跟在任何一個其餘限制符(,+,?,{n},{n,},{n,m*})後面時,匹配模式是非貪婪的。非貪婪模式儘量少地匹配所搜索的字符串,而默認的貪婪模式則儘量多地匹配所搜索的字符串。例如,對於字符串「oooo」,「o+」將盡量多地匹配「o」,獲得結果[「oooo」],而「o+?」將盡量少地匹配「o」,獲得結果 ['o', 'o', 'o', 'o']
.點 匹配除「\n」和"\r"以外的任何單個字符。要匹配包括「\n」和"\r"在內的任何字符,請使用像「[\s\S]」的模式。
   
x|y 匹配x或y。例如,「z|food」能匹配「z」或「food」(此處請謹慎)。「[zf]ood」則匹配「zood」或「food」。
[xyz] 字符集合。匹配所包含的任意一個字符。例如,「[abc]」能夠匹配「plain」中的「a」。
[^xyz] 負值字符集合。匹配未包含的任意字符。例如,「abc」能夠匹配「plain」中的「plin」任一字符。
[a-z] 字符範圍。匹配指定範圍內的任意字符。例如,「[a-z]」能夠匹配「a」到「z」範圍內的任意小寫字母字符。注意:只有連字符在字符組內部時,而且出如今兩個字符之間時,才能表示字符的範圍; 若是出字符組的開頭,則只能表示連字符自己.
[^a-z] 負值字符範圍。匹配任何不在指定範圍內的任意字符。例如,「a-z」能夠匹配任何不在「a」到「z」範圍內的任意字符。
\b 匹配一個單詞的邊界,也就是指單詞和空格間的位置(即正則表達式的「匹配」有兩種概念,一種是匹配字符,一種是匹配位置,這裏的\b就是匹配位置的)。例如,「er\b」能夠匹配「never」中的「er」,但不能匹配「verb」中的「er」;「\b1」能夠匹配「1_23」中的「1」,但不能匹配「21_3」中的「1_」。
\B 匹配非單詞邊界。「er\B」能匹配「verb」中的「er」,但不能匹配「never」中的「er」
\s 匹配任何不可見字符,包括空格、製表符、換頁符等等。等價於[ \f\n\r\t\v]。
\S 匹配任何可見字符。等價於 \f\n\r\t\v
\w 匹配包括下劃線的任何單詞字符。相似但不等價於「[A-Za-z0-9_]」,這裏的"單詞"字符使用Unicode字符集。
\W 匹配任何非單詞字符。等價於「A-Za-z0-9_」。
\d 匹配一個數字字符。等價於[0-9]。grep 要加上-P,perl正則支持
\D 匹配一個非數字字符。等價於0-9。grep要加上-P,perl正則支持
\n 匹配一個換行符。等價於\x0a和\cJ。
\r 匹配一個回車符。等價於\x0d和\cM。
\t 匹配一個製表符。等價於\x09和\cI。
( ) 將( 和 ) 之間的表達式定義爲「組」(group),而且將匹配這個表達式的字符保存到一個臨時區域(一個正則表達式中最多能夠保存9個),它們能夠用 \1 到\9 的符號來引用。
(?:pattern) 非獲取匹配,匹配pattern但不獲取匹配結果,不進行存儲供之後使用。這在使用或字符「(|)」來組合一個模式的各個部分時頗有用。例如「industr(?:y|ies)」就是一個比「industry|industries」更簡略的表達式。
| 將兩個匹配條件進行邏輯「或」(Or)運算。例如正則表達式(him|her) 匹配"it belongs to him"和"it belongs to her",可是不能匹配"it belongs to them."。注意:這個元字符不是全部的軟件都支持的。

 

10、shell腳本之subprocess模塊

#Popen
order = subprocess.Popen('dir',
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)

res = order.stdout.read().decode('gbk')
print(res)

print('==============================')

res = order.stderr.read().decode('gbk')
print(res)
# 舉例
# windows下測試列出目錄文件
# run
import subprocess
order = subprocess.run('dir',
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)

res = order.stdout.decode('gbk')
print(res)

print('==============================')
# stderr 輸出錯誤
res = order.stderr.decode('gbk')
print(res)
#Centos系統
>>> a = subprocess.call(['df','-lh'],shell=False)
Filesystem      Size  Used Avail Use% Mounted on
/dev/vda1        40G  9.0G   29G  25% /
/dev/vdb         99G   16G   78G  18% /db
tmpfs           783M     0  783M   0% /run/user/1000

>>> r1=subprocess.getstatusoutput("dir")
>>> r1
(0, 'lova  test.sh')

>>> r2 = subprocess.Popen('ping -c2 www.baidu.com',shell=True)
>>> PING www.a.shifen.com (115.239.210.27) 56(84) bytes of data.
64 bytes from 115.239.210.27 (115.239.210.27): icmp_seq=1 ttl=54 time=8.59 ms
64 bytes from 115.239.210.27 (115.239.210.27): icmp_seq=2 ttl=54 time=8.64 ms

--- www.a.shifen.com ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3004ms
rtt min/avg/max/mdev = 8.595/8.621/8.648/0.094 ms

>>> subprocess.Popen('./test.sh',shell=True)
<subprocess.Popen object at 0x7f2c51f10160>
>>> Hello World!

>>> res = subprocess.Popen('./test.sh',stdout = subprocess.PIPE,shell=True,stderr=subprocess.PIPE)
>>> res1 = res.stdout.read()
>>> res1
b'Hello World!\n'
>>> print(res1)
b'Hello World!\n'

12、configparser 模塊

# my.ini 配置文件讀寫
"""
[server]
ip = 192.168.66.88
port = 3306

[client]
user = root
password = root
"""

import configparser

# 1.初始化
parser = configparser.ConfigParser()

# 2.讀
parser.read('my.ini', encoding='utf-8')
# section | option | value
# 讀取列表
sts = parser.sections()
print(sts, type(sts))  # ['server', 'client'] <class 'list'>

ops = parser.options(sts[0])
print(ops)  # ['ip', 'port']
value = parser.get(sts[0], ops[0])
print(value, type(value))  # 192.168.66.88 <class 'str'>
# # get=>str getboolean=>bool getfloat=>float getint=>int
print(parser.get('server', 'port')) # 3306

# 3.寫
parser.read('my.ini', encoding='utf-8')
parser.set('server', 'port', '6666')
parser.write(open('my.ini', 'w'))

十3、xml模塊

# xml文件:1.做爲傳輸文件用於數據的傳輸  2.做爲配置文件配置信息

# 1.只能由一個根標籤
# 2.全部的標籤都是自定義的
# 3.標籤名就是key,標籤的內容就是value
# 4.與json不一樣的是,標籤不只能夠有key和value,還有標籤的屬性
# 注:xml的屬性一般用來表示標籤間的區分度,用於解析xml來使用
<data>
    <country name="Liechtenstein">
        <rank updated="yes">2</rank>
        <year>2008</year>
        <gdppc>141100</gdppc>
        <neighbor direction="E" name="Austria" />
        <neighbor direction="W" name="Switzerland" />
    </country>
    <country name="Singapore">
        <rank updated="yes">5</rank>
        <year>2011</year>
        <gdppc>88888</gdppc>
        <neighbor direction="N" name="Malaysia" />
    </country>
    <country name="Panama">
        <rank updated="yes">69</rank>
        <year>2011</year>
        <gdppc>13600</gdppc>
        <neighbor direction="W" name="Costa Rica" />
        <neighbor direction="E" name="Colombia" />
    </country>
</data>
my.xml
"""
{"countrys": [
    {
        "rank": 2,
        "year": 2008,
        "gdppc": 141100
    },
    {},
    {}
]}

{
    "data": {
        "countrys": [
            {},
            {},
            {}
        ]
    }
}
"""
# xml的文件解析 => 將xml轉化爲json類型的數據
# dict list => json

import xml.etree.ElementTree as ET

# 讀文件
tree = ET.parse("my.xml")
print(tree)  # xml.etree.ElementTree.ElementTree # <xml.etree.ElementTree.ElementTree object at 0x0000000001EACA58>
# 根節點
root_ele = tree.getroot()
print(root_ele)  # Element 'data':<Element 'data' at 0x0000000001DBD4A8>

# 遍歷往下
# print(root_ele[1])
for ele in root_ele:
    print(ele, ele.attrib)
    if ele.attrib['name'] == 'Singapore':
        for e in ele:
            print(e, e.tag)
            if e.tag == 'gdppc':
                print(e.text)
                e.text = '6666'  # 只修改了內容

# 全文搜索指定名的子標籤
# ele.iter("標籤名")
# 非全文查找知足條件的第一個子標籤
# ele.find("標籤名")
# 非全文查找知足條件的全部子標籤
# ele.findall("標籤名")
# print('==============')
# cs = root_ele.iter('country')
# for c in cs:
#     print(c)
# print('==============')
# print(root_ele.find('country').attrib) # {'name': 'Liechtenstein'}
# print(root_ele.find('rank').attrib)  # 不能跨標籤取,只能取子標籤
# print('==============')
# print(root_ele.findall('country'))

# 將內存的數據從新寫入文件
tree.write("my.xml")

# 讀
data = {'countrys': []}
tree = ET.parse("my.xml")
root = tree.getroot()
for ele in root:
country = {}
for e in ele:
if e.text and e.text.strip():
country[e.tag] = e.text
data['countrys'].append(country)
print(data)

十4、Excel操做

# Excel
                            年終報表                
              教學部    市場部    諮詢部    總計
Jan-19    10    15            5        30
Feb-19    11    20            5        36
Mar-19    12    25            5        42
Apr-19    13    30            5        48
May-19    14    35            5        54
Jun-19    15    40            5        60
Jul-19    16    45            5        66
Aug-19    17    50            5        72
Sep-19    18    55            5        78
Oct-19    19    60            5        84
Nov-19    20    65            5        90
Dec-19    21    70            5        96

基本操做

imimport xlrd

# 讀取文件
work_book = xlrd.open_workbook("my.xlsx")
# 獲取全部全部表格名稱
print(work_book.sheet_names())
# 選取一個表
sheet = work_book.sheet_by_index(0)
# 表格名稱
print(sheet.name)
# 行數
print(sheet.nrows)
# 列數
print(sheet.ncols)
# 某行所有
print(sheet.row(6))
print(sheet.row(13))
# 某列所有
print(sheet.col(4))
# 某行列區間
print(sheet.row_slice(6, start_colx=0, end_colx=4))
# 某列行區間
print(sheet.col_slice(3, start_rowx=0, end_rowx=3))
# 某行類型0:空 1:str 2:num 3:date | 值
print(sheet.row_types(1), sheet.row_values(6))

# 單元格
print(sheet.cell(6,0).value) # 取值
print(sheet.cell(6,0).ctype) # 取類型
print(sheet.cell_value(6,0)) # 直接取值
print(sheet.cell_type(6,0)) # 直接取類型

# 0:以1900年爲基準 1:以1904年爲基準
print(xlrd.xldate_as_datetime(sheet.cell(6, 0).value, 0))
import xlwt
# 建立工做簿
work = xlwt.Workbook()
# 建立一個表
sheet = work.add_sheet("員工信息數據")
# 建立一個字體對象
# font = xlwt.Font()
# font.name = "Times New Roman"  # 字體名稱
# font.bold = True  # 加粗
# font.italic = True  # 斜體
# font.underline = True  # 下劃線
# 建立一個樣式對象
# style = xlwt.XFStyle()
# style.font = font
keys = ['Owen', 'Zero', 'Egon', 'Liuxx', 'Yhh']
# 寫入標題
c = 0
for k in keys:
    # sheet.write(0, keys.index(k), k, style)
    # sheet.write(0, keys.index(k), k)

    sheet.write(keys.index(k) + 5, 2, k if k != 'Egon' else 'cool')
    # sheet.write(c, c, k)
    # c += 1

# 寫入數據
# sheet.write(1, 0, 'cool', style)
# sheet.write(0, 0, 'cool')
# 保存至文件
work.save("new_my.xls")
相關文章
相關標籤/搜索