1.1 普通字符串 |
1.21 錯誤與異常 |
1.41 XXXXXX |
1.61 XXXXXX |
1.81 XXXXXX |
1.101 XXXXXX |
1.2 轉義字符串 |
1.22 裝飾器 |
||||
1.3 字符串運算 |
1.23 高階函數 |
||||
1.4 字符串函數 |
1.24 生成器 |
||||
1.5 字符編碼 |
1.25 迭代器 |
||||
1.6 註釋 |
1.26 序列化 |
||||
1.7 交互程序 |
1.27 Python反射 |
||||
1.8 格式化輸出 |
1.28 Socket編程 |
||||
1.9 流程控制If-Else |
1.29 Paramiko |
||||
1.10 While循環 |
1.30 爬蟲 | ||||
1.11 模塊 |
|||||
1.12 列表 |
|||||
1.13 元組 |
|||||
1.14 字典 |
|||||
1.15 購物車實例 |
|||||
1.16 文件讀寫 |
|||||
1.17 目錄操做 |
|||||
1.18 函數 |
|||||
1.19 類和對象 |
|||||
1.20 字符編碼轉換 |
1、Python基礎html
1.1 普通字符串python
字符串主要用來存儲和表示文本內容的,在python中表示字符串有單引號('),雙引號(")和註釋用的三引號(''')三種方式。linux
name = "harry" print('my name is ',name) 輸出: my name is harry
print('飛機',"大廈",'''鋼琴''',"""航海""") 輸出: 飛機 大廈 鋼琴 航海
可是有一種狀況,就是本來被雙引號擴起來的內容中須要用單引號進行標記,本來被單引號擴起來的內容中須要用雙引號進行標記,不然使用相同的引號進行內部標記的時候python解釋器會因沒法判斷引號的邊界而報錯。git
print('hello "world"') print("hello 'world'") print('hello 'world'') # 報錯 輸出: hello "world" hello 'world'
1.2 轉義字符串程序員
python中包須要打印一些特殊的字符的時候,好比單引號、雙引號、換行符的輸出須要用\進行轉義。例如web
# \n 換行符 print('今天是個好日子\n明天也是!') 輸出: 今天是個好日子 明天也是! # \t 製表符 print('name:harry\tage:18') 輸出: name:harry age:18 # \r 回車 print('abc\r111') 輸出: 111 # \\ 打印一個\字符 print('\\') 輸出: \ # \' 打印單引號 print('\'') print("'") 輸出: ' ' # \" 打印雙引號 print('"') print("\"") 輸出: " "
1.3 字符串運算正則表達式
字符串能夠經過➕或✖️來進行運算,加號就是拼接乘號就是字符串的倍數,效果以下算法
print('demo ' + 'hello') 輸出: demo hello print('demo ' * 3) 輸出: demo demo demo
1.4 字符串函數docker
python中又一些函數能夠來操做字符串,好比將字符串的小寫字母所有轉化爲大寫,或者計算出某個字母在字符串中出現的次數等等,如下爲部分實際例子:shell
# 'abc'.capitalize() 將字符串的首字母大寫 print('abc') print('abc'.capitalize()) 輸出: abc Abc # 'abcba'.count('a') 計算a在abcba中出現的次數 print('abcba'.count('a')) 輸出: 2 # 獲得a、b在字符串abcba中的最初出現的位置,第1位的位置是0,依此類推。 print('abcba'.find('a')) print('abcba'.find('b')) 輸出: 0 1 # 字符串分割 name = 'hellow.world' a,b = name.split('.') print('a:',a) print('b:',b) 輸出: a: hellow b: world # 將字符串中的大寫字母所有轉換爲小寫字母 name = 'Hello World' print(name.lower()) 輸出: hello world # 將字符串中的小寫字母所有轉換爲大寫字母 name = 'hello world' print(name.upper()) 輸出; HELLO WORLD # 計算出一個字符串的長度是多少 name = 'hello world' print('字符串長度:',len(name)) 輸出: 字符串長度: 11 # 判斷字符串是否只有大小寫字母+數字組成 info_1 = 'Harry19' info_2 = 'Harry19?' print(info_1.isalnum()) print(info_2.isalnum()) 輸出: True False # 判斷字符串是否只有大小寫字母組成 info_3 = 'AaBb' info_4 = 'AaBb_' print(info_3.isalpha()) print(info_4.isalpha()) 輸出: True False # 判斷字符串是否只有數字組成 info_5 = '110' info_6 = '110+110' print(info_5.isdigit()) print(info_6.isdigit()) 輸出: True False
1.5 字符編碼
計算機發展初期多爲英語國家使用,而英文字母個數不像漢語的數量那麼龐大,所以早期採用ASCII表來進行字符編碼,可是隨着全球經濟發展使用計算機的非英語國家數量大大增長了,而非英語國家如,日語,漢語和韓語等字符沒有辦法參照ASCII表進行編碼,所以各個國家開始在原始的ASCII表裏插入本國的字符編碼表,如中國前期的擴展出了用於編碼漢字的GB2312表。固然ASCII表只有兩百多位可使用,而早期的漢字個數就已經在8k以上了,所以這裏所謂的「插入本國字符編碼」實際上是在原有的ASCII表裏佔用剩餘的一位,而後將本國的編碼表指向ASCII表中的一位而已。GB2312以後又經歷GB18030,可擴展的漢字個數擴展到了2萬以上了。
與中國同樣,其它不少非英語國家都逐漸擴展出來適合本身國家的字符編碼表。而各類各樣的編碼表出現後帶來的問題就是開發出的程序或其它應用在跨國展示的時候極其容易出現亂碼。爲了解決這個問題國際ISO的一個標準組織發佈了一個統一標準,即:Unicode也叫作統一萬國碼。Unicode的好處是顯而易見的,可是有一點也是不能忽略的,就是Unicode規定全部字符和符號最少由16位來表示,也就是2個字節(2**16=65536)。如此一來純英文文本的存儲本來只須要一個字節如今要佔用2個字節了,帶來的最大壞處就是極大的浪費了咱們的磁盤空間。爲了解決這個問題,人們在Unicode的基礎上由開發出了一個存儲空間可靈活擴展或縮小的編碼形式,而這個編碼也正是咱們如今正在使用的UTF-8.
1.6 註釋
python中的註釋分爲單行註釋和多行註釋,效果以下:
# 單行註釋,當前行最前邊的井號就是單行註釋 # 多行註釋使用三個引號來表示,能夠是單引號也能夠是三個雙引號 ''' name = 'natasha' age = 19 print(name,age) ''' # 三個單引號或雙引號除了作註釋用還能夠用於保存多行字符串,以下所示: info = ''' 外面下雨了 音樂響起了 菜場關門了 ''' print(info) 輸出: 外面下雨了 音樂響起了 菜場關門了
1.7 交互程序
使用input()能夠完成用戶與程序間的交互,如下代碼除了應用了交互外還使用+號進行字符串拼接:
name = input("please input your username:") passwd = input('please input your password:') age = input('please input your age:') info = ''' ---------- info of ''' + name + ''' ---------- UserName:''' + name + ''' Password:''' + passwd + ''' Age:''' + age print(info) 輸出: please input your username:harry please input your password:123456 please input your age:18 ---------- info of harry ---------- UserName:harry Password:123456 Age:18
1.8 格式化輸出
以上交互程序中使用了字符串拼接,把經過input()接收來的字符串經過+號拼接起來看起來略顯雜亂。而python的字符串格式化能夠完美的解決這個問題。python格式化輸出的其中一種方式就是百分號的形式%。所謂的格式化字符串就是指,在字符串中使用以%開頭的字符在程序中改變字符的內容,經常使用的字符串有如下幾種類型:
%c 單個字符 %d 十進制整數 %o 八進制整數 %s 字符串 %x 十六進制整數,其中字母小寫 %X 十六進制整數,其中字母大寫
仍然以1.7的代碼爲例,變動以下
name = input("please input your username:") passwd = input('please input your password:') age = int(input('please input your age:')) # input()接收的爲字符串形式,經過int()函數將結果轉爲整數 info = ''' ---------- info of %s ---------- Username:%s Password:%s Age:%d ''' % (name,name,passwd,age) print(info) 輸出: please input your username:natasha please input your password:1112223333abc please input your age:10 ---------- info of natasha ---------- Username:natasha Password:1112223333abc Age:10
另一種格式化輸出是使用.format()函數。而.format()函數在字符串標記有兩種形式,即{變量}=變量,{下標}=變量的兩種形式。使用時即在字符串中用{變量/下表}標記,而後字符串後跟.format(變量)來表示,語法以下:
》{變量}=變量
name = input("please input your username:") passwd = input('please input your password:') age = int(input('please input your age:')) info = ''' ---------- info of {_name} Name: {_name} Password: {_passwd} Age: {_age} '''.format(_name=name, _passwd = passwd, _age = age) print(info) 輸出: please input your username:natasha please input your password:888777 please input your age:28 ---------- info of natasha Name:natasha Password:888777 Age:28
》{下標}=變量
name = input("please input your username:") passwd = input('please input your password:') age = int(input('please input your age:')) info = ''' ---------- info of {0} ---------- Name: {0} Password:{1} Age:{2} '''.format(name,passwd,age) print(info) 輸出: please input your username:akira please input your password:222222 please input your age:78 ---------- info of akira ---------- Name: akira Password:222222 Age:78
1.9 流程控制If-Else
流程控制語句if-else爲判斷條件成立時執行什麼,條件不成立時執行什麼,在演示if-else代碼前先看一段普通的輸入用戶名密碼的代碼:
import getpass # 導入getpass模塊,輸入密碼時不可見 username = input("username:") password = getpass.getpass("password") # 注意,getpass.getpass()在pycharm裏使用會報錯,能夠直接在命令行執行。 print(username,password) 輸出: username:akira password: # 密碼輸入了,可是並無顯示在控制檯 akira 111111
一般狀況下,輸入用戶名密碼後須要判斷內容是否正確,正確的話容許登陸系統錯誤的話會返回一個報錯信息。接下來用if-else來演示:
# 定義正確的用戶名密碼是什麼 db_username = 'akira' db_password = '111111' username = input("請輸入用戶名:") password = input("請輸入密碼:") if db_username == username and db_password == password: print('\n登陸成功!\n歡迎{name}!'.format(name=username)) # \n爲換行符 else: print('\n登陸失敗!\n用戶名{name}或密碼{passwd}錯誤'.format(name=username,passwd=password)) 正確輸出: 請輸入用戶名:akira 請輸入密碼:111111 登陸成功! 歡迎akira! 錯誤輸出: 請輸入用戶名:akira 請輸入密碼:222222 登陸失敗! 用戶名akira或密碼222222錯誤
1.10 While循環
假定一個條件成立則一直執行符合條件的代碼部分。如下實例在1.9流程控制If-Else的基礎上演變而來,需求爲用戶第一次輸入用戶名密碼時判斷是否成功,若是第一次登陸失敗則以後的每一次都須要問一下用戶是否仍要繼續嘗試登陸,是則再次進行判斷不然退出。
count = 0 while True: # 定義正確的用戶名密碼是什麼 db_username = 'akira' db_password = '111111' if count == 0 : count += 1 username = input("請輸入用戶名:") password = input("請輸入密碼:") if db_username == username and db_password == password: print('\n登陸成功!\n歡迎{name}!\n'.format(name=username)) # \n爲換行符 break else: print('\n登陸失敗!\n用戶名{name}或密碼{passwd}錯誤\n'.format(name=username, passwd=password)) elif count > 0 : flag = input("按任意鍵退出,繼續請按y:") if flag == 'y': username = input("請輸入用戶名:") password = input("請輸入密碼:") if db_username == username and db_password == password: print('\n登陸成功!\n歡迎{name}!\n'.format(name=username)) # \n爲換行符 break else: print('\n登陸失敗!\n用戶名{name}或密碼{passwd}錯誤\n'.format(name=username, passwd=password)) else: print('您已放棄登陸,Bye!') break 》錯誤輸出: 請輸入用戶名:natasha 請輸入密碼:222222 登陸失敗! 用戶名natasha或密碼222222錯誤 按任意鍵退出,繼續請按y:y 請輸入用戶名:sudo 請輸入密碼:333333 登陸失敗! 用戶名sudo或密碼333333錯誤 按任意鍵退出,繼續請按y:n 您已放棄登陸,Bye! 》正確輸出: 請輸入用戶名:kkkkk 請輸入密碼:123456 登陸失敗! 用戶名kkkkk或密碼123456錯誤 按任意鍵退出,繼續請按y:y 請輸入用戶名:akira 請輸入密碼:111111 登陸成功! 歡迎akira!
1.11 模塊
模塊,在Python中可理解爲一個Python文件。在建立了一個腳本文件後,模塊中定義了某些函數、類和變量等。你在其餘須要這些功能的文件中,導入該模塊,就可重用這些函數和變量。以sys和os模塊爲例,代碼以下
import sys # 導入sys模塊 print(sys.path) # 打印環境變量 輸出: ['/Users/***/PycharmProjects/python_basic/python教程/模塊', '/Users/***/Documents/Python/21天學通python/源代碼', '/Users/***/PycharmProjects/python_basic/python教程', '/Library/Frameworks/Python.framework/Versions/3.6/lib/python36.zip', '/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6', '/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/lib-dynload', '/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages']
sys.path爲調用python的系統環境變量,python尋找模塊則會在以上路徑中尋找。咱們所安裝的第三方的庫通常會安裝在site-packages這個目錄裏。下面看一下os模塊
import os #導入os模塊 result_1 = os.system("dir") # os.system("dir")打印當前目錄的全部文件 print(result_1) 輸出: C:\Users\***\PycharmProjects\PyDemo ��Ŀ¼ 2017/07/10 19:49 <DIR> . 2017/07/10 19:49 <DIR> .. 2017/07/10 19:49 <DIR> .idea 2017/07/10 19:49 317 osDemo.py 2017/07/10 18:58 <DIR> __pycache__ 1 ���ļ� 317 �ֽ� 4 ��Ŀ¼ 1,553,289,216 �����ֽ� 0
注意,os.system("dir")直接輸出在控制檯,同時result被賦值爲0,也就是執行成功的返回值。使用os.popen().read()則能夠直接將整個命令執行結果賦值給result_2
result_2 = os.popen("dir").read() print(result_2) 輸出: 2017/07/10 19:51 <DIR> . 2017/07/10 19:51 <DIR> .. 2017/07/10 19:50 <DIR> .idea 2017/07/10 19:51 317 osDemo.py 2017/07/10 18:58 <DIR> __pycache__ 1 個文件 317 字節 4 個目錄 1,553,018,880 可用字節
模塊導入分爲兩種形式,即import module_name與from module_name import *兩種方式,各自的調用方式均有不一樣;
模塊路徑:
-- module(文件夾) -- main.py -- module_A.py module_A.py內容: name = 'pentest123' def say_hello(): print('module_A: say_hello') def say_hi(): print('module_A: say_hi')
實例1: import module_name導入
import module_A print(module_A.name) # 經過模塊名調用屬性 module_A.say_hello() # 經過模塊名調用方法 module_A.say_hi() # 經過模塊名調用方法 輸出: pentest123 module_A: say_hello module_A: say_hi
實例2: from module_name import * 導入
# from module_A import * 至關與把module_A裏的全部內容都複製到當前py文件內一個效果,因此直接使用方法或屬性。
from module_A import * say_hi() print(name) say_hello() 輸出: module_A: say_hi pentest123 module_A: say_hello
實例3: 導入其餘目錄下的模塊
目錄結構及導入要求:
目錄結構: ——模塊 ————import_package(包) ———————__init__.py ————module ———————imp_pac.py 要求: 在module目錄下的imp_pac.py文件中導入「模塊/import_package包」,其中待導入模塊的__init__.py內容爲: print('from import_package') def say_hello(): print('hello everyone!')
在導入其餘目錄下的模塊前先來看幾個獲取python模塊路徑的方法:
import sys,os print('查看Python搜索模塊的路徑有哪些:\n',sys.path) 輸出: 查看Python搜索模塊的路徑有哪些: [‘/Users/pentest/PycharmProjects/python_basic/python教程/模塊/module’, ‘/Users/pentest/Documents/Python/21天學通python/源代碼’, ‘/Users/pentest/PycharmProjects/python_basic/python教程’, ‘/Library/Frameworks/Python.framework/Versions/3.6/lib/python36.zip’, ‘/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6’, ‘/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/lib-dynload’, ‘/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages’] print('查看當前.py文件的當前路徑:\n',os.path.abspath(__file__)) 輸出: 查看當前.py文件的當前路徑: /Users/pentest/PycharmProjects/python_basic/python教程/模塊/module/imp_pac.py print('查看當前.py文件的所在上級目錄:\n',os.path.dirname(os.path.abspath(__file__))) 輸出: 查看當前.py文件的所在上級目錄: /Users/pentest/PycharmProjects/python_basic/python教程/模塊/module # os.path.dirname()重複利用便可逐一回溯到更上級的目錄 x1 = os.path.dirname(os.path.abspath(__file__)) print('x1目錄名:',x1) x2 = os.path.dirname(x1) print('x2目錄名:',x2) x3 = os.path.dirname(x2) print('x3目錄名:',x3) x4 = os.path.dirname(x3) print('x4目錄名:',x4) print() 輸出: x1目錄名: /Users/pentest/PycharmProjects/python_basic/python教程/模塊/module x2目錄名: /Users/pentest/PycharmProjects/python_basic/python教程/模塊 x3目錄名: /Users/pentest/PycharmProjects/python_basic/python教程 x4目錄名: /Users/pentest/PycharmProjects/python_basic
導入其餘目錄下的模塊能夠將被導入模塊的上層目錄添加到python搜索模塊的路徑列表中(也就是上例中的sys.path),而如何找到該包的路徑名稱就能夠經過上述的os.path.dirname()來逐一查找,以下所示:
pt = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # 找到被導入模塊的上層路徑
print('被導入模塊的上層包爲:',pt)
輸出:
被導入模塊的上層包爲: /Users/pentest/PycharmProjects/python_basic/python教程/模塊
sys.path.insert(0,pt) # 將該目錄插入到python搜索模塊的路徑列表的第一個元素位置
print(sys.path) # 再次查看目錄已被添加都列表首位
輸出:
['/Users/pentest/PycharmProjects/python_basic/python教程/模塊', '/Users/pentest/PycharmProjects/python_basic/python教程/模塊/module', '/Users/pentest/Documents/Python/21天學通python/源代碼', '/Users/pentest/PycharmProjects/python_basic/python教程', '/Library/Frameworks/Python.framework/Versions/3.6/lib/python36.zip', '/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6', '/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/lib-dynload', '/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages']
import import_package # 嘗試導入該模塊,發現並未報錯。
輸出:
from import_package
print('\n執行import_package包裏的say_hello()方法:')
import_package.say_hello() # 嘗試執行被導入模塊裏都方法
輸出:
執行import_package包裏的say_hello()方法:
hello everyone!
實例4:Time模塊
>時間的幾種表示方法:
-> 時間戳:從1970年1月1日0:00開始到當前時間爲止的時間,單位爲秒。 -> 格式化的時間字符串:徹底按着本身所須要展示的格式去定義時間組合 -> 元組(struct_time)共九個元素,time.struct_time(tm_year=2017, tm_mon=8, tm_mday=1, tm_hour=18, tm_min=58, tm_sec=58, tm_wday=1, tm_yday=213, tm_isdst=0)
>代碼部分:
import time # 獲取時間戳 print('當前時間戳:',time.time()) 輸出: 當前時間戳: 1501653135.0996149 # 由時間戳反轉到年份,能夠經過逐步轉秒->分->時->天->年的方式,另外一種方式是經過gmtime()或localtime()方法進行轉換 t = time.time() # 計算得出從1970-01-01 00:00:00 到目前爲止到秒數 min = t/60 # 計算分鐘總數 hou = min/60 # 小時總數 day = hou/24 # 天總數 year = day/365 # 年總數 print('當前年:',int(year+1970)) # 年總數+1970後取整就是2017年 輸出: 當前年: 2017 # gmtime()爲空時輸出當前時間 curt_time = time.gmtime() print('time.gmtime()未指定時間戳:',curt_time) 輸出: time.gmtime()未指定時間戳: time.struct_time(tm_year=2017, tm_mon=8, tm_mday=2, tm_hour=5, tm_min=52, tm_sec=15, tm_wday=2, tm_yday=214, tm_isdst=0) # gmtime()給出具體時間戳時計算對應的時間 zd_time = time.gmtime(1401639557) print('time.gmtime()指定時間戳:',zd_time) 輸出: time.gmtime()指定時間戳: time.struct_time(tm_year=2014, tm_mon=6, tm_mday=1, tm_hour=16, tm_min=19, tm_sec=17, tm_wday=6, tm_yday=152, tm_isdst=0) # 格式化的時間字符串 print('time.localtime()未指定時間戳:',time.localtime()) # localtime()括號內不添加秒數的時候是將當前時間格式化輸出 輸出: time.localtime()未指定時間戳: time.struct_time(tm_year=2017, tm_mon=8, tm_mday=2, tm_hour=13, tm_min=52, tm_sec=15, tm_wday=2, tm_yday=214, tm_isdst=0) print('time.localtime()指定時間戳:',time.localtime(1401639557)) # localtime()括號內指定具體秒數的時候能夠轉換成的對應的時間格式輸出。 輸出: time.localtime()指定時間戳: time.struct_time(tm_year=2014, tm_mon=6, tm_mday=2, tm_hour=0, tm_min=19, tm_sec=17, tm_wday=0, tm_yday=153, tm_isdst=0) # 經過time.localtime()單獨獲取時間元素,如年、月、日、時、分、秒等。 x = time.localtime() print('年:',x.tm_year) print('月:',x.tm_mon) print('日:',x.tm_mday) print('時:',x.tm_hour) print('分:',x.tm_min) print('秒:',x.tm_sec) print('周:',x.tm_wday) print('一年中的第幾天:',x.tm_yday) print('時區:',x.tm_isdst) 輸出: 年: 2017 月: 8 日: 2 時: 13 分: 52 秒: 15 周: 2 一年中的第幾天: 214 時區: 0 # 經過time.strftime()格式化輸出時間,strptime(...)的用法以下所示: %Y Year with century as a decimal number. %m Month as a decimal number [01,12]. %d Day of the month as a decimal number [01,31]. %H Hour (24-hour clock) as a decimal number [00,23]. %M Minute as a decimal number [00,59]. %S Second as a decimal number [00,61]. %z Time zone offset from UTC. %a Locale's abbreviated weekday name. %A Locale's full weekday name. %b Locale's abbreviated month name. %B Locale's full month name. %c Locale's appropriate date and time representation. %I Hour (12-hour clock) as a decimal number [01,12]. %p Locale's equivalent of either AM or PM. print('time.strftime時間格式化:',time.strftime("%Y-%m-%d %H:%M:%S")) print('time.strftime參數:',time.strftime("%Y-%m-%d %H:%M %a %A %b %B %c %I %p")) 輸出: time.strftime時間格式化: 2017-08-02 13:52:15 time.strftime參數: 2017-08-02 13:52 Wed Wednesday Aug August Wed Aug 2 13:52:15 2017 01 PM
實例5: Random模塊
import random # 隨機生成浮點數,範圍爲0-1之間的小數 x = random.random() print('random.random():',x) 輸出: random.random(): 0.3629850178005113 # random.randint()隨機生成指定範圍之間的數字,首尾均可能會被取到 x = random.randint(5,10) # 取值範圍5-10 print('random.randint(5,10):',x) 輸出: random.randint(5,10): 5 # random.randrange()隨機生成指定範圍之間的數字,首位可能回被取到但末尾絕對不取(顧頭不顧尾) x = random.randrange(5,10) # 取值範圍:5-9 print('random.randrange(5,10):',x) 輸出: random.randrange(5,10): 6 # random.choice()隨機選出括號內的元素,括號內須要是序列,例如字符串,列表等 x = random.choice('pentest') print("random.choice('pentest'):",x) 輸出: random.choice('pentest'): e li = [1,2,23,45,66] x = random.choice(li) print('random.choice([1,2,23,45,66]):',x) 輸出: random.choice([1,2,23,45,66]): 2 name = ("akira","natasha","jack","susan") x = random.choice(name) print('random.choice(("akira","natasha","jack","susan"))',x) 輸出: random.choice(("akira","natasha","jack","susan")) akira # random.sample()隨機選出序列中指定個數的元素。 x1 = random.sample('pentest',2) x2 = random.sample('pentest',2) print('random.sample()_1:',x1) print('random.sample()_2',x2) 輸出: random.sample()_1: ['p', 'e'] random.sample()_2 ['s', 'n'] # random.uniform()隨機取出給定範圍內的浮點數 x = random.uniform(1,10) print('random.uniform(1,10):',x) 輸出: random.uniform(1,10): 9.315535595496103 # random.shuffle()隨機打算一個序列 items = [1,2,3,4,5,6,7,8,9,10] print('[1,2,3,4,5,6,7,8,9,10]:',items) random.shuffle(items) print('random.shuffle([1,2,3,4,5,6,7,8,9,10]):',items) 輸出: [1,2,3,4,5,6,7,8,9,10]: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] random.shuffle([1,2,3,4,5,6,7,8,9,10]): [2, 9, 10, 7, 4, 1, 3, 8, 6, 5]
>製做一個6位隨機數字+字母驗證碼
import random checkcode = '' for i in range(6): # 循環6次 current = random.randrange(0,6) # 每次循環取出一位隨機值 if i == current: # 若是循環的次數等於該隨機值,打印字母 tmp = chr(random.randint(65,90)) # chr()將十進制數字轉換爲ASCII表中對應的英文字母 else: # 不然打印0-9之間的隨機數字 tmp = random.randint(0,9) checkcode += str(tmp) # 將每一次獲取的數字或字母添加到checkcode裏即爲隨機驗證碼。 print(checkcode) 輸出; 123382 / 7JH614 / 4YED09
實例6:OS模塊
import os # 獲取當前被執行文件的所在路徑 print(os.getcwd()) 輸出: C:\Users\IH1407\PycharmProjects\PyDemo\module\osModule # 更改路徑,注意windows下路徑D:\apk則應變動爲D://apk os.chdir("D://apk//dir1//dir2") print(os.getcwd()) 輸出: D:\apk\dir1\dir2 # 返回當前目錄 . print('當前目錄:',os.curdir) 輸出: 當前目錄: . # 返回當前目錄的父目錄 .. print('當前目錄的父目錄:',os.pardir) 輸出: 當前目錄的父目錄: .. # 生成多層遞歸目錄 os.chdir("D://apk") os.makedirs('dir1/dir2/dir3') 輸出: 文件夾:D:\apk\dir1\dir2\dir3 # 若最下層目錄爲空則刪除並返回到上一層目錄爲空的話繼續刪除,若不爲空則報錯 os.removedirs('dir1/dir2/dir3') # 生成單級目錄,若目錄存在則報錯。 os.mkdir('testDir') 輸出: 文件夾:D:\apk\testDir # 刪除單級目錄,若目錄不存在或目錄不爲空,則報錯。 os.rmdir('testDir') # 列出指定目錄下的全部文件及子目錄 print(os.listdir()) 輸出: ['111.apk', '222.txt'] # 刪除一個文件,若是文件不存在則報錯 print(os.listdir()) os.remove('222.txt') print(os.listdir()) 輸出: ['111.apk', '222.txt'] ['111.apk'] # 重命名一個文件 print(os.listdir()) os.rename('222.txt','111.txt') print(os.listdir()) 輸出: ['111.apk', '222.txt'] ['111.apk', '111.txt'] # 查看文件\目錄信息 print(os.stat('111.txt')) print(os.stat('111.apk')) 輸出: os.stat_result(st_mode=33206, st_ino=2814749767315451, st_dev=730660, st_nlink=1, st_uid=0, st_gid=0, st_size=0, st_atime=1501738210, st_mtime=1501738210, st_ctime=1501738210) os.stat_result(st_mode=33206, st_ino=844424930348713, st_dev=730660, st_nlink=1, st_uid=0, st_gid=0, st_size=22208042, st_atime=1474528040, st_mtime=1476942255, st_ctime=1474528040) # 輸出操做系統的路徑分隔符,windows是\,mac是/ print(os.sep) 輸出: \ # 運行系統shell命令,直接輸出,下例爲命令行調出計算器 print(os.system('calc')) 輸出: 彈出計算機窗口 # 輸出系統環境變量 print(os.environ) 輸出: environ({'ALLUSERSPROFILE': 'C:\\ProgramData', ... 'WINDIR': 'C:\\WINDOWS'}) # 將path分割成目錄和文件名,並以元祖的形式返回 print('當前路徑:',os.getcwd()) os.makedirs('dir1/dir2/dir3') 輸出: 當前路徑: D:\apk print(os.path.split(os.getcwd())) 輸出: ('D:\\', 'apk') os.chdir('D:/apk/dir1/dir2/dir3/') print(os.path.split(os.getcwd())) 輸出: ('D:\\apk\\dir1\\dir2', 'dir3') # 返回path的目錄,其實就是os.path.split(path)的第一個元素 print(os.path.dirname(os.getcwd())) # 返回path最後的文件名 print(os.path.basename(os.getcwd())) 輸出: D:\ apk # 查看指定目錄是否存在,若是存在返回True,不然返回False print(os.getcwd()) print(os.path.exists('D:/apk/dir1/dir2/dir3')) print(os.path.exists('D:/test')) 輸出: D:\apk True False # 若是path是絕對路徑返回True print(os.path.isabs('dir3')) print(os.path.isabs('D:/apk/dir1/dir2/dir3')) 輸出: False True # 若是文件存在返回True,不然返回False print(os.listdir(os.getcwd())) print(os.path.isfile('dir4.txt')) print(os.path.isfile('111.txt')) 輸出: ['111.apk', '111.txt', 'dir1'] False True # 若是指定path存在則返回True,不然返回False print(os.path.isdir('D:/apk/dir1/dir2')) print(os.path.isdir('D:/apk/dir1/dir')) 輸出: True False # 返回path所指向的文件或目錄的最後存取時間,返回的時間格式爲時間戳 print(os.path.getatime(os.getcwd())) 輸出: 1501738703.7218287 #返回path所指向文件或目錄的最後修改時間,返回的時間格式爲時間戳 print(os.path.getmtime(os.getcwd())) 輸出: 1501738703.7218287
實例7: SYS模塊
>sys.exit()退出程序
import sys # sys.exit(0)執行後後面的end將不會被打印了。 print('start') sys.exit(0) print('end') ''' 輸出: tdcqma:SYS $ ./sysModule.py start '''
>sys.argv獲取參數(須要在終端進行實驗)
import sys a = sys.argv print(a,type(a)) # 參數接收後保存在列表裏 print(a[1:]) # 列表的第一位是腳本自己,從第二位開始纔是接收來的參數,因此使用切片從下標爲1的地方開始讀 輸出: tdcqma:SYS $ ./sysModule.py 1 2 3 4 5 (['./sysModule.py', '1', '2', '3', '4', '5'], <type 'list'>) ['1', '2', '3', '4', '5']
實例8: shutil模塊(高級的文件、文件夾、壓縮包處理模塊)
>shutil.copy()模塊複製文件
import shutil import os print('目錄更改前:',os.getcwd()) # 查看當前目錄: # 變動目錄: os.chdir('/Users/mahaibin/Desktop') print('目錄更改後:',os.getcwd()) print() # 建立文件1.txt' os.system('echo pentest > 1.txt') # 複製1.txt給2.txt(本來2.txt不存在) shutil.copy('1.txt','2.txt') # 由於os.listdir()爲列表類型,可被for循環 for item in os.listdir(): print(item) print('\n查看2.txt的內容:') print(os.system('cat 2.txt')) 輸出: 目錄更改前: /Users/pentest/PycharmProjects/python_basic/python教程/模塊/shutilModule 目錄更改後: /Users/pentest/Desktop .DS_Store .localized 1.txt 2.txt 45個報警鈴音WAV格式 查看2.txt的內容: pentest
>shutil.copyfileobj()複製文件到另外一個文件
import shutil # f1與f2在當前目錄,因此能夠直接open打開 f1 = open('源文件',encoding='utf-8') f2 = open('目標文件','w') shutil.copyfileobj(f1,f2) 輸出: 效果爲f1的內容copy到f2的文件裏去了。
實例9: hashlib模塊,用於加密相關的操做提供了MD五、SHA224,SHA25六、SHA512等算法。
將"hello python"字符串轉換成16進制md5值。
import hashlib m = hashlib.md5() m.update(b"hello python") print(m.hexdigest()) 輸出: e53024684c9be1dd3f6114ecc8bbdddc
一個md5對象每次update一個內容都會進行疊加,例如m1 = hello ,m1 = world , m1 = 123,那麼最後一次m1.hexdigest()的md5值的對象實際上是helloworld123,如:
m1 = hashlib.md5() m1.update(b"hello") print(m1.hexdigest()) m1.update(b"world") print(m1.hexdigest()) m1.update(b"123") print('m1-->',m1.hexdigest()) m2 = hashlib.md5() m2.update(b"helloworld123") print('m2-->',m2.hexdigest()) 輸出: 5d41402abc4b2a76b9719d911017c592 fc5e038d38a57032085441e7fe7010b0 m1--> cd1b8ecf103743a98958211a11e33b71 m2--> cd1b8ecf103743a98958211a11e33b71
將"hello python"字符串轉換成16進制sha256值。
m3 = hashlib.sha256() m3.update(b"hello python") print(m3.hexdigest()) 輸出: 373a23512f9531ad49ec6ad43ecdda58df01e59d9ec5812d601fd05cc53345d3
將包含中文的字符串轉換成16進制md5值
m4 = hashlib.md5() m4.update("戰狼2真好看".encode(encoding="utf-8")) print(m4.hexdigest()) 輸出: ba284db74431c77acf84a309240a4a28
實例10: re模塊(正則表達式)
經常使用正則表達式符號
'.' 默認匹配除\n以外的任意一個字符,若指定flag DOTALL,則匹配任意字符,包括換行 '^' 匹配字符開頭,若指定flags MULTILINE,這種也能夠匹配上(r"^a","\nabc\neee",flags=re.MULTILINE) '$' 匹配字符結尾,或e.search("foo$","bfoo\nsdfsf",flags=re.MULTILINE).group()也能夠 '*' 匹配*號前的字符0次或屢次,re.findall("ab*","cabb3abcbbac") 結果爲['abb', 'ab', 'a'] '+' 匹配前一個字符1次或屢次,re.findall("ab+","ab+cd+abb+bba") 結果['ab', 'abb'] '?' 匹配前一個字符1次或0次 '{m}' 匹配前一個字符m次 '{n,m}' 匹配前一個字符n到m次,re.findall("ab{1,3}","abb abc abbcbbb") 結果'abb', 'ab', 'abb'] '|' 匹配|左或|右的字符,re.search("abc|ABC","ABCBabcCD").group() 結果'ABC' '(...)' 分組匹配,re.search("(abc){2}a(123|456)c", "abcabca456c").group() 結果 abcabca456c '\A' 只從字符開頭匹配,re.search("\Aabc","alexabc") 是匹配不到的 '\Z' 匹配字符結尾,同$ '\d' 匹配數字0-9 '\D' 匹配非數字 '\w' 匹配[A-Za-z0-9] '\W' 匹配非[A-Za-z0-9] 's' 匹配空白字符、\t、\n、\r , re.search("\s+","ab\tc1\n3").group() 結果 '\t' (摘自alex金角大王的cnblog)
匹配特定字符開頭
my_str = 'tianwanggaidihu1212' res1 = re.match('^tian',my_str) # 在my_str中匹配是否由"tian"開頭,若是匹配到有輸出下標 print(res1) res2 = re.match('^di',my_str) # 在my_str中匹配是否由"di"開頭,若是沒有匹配到返回None print(res2) 輸出: <_sre.SRE_Match object; span=(0, 4), match='tian'> None
匹配開頭是任意字符,第二位是數字
my_str = "w2192olegequ123" res1 = re.match("^.\d",my_str) # \d表明匹配一個數字 print(res1) 輸出: <_sre.SRE_Match object; span=(0, 2), match='w2'>
匹配開頭是任意字符,後面跟着連續N位都是數字
import re my_str = "h2310238feihong" res1 = re.match("^.\d+",my_str) print(res1) 輸出: <_sre.SRE_Match object; span=(0, 8), match='h2310238'>
匹配結尾是不是由連續N位數字結束
import re my_str = "ChengfengPolang000" res1 = re.search("\d+$",my_str) print(res1) 輸出: <_sre.SRE_Match object; span=(15, 18), match='000'>
匹配*號前的字符0次或屢次
import re my_str = "zhiquuweiquuuuShan1q110" res = re.findall("qu*",my_str) # u能夠爲0次匹配即q,或者屢次qu、quu、quuu... print(res) 輸出: ['quu', 'quuuu', 'q']
匹配指定長度的數字,N{m}表明匹配N這個字符m次,注意看re.search與re.findall的區別
import re my_str = "woaib23232eijingtia98989nan23sdfmen1" res1 = re.search("\d{5}",my_str) # \d表明匹配數字,re.search只匹配最初符合條件的字符 print(res1) res2 = re.findall("\d{5}",my_str) # re.findall匹配全部符合條件的字符 print(res2) 輸出: <_sre.SRE_Match object; span=(5, 10), match='23232'> ['23232', '98989']
匹配全部出現指定範圍內的數字,[0-9]{a,b}表明出現a到b次0-9之間的任意數字
import re my_str = "woaib23232eijingtia98989nan23sdfmen1" res1 = re.findall("[0-9]{1,5}",my_str) print(res1) 輸出: ['23232', '98989', '23', '1']
匹配 |(或)左右兩邊的字符
import re my_str = "woaib23232eijingtia98989nan23sdfmen1" res1 = re.findall("woai|jingtia",my_str) print(res1) res2 = re.search("woai|jingtia",my_str) print(res2) print(res2.group()) 輸出: ['woai', 'jingtia'] <_sre.SRE_Match object; span=(0, 4), match='woai'> woai
匹配分組,用()擴起來的能夠看做一個單獨的對象進行匹配
import re my_str = "TESTTEST111TESTtest222" res1 = re.findall("TEST{2}",my_str) print(res1) 輸出: ['TESTT'] res2 = re.findall("(TEST){2}",my_str) print(res2) 輸出: ['TEST'] res3 = re.search("TEST{2}",my_str) print(res3) 輸出: <_sre.SRE_Match object; span=(0, 5), match='TESTT'> res4 = re.search("(TEST){2}",my_str) print(res4) 輸出: <_sre.SRE_Match object; span=(0, 8), match='TESTTEST'>
\A表明匹配開始字符,\Z表明匹配結束字符
import re # re.search("\A[0-9].*[a-z]\Z",my_str)表明匹配開頭是數字,中間是任意內容,末尾必須是小寫字母的字符 my_str1 = "1232KHJKJlkda" res1 = re.search("\A[0-9].*[a-z]\Z",my_str1) print(res1) 輸出: <_sre.SRE_Match object; span=(0, 13), match='1232KHJKJlkda'> # re.search("\A[0-9]+[a-z]\Z",mystr)表明只匹配數字+小寫字母 my_str2 = "123abc" my_str3 = "123a" res2 = re.search("\A[0-9]+[a-z]\Z",my_str2) res3 = re.search("\A[0-9]+[a-z]\Z",my_str3) print(res2) print(res3) 輸出: None <_sre.SRE_Match object; span=(0, 4), match='123a'>
匹配除了數字以外的其餘任意字符
import re my_str = "2233-lkaP*098" res = re.search("\D+",my_str) # \D表明除數字外的任意字符 print(res) print(res.group()) 輸出: <_sre.SRE_Match object; span=(4, 10), match='-lkaP*'> -lkaP*
匹配[0-9a-zA-Z]字符,用\w來表達,匹配除了[0-9a-zA-Z]以外的字符用\W來表達。
import re my_str = "##123abcCDE!!" res1 = re.search("\w+",my_str) # 小寫的w print(res1) print(res1.group()) 輸出: <_sre.SRE_Match object; span=(2, 11), match='123abcCDE'> 123abcCDE res2 = re.search("\W+",my_str) # 大寫的W print(res2) print(res2.group()) 輸出: <_sre.SRE_Match object; span=(0, 2), match='##'> ##
匹配空白字符
import re my_str = "a b\nbc\t123 def\n(((" res1 = re.search("\s+",my_str) print(res1) 輸出: <_sre.SRE_Match object; span=(1, 2), match=' '> res2 = re.findall("\s+",my_str) print(res2) 輸出: [' ', '\n', '\t', ' ', '\n']
1.12 列表
列表是一個數據集合,用[ ]擴起來且以「,」進行分割,列表裏面能夠包含任何數據類型,如對象、列表等等。
# 建立一個空列表 result = list() print(result) 輸出: [] # 建立含有兩個元素的列表 result = [1,2] print(result) 輸出: [1, 2] # 建立包含不一樣類型元素的列表 result = ['a',False,2,1.342] print(result) 輸出: ['a', False, 2, 1.342] # append()在列表末尾添加元素 result = [1,2,3,4,5] print('原始result:',result) result.append(6) print('更新result:',result) 輸出: 原始result: [1, 2, 3, 4, 5] 更新result: [1, 2, 3, 4, 5, 6] # count()返回被選中元素在列表中出現的次數 result = ['a','b',1,False,'a','b','c','d'] num = result.count('a') print(num) 輸出: 2 # extend()能夠鏈接兩個列表裏全部的元素 list_a = ['a','b','c'] list_b = [1,2,3] list_a.extend(list_b) print(list_a) 輸出: ['a', 'b', 'c', 1, 2, 3] # 查找被選中元素在列表中的位置,注意起始位置從0開始 result = ['ab','weiu','^&hl',121231,'hello',0.0001,True,[1,2,3]] num = result.index('hello') print(num) 輸出: 4 # insert()函數在列表的指定位置上插入一個元素 list_a = ['a','b','c'] list_a.insert(0,'*') print(list_a) 輸出: ['*', 'a', 'b', 'c'] # pop()可將列表中的最後一個元素刪除而且返回被刪除的元素。 list_a = ['ab','weiu','^&hl',121231,'hello',0.0001,True,[1,2,3]] print('刪除前:',list_a) result = list_a.pop() print('刪除元素:',result) print('刪除後:',list_a) 輸出: 刪除前: ['ab', 'weiu', '^&hl', 121231, 'hello', 0.0001, True, [1, 2, 3]] 刪除元素: [1, 2, 3] 刪除後: ['ab', 'weiu', '^&hl', 121231, 'hello', 0.0001, True] # remove(元素),刪除元素。注意括號內的不是下標而是元素的內容 list_a = ['ab','weiu','^&hl',121231,'hello',0.0001,True,[1,2,3]] print('刪除前:',list_a) print('刪除元素:',list_a[0]) list_a.remove('ab') print('刪除後:',list_a) 輸出: 刪除前: ['ab', 'weiu', '^&hl', 121231, 'hello', 0.0001, True, [1, 2, 3]] 刪除元素: ab 刪除後: ['weiu', '^&hl', 121231, 'hello', 0.0001, True, [1, 2, 3]] # reverse()反轉列表 list_c = [1,2,3,4,5,'a','b','c','d','e'] print('反轉前:',list_c) list_c.reverse() print('反轉後:',list_c) 輸出: 反轉前: [1, 2, 3, 4, 5, 'a', 'b', 'c', 'd', 'e'] 反轉後: ['e', 'd', 'c', 'b', 'a', 5, 4, 3, 2, 1] # sort(),給列表排序,數據類型需一致,不然報錯 list_a = [1,267,0,986,5,-12,8,97,223] print('排序前:',list_a) list_a.sort() print('排序後:',list_a) 輸出: 排序前: [1, 267, 0, 986, 5, -12, 8, 97, 223] 排序後: [-12, 0, 1, 5, 8, 97, 223, 267, 986] list_b = ['r','g','v','e','j','s','k'] print('排序前:',list_b) list_b.sort() print('排序後:',list_b) 輸出: 排序前: ['r', 'g', 'v', 'e', 'j', 's', 'k'] 排序後: ['e', 'g', 'j', 'k', 'r', 's', 'v'] # 列表切片,list[a,b]表明從a的位置開始,截取到b-1下標位置的元素 list_a = ["zhangsan","harry","akira","natasha"] result = list_a[0:2] print(result) 輸出: ['zhangsan', 'harry'] # 列表切片,負數表示從末尾開始取值,最後一個值的下標記爲-1,從列表右側向左側第二個值的下標爲-2,以此類推 list_a = ["zhangsan","harry","akira","natasha"] result = list_a[-1] print(result) 輸出: natasha # 列表切片,特殊狀況爲負數切片的時候若是想獲取到最後一個元素(最右側的元素),原list[-a:-b]必須寫成list[-a:] list_a = ["zhangsan","harry","akira","natasha"] result = list_a[-3:-1] # 只能獲取到['harry', 'akira'] print(result) result = list_a[-3:] print(result) 輸出: ['harry', 'akira'] ['harry', 'akira', 'natasha'] # clear()用於清空列表的全部元素內容 list_b = [1,2,3,4,5] print('clear前:',list_b) list_b.clear() print('clear後:',list_b) 輸出: clear前: [1, 2, 3, 4, 5] clear後: []
1.13 元組
元組能夠當作是一組特殊的列表,與列表不一樣之處在於元組一經建立就不能被改變了,即不能對元組裏的數據進行刪除、更改甚至添加。所以元組一般用於存放一組不容許被用戶修改的數據。另外,列表使用[ ]擴起來,而元組則是使用( )擴起來。
# 建立空元組 result = tuple() print(result) 輸出: () # 建立只有一個元素的元組 result = ('h',) print(result,'\n類型:',type(result)) 輸出: ('h',) # 建立一個多元素的元組,並嘗試修改 result = ('ab','weiu','^&hl',121231,'hello',0.0001,True,[1,2,3]) print('第一個元素:',result[0]) result[0] = 'cd' print(result) 輸出: Traceback (most recent call last): File "/Users/***/PycharmProjects/python_basic/python教程/元組/tupleDemo.py", line 19, in <module> result[0] = 'cd' TypeError: 'tuple' object does not support item assignment
1.14 字典
字典(dict)也是一種數據類型,是由大括號{ }括起來同時以「鍵:值」對的形式來表現的,字典不像列表有下標,字典裏沒有下標概念因此字典是無序的。而若是想要訪問字典裏的內容則須要經過「鍵」來訪問「值」
# 建立一個空的字典 result = {} print(result,type(result)) 輸出: {} <class 'dict'> # 建立一個空的字典 result = dict() print(result,type(result)) 輸出: {} <class 'dict'> # 經過「鍵」來獲取「值」 dicDem = {'harry':20,'akira':19,'daniel':22,'susan':17} print('字典內容:',dicDem) res = dicDem["harry"] print('harry的值:',res) 輸出: 字典內容: {'harry': 20, 'akira': 19, 'daniel': 22, 'susan': 17} harry的值: 20 # 試圖用下標來獲取值,由於字典經過「鍵」來獲取,因此經過下標獲取值的時候會報錯。 dicDem = {'harry':20,'akira':19,'daniel':22,'susan':17} res = dicDem[1] print(res) 輸出報錯: Traceback (most recent call last): File "C:/Users/IH1407/PycharmProjects/PyDemo/Dict/dictDemo.py", line 24, in <module> res = dicDem[1] KeyError: 1 # dic.clear(),清除字典內容 dic_1 = {'a':1,'b':2,'c':3} print('清除前:',dic_1) dic_1.clear() print('清除後:',dic_1) 輸出: 清除前: {'a': 1, 'b': 2, 'c': 3} 清除後: {} # dic.copy(),複製字典給另外一個字典 dic_1 = {'a':1,'b':2,'c':3} dic_2 = dic_1.copy() print('dic_2複製了dic_1的鍵-值:',dic_2,type(dic_2)) 輸出: dic_2複製了dic_1的鍵-值: {'a': 1, 'b': 2, 'c': 3} <class 'dict'> # dic.get('k',[指定值]),要求字典返回鍵"k"所對應的值,若是沒有則返回中括號內的「指定值」 dic_1 = {'a':1,'b':2,'c':3} res = dic_1.get('a',['無值']) print(res) res = dic_1.get('d',['無值']) print(res) 輸出: 1 ['無值'] # 得到由鍵和值組成的迭代器 dicDem = {'harry':20,'akira':19,'daniel':22,'susan':17} print('鍵值迭代器:',dicDem.items()) 輸出: 鍵值迭代器: dict_items([('harry', 20), ('akira', 19), ('daniel', 22), ('susan', 17)]) # 獲取由鍵組成的迭代器 dicDem = {'harry':20,'akira':19,'daniel':22,'susan':17} print('鍵迭代器:',dicDem.keys()) 輸出: 鍵迭代器: dict_keys(['harry', 'akira', 'daniel', 'susan']) # 獲取由值組成的迭代器 dicDem = {'harry':20,'akira':19,'daniel':22,'susan':17} print('值迭代器:',dicDem.values()) 輸出: 值迭代器: dict_values([20, 19, 22, 17]) # 刪除指定鍵值對 dicDem = {'harry':20,'akira':19,'daniel':22,'susan':17} dicDem.pop('harry') print('刪除鍵值:',dicDem) 輸出: 刪除鍵值: {'akira': 19, 'daniel': 22, 'susan': 17} # 合併兩個字典,若是有相同的鍵值就覆蓋掉相同的部分,若是沒有相同的部分就建立新的鍵值。 dic_1 = {'a':1,'b':2,'c':3} dic_2 = {'c':3,'d':4,'e':5,'f':6} dic_1.update(dic_2) #由於dic_2與dic_1中的'c':3鍵值是重複的,因此覆蓋。 print('兩個字典合併後:',dic_1) 輸出: 兩個字典合併後: {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5, 'f': 6} # 從字典中刪除任意鍵值,並返回刪除的鍵值 dicDem = {'harry':20,'akira':19,'daniel':22,'susan':17} res = dicDem.popitem() print('刪除的鍵值:',res) print('刪除後的字典:',dicDem) 輸出: 刪除的鍵值: ('susan', 17) 刪除後的字典: {'harry': 20, 'akira': 19, 'daniel': 22} # dicDem = {'harry':20,'akira':19,'daniel':22,'susan':17} res = dicDem.setdefault('harry',18) print('harry(有):',res) res = dicDem.setdefault('merry',18) print('merry(無):',res) 輸出: harry(有): 20 merry(無): 18
1.15 購物車實例
需求:
1. 要求用戶輸入一個金額,而後打印商品列表
2. 用戶對想要買的商品經過商品編號將商品加入購物車
3. 用戶可屢次添加商品到購物車,訂單金額小於用戶輸入金額容許購買,不然提示餘額不足。
salary = int(input('請輸入您的金額:')) goods = [['1','iphone',7200],['2','imac pc',12000],['3','benz car',600000],['4','big house',1500000]] shopping_car = [] my_goods = [] fgx = '-'.center(40,'-') count = 0 money = 0 flag = True while flag: print('\n商品列表:') for i in goods: print(i[0],'\t',i[1],'\t',i[2]) goods_num = input('\n請選擇您要購買商品的序號以加入購物車:') for i in goods: if i[0] == goods_num: shopping_car.append(i) print('\n已加入購物車的商品:') for j in shopping_car: print('>>',j[1],'\t',j[2],'元') money = money + int(shopping_car[count][2]) count += 1 conf = input('\n繼續購買請按[C],去購物車支付請安[Y]: ') if conf == 'c': continue elif conf == 'y': conf_2 = input('您的商品訂單總額爲{price},確認付款請按[Y]: '.format(price=money)) if conf_2 == 'y': if salary >= money: salary = salary - money print(fgx,'\n\n購買成功!當前餘額:',salary) break else: print('餘額不足,請充值。') break 輸出1: 請輸入您的金額:20000 商品列表: 1 iphone 7200 2 imac pc 12000 3 benz car 600000 4 big house 1500000 請選擇您要購買商品的序號以加入購物車:1 已加入購物車的商品: >> iphone 7200 元 繼續購買請按[C],去購物車支付請安[Y]: c 商品列表: 1 iphone 7200 2 imac pc 12000 3 benz car 600000 4 big house 1500000 請選擇您要購買商品的序號以加入購物車:2 已加入購物車的商品: >> iphone 7200 元 >> imac pc 12000 元 繼續購買請按[C],去購物車支付請安[Y]: y 您的商品訂單總額爲19200,確認付款請按[Y]: y ---------------------------------------- 購買成功!當前餘額: 800 輸出2: 請輸入您的金額:20000 商品列表: 1 iphone 7200 2 imac pc 12000 3 benz car 600000 4 big house 1500000 請選擇您要購買商品的序號以加入購物車:1 已加入購物車的商品: >> iphone 7200 元 繼續購買請按[C],去購物車支付請安[Y]: c 商品列表: 1 iphone 7200 2 imac pc 12000 3 benz car 600000 4 big house 1500000 請選擇您要購買商品的序號以加入購物車:2 已加入購物車的商品: >> iphone 7200 元 >> imac pc 12000 元 繼續購買請按[C],去購物車支付請安[Y]: c 商品列表: 1 iphone 7200 2 imac pc 12000 3 benz car 600000 4 big house 1500000 請選擇您要購買商品的序號以加入購物車:3 已加入購物車的商品: >> iphone 7200 元 >> imac pc 12000 元 >> benz car 600000 元 繼續購買請按[C],去購物車支付請安[Y]: y 您的商品訂單總額爲619200,確認付款請按[Y]: y 餘額不足,請充值。
1.16 文件讀寫
文件和文件處理是任何高級語言都不可缺乏的一部分,Python語言提供了豐富的文件操做功能,包括文件讀寫操做、處理文件中的數據、fileinput操做文件及目錄操做等等。
測試讀寫文件1:testfile.txt
中國是世界上文明發達最先的國家之一,有將近4000年的有文字可考的歷史。 中國古代史經歷瞭如下幾個階段:原始社會(170萬年前-公元前2070年)、奴隸社會(公元前2070年-公元前476年)和封建社會。 其中封建社會可分爲五個階段:東周、秦、漢是封建社會造成和初步發展階段。 三國、兩晉、南北朝,是封建國家分裂和民族大融合的階段。 隋唐五代時期是封建社會的繁榮階段。遼、宋、夏、金、元,是民族融合進一步增強和封建經濟繼續發展的階段。 明、清,是統一的多民族國家鞏固和封建制度漸趨衰落階段。
測試讀寫文件2:pythonFile.txt
AAUUAA BJBBBB CCCCAC DDDDDB EEAEEE
測試代碼:
# open("filename","r/w/a/b",encoding="字符集"),read()表示讀取文件所有內容到內存文件對象中。 f = open("testfile.txt",'r',encoding="utf-8") print(f.read()) f.close() 輸出: 中國是世界上文明發達最先的國家之一,有將近4000年的有文字可考的歷史。 中國古代史經歷瞭如下幾個階段:原始社會(170萬年前-公元前2070年)、奴隸社會(公元前2070年-公元前476年)和封建社會。 其中封建社會可分爲五個階段:東周、秦、漢是封建社會造成和初步發展階段。 三國、兩晉、南北朝,是封建國家分裂和民族大融合的階段。 隋唐五代時期是封建社會的繁榮階段。遼、宋、夏、金、元,是民族融合進一步增強和封建經濟繼續發展的階段。 明、清,是統一的多民族國家鞏固和封建制度漸趨衰落階段。 # read()括號內添加數字表示讀取的字符個數。注意此字符既包括英文又包括漢字。 f = open("testfile.txt",'r',encoding="utf-8") print(f.read(3)) f.close() 輸出: 中國是 # readline()方法執行一次便打印其中一行,執行兩次打印其中兩行,以此類推。 f = open('testFile.txt','r',encoding='utf-8') print(f.readline()) print(f.readline()) f.close() 輸出: 中國是世界上文明發達最先的國家之一,有將近4000年的有文字可考的歷史。 中國古代史經歷瞭如下幾個階段:原始社會(170萬年前-公元前2070年)、奴隸社會(公元前2070年-公元前476年)和封建社會。 # readlines()則將文件內容所有打印,而且以列表到形式保存每一行,即每一行都是列表到一個元素。 f = open('testFile.txt','r',encoding='utf-8') print(f.readlines()) f.close() 輸出: ['中國是世界上文明發達最先的國家之一,有將近4000年的有文字可考的歷史。\n', '中國古代史經歷瞭如下幾個階段:原始社會(170萬年前-公元前2070年)、奴隸社會(公元前2070年-公元前476年)和封建社會。\n', '其中封建社會可分爲五個階段:東周、秦、漢是封建社會造成和初步發展階段。\n', '三國、兩晉、南北朝,是封建國家分裂和民族大融合的階段。\n', '隋唐五代時期是封建社會的繁榮階段。遼、宋、夏、金、元,是民族融合進一步增強和封建經濟繼續發展的階段。\n', '明、清,是統一的多民族國家鞏固和封建制度漸趨衰落階段。'] # open('filename','w/a',encoding='utf-8'),wirte()函數是將內容寫入到文件中。 # 模式選擇'w',即賦予寫權限,同時在寫入到時候將原有內容所有清除後再寫,使用該模式時請慎重選擇。 f = open('testFile.txt','w',encoding='utf-8') f.write('write test') f.close() f = open('testFile.txt','r',encoding='utf-8') print(f.read()) f.close() 輸出(寫入到文件的內容): write test
實例1: 使用while循環打印readline()
f = open('testFile.txt','r',encoding='utf-8') print(f.readline()) while True: line = f.readline() print(line) if not line: break
f.close() 輸出: 中國是世界上文明發達最先的國家之一,有將近4000年的有文字可考的歷史。 中國古代史經歷瞭如下幾個階段:原始社會(170萬年前-公元前2070年)、奴隸社會(公元前2070年-公元前476年)和封建社會。 其中封建社會可分爲五個階段:東周、秦、漢是封建社會造成和初步發展階段。 三國、兩晉、南北朝,是封建國家分裂和民族大融合的階段。 隋唐五代時期是封建社會的繁榮階段。遼、宋、夏、金、元,是民族融合進一步增強和封建經濟繼續發展的階段。 明、清,是統一的多民族國家鞏固和封建制度漸趨衰落階段。
實例2: 使用for循環打印readline()
f = open('testFile.txt','r',encoding='utf-8') for line in f: print(line) f.close() 輸出: 中國是世界上文明發達最先的國家之一,有將近4000年的有文字可考的歷史。 中國古代史經歷瞭如下幾個階段:原始社會(170萬年前-公元前2070年)、奴隸社會(公元前2070年-公元前476年)和封建社會。 其中封建社會可分爲五個階段:東周、秦、漢是封建社會造成和初步發展階段。 三國、兩晉、南北朝,是封建國家分裂和民族大融合的階段。 隋唐五代時期是封建社會的繁榮階段。遼、宋、夏、金、元,是民族融合進一步增強和封建經濟繼續發展的階段。 明、清,是統一的多民族國家鞏固和封建制度漸趨衰落階段。
實例3: 定義一個函數,只打印文件中偶數行的內容
def file_hdl(name): f = open(name) i = 0 print('打印偶數行內容:') for line in f : i += 1 if i % 2 == 0 : print('第%s行:' % i,line) else: continue f.close() file_hdl('testFile.txt') 輸出: 打印偶數行內容: 第2行: 中國古代史經歷瞭如下幾個階段:原始社會(170萬年前-公元前2070年)、奴隸社會(公元前2070年-公元前476年)和封建社會。 第4行: 三國、兩晉、南北朝,是封建國家分裂和民族大融合的階段。 第6行: 明、清,是統一的多民族國家鞏固和封建制度漸趨衰落階段。
實例4: 使用with語句來進行文件管理,同時定義函數只打印奇數行內容
def file_hdl(name): with open(name) as f: i = 0 for line in f: i += 1 if i % 2 != 0: print('第{line_row}行:{line_cont}'.format(line_row=i,line_cont=line)) f.close() file_hdl('testFile.txt') 輸出: 第1行:中國是世界上文明發達最先的國家之一,有將近4000年的有文字可考的歷史。 第3行:其中封建社會可分爲五個階段:東周、秦、漢是封建社會造成和初步發展階段。 第5行:隋唐五代時期是封建社會的繁榮階段。遼、宋、夏、金、元,是民族融合進一步增強和封建經濟繼續發展的階段。
實例5: 使用fileinput模塊讀取兩個文件到列表中,而後依次識別文件名,並打印單一文件行數、總文件行數以及文件內容,line.strip()去掉空白行,同時找出包含'會'與'A'的行。
import fileinput with fileinput.input(['testFile.txt','pythonFile.txt']) as lines: for line in lines: if fileinput.isfirstline(): print('\n>>>當前文件名稱:{file_name}'.format(file_name=fileinput.filename())) print(' 總第%d行\t當前文件的第%d行\t內容:%s' % (fileinput.lineno(),fileinput.filelineno(),line.strip())) if line.count('會') != 0: print(' >>第%d行有%d個\'會\'\n' %(fileinput.lineno(),line.count('會'))) if line.count('A') != 0: print(' >>第%d行有%d個\'A\'\n' %(fileinput.lineno(),line.count('A'))) 輸出: >>>當前文件名稱:testFile.txt 總第1行 當前文件的第1行 內容:中國是世界上文明發達最先的國家之一,有將近4000年的有文字可考的歷史。 總第2行 當前文件的第2行 內容:中國古代史經歷瞭如下幾個階段:原始社會(170萬年前-公元前2070年)、奴隸社會(公元前2070年-公元前476年)和封建社會。 >>第2行有3個'會' 總第3行 當前文件的第3行 內容:其中封建社會可分爲五個階段:東周、秦、漢是封建社會造成和初步發展階段。 >>第3行有2個'會' 總第4行 當前文件的第4行 內容:三國、兩晉、南北朝,是封建國家分裂和民族大融合的階段。 總第5行 當前文件的第5行 內容:隋唐五代時期是封建社會的繁榮階段。遼、宋、夏、金、元,是民族融合進一步增強和封建經濟繼續發展的階段。 >>第5行有1個'會' 總第6行 當前文件的第6行 內容:明、清,是統一的多民族國家鞏固和封建制度漸趨衰落階段。 >>>當前文件名稱:pythonFile.txt 總第7行 當前文件的第1行 內容:AAUUAA >>第7行有4個'A' 總第8行 當前文件的第2行 內容:BJBBBB 總第9行 當前文件的第3行 內容:CCCCAC >>第9行有1個'A' 總第10行 當前文件的第4行 內容:DDDDDB 總第11行 當前文件的第5行 內容:EEAEEE >>第11行有1個'A'
1.17 目錄操做
python的os模塊提供了一些操做文件和目錄的功能,能夠很方便的重命名文件名、添加刪除目錄、複製目錄文件等操做。
import os # 當前目錄路徑: os.getcwd() print('當前目錄路徑:',os.getcwd()) 輸出: 當前目錄路徑: /Users/pentest/PycharmProjects/python_basic/python教程/文件與文件系統/directory # 列出當前執行文件所在目錄的全部文件 print('獲取當前目錄全部文件:',os.listdir()) 輸出: 獲取當前目錄全部文件: ['direDemo.py', 'subDirec', '三國演義.mp4', '工資單.txt'] # 列出指定目錄下的文件 print('列出指定目錄內容:',os.listdir('/Users/pentest/learngit')) 輸出: 列出指定目錄內容: ['.DS_Store', 'hello python'] # 使用os.mkdir()建立目錄,所建立的目錄必須是不存在的,不然報錯。 os.mkdir('/Users/pentest/learngit/python') print('添加目錄python後:',os.listdir('/Users/pentest/learngit')) 輸出: 添加目錄python後: ['.DS_Store', 'hello python', 'python'] # 刪除目錄,使用os.rmdir()刪除的目錄必須是空目錄,必須是已存在的目錄,不然都會報錯 os.rmdir('/Users/pentest/learngit/python') print('刪除目錄python後:',os.listdir('/Users/pentest/learngit/')) 輸出: 刪除目錄python後: ['.DS_Store', 'hello python'] # 判斷是不是目錄 print(os.path.isdir('/Users/pentest')) print(os.path.isdir('工資單.txt')) 輸出: True False # 判斷是不是文件 print(os.path.isfile('/Users/pentest')) print(os.path.isfile('工資單.txt')) 輸出: False True # 使用os.walk(path)能夠遍歷某目錄下全部的文件和目錄,可是os.walk()的返回對象只是一個能夠迭代的生成器對象,若是想要打印每一個元素能夠經過for循環進行打印。打印結果保存在元組中,單引號擴起來的是目錄,後邊用[]擴起來的是每一個元素內容。 result = os.walk('./') # 指定當前目錄 print(result,type(result)) for i in result: print(i) 輸出: <generator object walk at 0x102a144c0> <class 'generator'> ('./', ['subDirec'], ['direDemo.py', '三國演義.mp4', '工資單.txt']) ('./subDirec', [], ['wolegequ.html'])
實例1: 批量收集文件,並彙總各種信息到excel表格
用戶需求:
1)接收用戶輸入一個路徑,該路徑中包含待收集文件,且文件名的組成方式爲用戶名 + 2位數字ID號 + .txt後綴 2)用戶執行腳本後應自動生成後綴爲.xls的excel文件,且表格中應包含目錄文件的ID列,用戶姓名列以及文件內容列。 3)待收集文件路徑 $ pwd /Users/pentest/learngit/userInfo/ 4)待收集文件列表 $ ll total 24 -rw-r--r-- 1 pentest staff 28 7 19 11:20 akira33.txt -rw-r--r--@ 1 pentest staff 87 7 19 13:31 harry99.txt -rw-r--r-- 1 pentest staff 40 7 19 11:20 natasha12.txt
代碼實現:
import os import fileinput filenames = [] fname = 'userInfo_' file_path = input('please input file path: ') # for循環中變量a,b,files分別表明如下含義: # a = ./userInfo 文件執行路徑 # b = [] 空列表 #files = ['akira33.txt', 'natasha12.txt','harry99.txt'] files纔是要操做的用戶信息 # 將目錄中全部文件名(不包括後綴)所有添加到filenames列表裏。 for a,b,files in os.walk(file_path): if files: index = 0 filenames.append([file[:-4] for file in files]) i = 0 for files in filenames: # 生成新文件用於保存用戶信息,文件名組成方式:userInfo_ + 數字 + .xls f = open(fname+str(i)+'.xls','w',encoding='utf-8') # 在第一行中寫入'UserId','UserName','Summary'到三個列 count = 0 for name in files: if count == 0 : f.write('UserId'+'\t'+'UserName'+'\t'+'Summary'+'\n') # 以只讀模式打開./userInfo/name.txt文件,如harry99.txt,natasha12.txt等 f_cont = open(file_path+name+'.txt','r',encoding='utf-8') # 向新建文件裏寫入用戶信息,包括:文件名後兩位的ID號+第1位到倒數後兩位之間的用戶名+對應文件的內容 f.write(name[-2:]+'\t'+name[:-2]+'\t'+f_cont.read()+'\n') count += 1 f.close() i += 1 print('新文件生成成功!') 輸出: please input file path: /Users/pentest/learngit/userInfo/ 新文件生成成功!
1.18 函數
Python函數類別有內建函數和自定義函數,其中內建函數就是以上實例中屢次用到的方法,例如range(),input()及數據類型轉換函數等等。可是不少時候開發者須要解決本身的實際問題的時候內建函數未必夠用,這個時候就須要本身寫函數了,這個就是所謂的自定義函數。而使用函數的好處就是能夠調用函數來完成一些重複性的工做,且結構清晰易於維護。
聲明函數
def <函數名> (參數列表): <函數語句> return 返回值 其中,參數列表與return返回值都不是必須的,當沒有return語句或者return後沒有返回值的時候均會返回None。
應用函數:
# 定義並調用函數,打印hello,python def hello(): # 聲明函數 print('hello,python') hello() # 調用函數 輸出: hello,python # 定義一個有參數列表的函數,調用時需給出符合函數計算的參數 def tpl_sum(arg): result = 0 for item in arg: result += item return result result2 = tpl_sum([1,2,3,4,5]) print(result2) 輸出: 15 # 默認值參數,函數能夠設定一個默認值參數,若是調用時不給出其餘參數那麼就會執行默認值參數,如下代碼中須要給出參數有name和age,其中age設定了默認值18歲,若是用戶在調用函數的時候沒有給定具體age值,那麼默認輸出18。注意事項,含有默認值的參數須要放在參數列表的最後面,不然會報錯。 def userInfo(name,age=18): print('my name is %s,and i\'m %d !' % (name,age)) userInfo('harry',20) userInfo('akira') #調用時沒有給定具體age值則輸出默認age值18。 輸出: my name is harry,and i'm 20 ! my name is akira,and i'm 18 ! # 參數傳遞(按照參數名匹配傳遞):通常狀況下在調用python的函數時會依據函數的參數列表的順序進行傳參,但python提供了形爲"關鍵字=關鍵字"的參數傳遞方式,如此以來就沒必要按着函數參數列表的順序進行傳參了。 def userInfo(name,age): print('my name is %s,and i\'m %d !' % (name, age)) userInfo(age=20,name='daniel') # 傳遞參數時未按順序給出參數。 輸出: my name is daniel,and i'm 20 !
實例1: 充分理解函數調用的可重用性,一致性以及可擴展性
如下代碼中,函數test一、test二、test3均會調用logger()函數,起初logger函數完成的功能只是將"end action"寫入到def_test1.txt文件中。但新的需求提出須要繼續在logger函數中日誌的前面添加時間模塊,而新添加的時間模塊都可以在調用logger函數的其餘函數裏有體現,也就是說修改了logger函數後就不須要再在其餘幾個函數裏分別進行添加時間模塊了。由此充分體現了函數調用的可重用性,一致性以及可擴展性。 import time def logger(): time_format = '%Y-%m-%d %X' # %X表明小時:分鐘:秒 time_current = time.strftime(time_format) with open('def_test1.txt','a+',encoding='utf-8') as f: f.write('%s : end action\n' % time_current) f.close() def test1(): print('in the test1') logger() def test2(): print('in the test2') logger() def test3(): print('in the test3') logger() test1() test2() test3() 輸出(控制檯): in the test1 in the test2 in the test3 輸出(def_test1.txt): 2017-07-21 15:55:29 : end action 2017-07-21 15:55:29 : end action 2017-07-21 15:55:29 : end action
實例2: 函數返回值的幾種形式
>無return語句時返回None >有return且值爲惟一的時候,返回該惟一值 >有return且值爲多個的時候,返回一個元組,元組裏的元素爲return返回的多個值。 def def_return1(): print('hello python1') def def_return2(): print('hello python2') return 0 def def_return3(): print('hello python3') return 'world',123,['a','b','c'],{'name':'akira'} d1 = def_return1() d2 = def_return2() d3 = def_return3() print('d1:',d1) print('d2:',d2) print('d3:',d3) 輸出: hello python1 hello python2 hello python3 d1: None d2: 0 d3: ('world', 123, ['a', 'b', 'c'], {'name': 'akira'})
1.19 類和對象
Python中具備相同屬性或能力的模型在面向對象編程中以類進行定義和表示的,由類能夠派生出(實例化)出同類的各個實例就是對象。
定義類:
# 使用class關鍵字進行定義,其中父類爲可選項,若是不繼承任何父類則括號都不須要寫。 class <類名> (父類) pass # 定義一個不含父類的類 class MyClass: pass # 若是一個類表面上沒有繼承任何類但實際上它是繼承了內建的object類,使用dir()函數來查看MyClass從object類那裏繼承來的屬性和方法 print(dir(MyClass)) 輸出: ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
實例化:
類在定義後必須先實例化後纔可使用,類的實例化跟函數調用相似,只要使用類名加圓括號的形式就能夠實例化一個類。類實例化之後會生成該類的一個實例,一個類能夠實例化多個實例,實例和實例之間並不會相互影響,類實例化之後就能夠直接使用了。 class MyClass: # 定義一個類 "MyClass help." myclass = MyClass() # 實例化一個類 print('輸出類說明:') print(myclass.__doc__) # 輸出類實例myclass的屬性__doc__的值(類說明) print('\n顯示類幫助信息:') print(help(myclass)) 輸出: 輸出類說明: MyClass help. 顯示類幫助信息: Help on MyClass in module __main__ object: class MyClass(builtins.object) # 繼承了object類 | MyClass help. | | Data descriptors defined here: | | __dict__ | dictionary for instance variables (if defined) | | __weakref__ | list of weak references to the object (if defined)
類的方法
類中的方法的定義和調用與函數定義和調用基本相同,其區別有: >方法的第一個參數必須是self,並且不能省略。可是在經過實例調用方法的時候能夠不用提供self參數。 >方法的調用須要實例來調用,而且以實例名.方法名(參數列表)形式調用 >總體進行一個單位的縮進,表示其屬於類體中的內容 class MyClass: def info(self): print('>>>info method!') def mycacl(self,x,y): return x + y mc = MyClass() print('調用info方法:') mc.info() print('調用mycacl方法:') result = mc.mycacl(3,4) print(result) 輸出: 調用info方法: >>>info method! 調用mycacl方法: 7
構造方法
python的構造方法用__init__()方法來表示,用於類實例化時初始化相關數據,若是在這個方法中有相關參數,則實例化時就必須提供。 class UserInfo: def __init__(self,name,age=18): #此方法爲構造方法,參數中的age被設置成了默認參數 self.name = name self.age = age def user(self): return 'name:{_name}\tage:{_age}'.format(_name=self.name,_age=self.age) # 實例化的時候必須給name傳參,age可傳可不傳,不傳的時候使用默認age=18。 # 另外,調用方法的時候必須使用實例來調用。 dia = UserInfo('akira',22) print('調用user-akira方法的結果:') print(dia.user()) dib = UserInfo('susan') print('調用user-susan方法的結果:') print(dib.user()) 輸出: 調用user-akira方法的結果: name:akira age:22 調用user-susan方法的結果: name:susan age:18
構造函數中存在指定的參數時,實例化對象時必須給定相應的參數
class person : def __init__(self,name): # 構造函數 self.name = name def showName(self): print(self.name) p1 = person() # 由於構造函數要求name參數,而p1實例化時未給出因此報錯 print(p1) 輸出: Traceback (most recent call last): File "/Users/PycharmProjects/python_basic/python教程/類和對象/alex/xigou函數.py", line 14, in <module> p1 = person() TypeError: __init__() missing 1 required positional argument: 'name' p2 = person('jack') # 實例化時給出了構造函數要求的name參數,因此不會報錯 print(p2.showName()) 輸出: jack
類中方法內部調用全局函數
類中的方法內部既能夠調用本類中的其餘方法,也能夠調用全局函數來完成相關工做。調用全局函數和麪向過程當中的調用方式徹底相同,而調用本類中的方法應使用self.方法名(參數列表)的形式完成。另外,調用本類中的方法時提供的參數列表中也仍不需包含self。 def coord_chng(x,y): # coord_chng(x,y)是全局函數 return (abs(x),abs(y)) class Ant: def __init__(self,x=0,y=0): # __init__()爲構造方法 self.x = x self.y = y self.disp_point() # 調用類中的其餘方法,顯示座標位置 def move(self,x,y): x,y = coord_chng(x,y) # 調用全局函數,注意看此時並無實例進行調用,而是直接使用函數 self.edit_point(x,y) # 調用類中的其餘方法 self.disp_point() def edit_point(self,x,y): self.x += x self.y += y def disp_point(self): print("當前位置:(%s,%d)" % (self.x,self.y)) # 建立實例ant_a,調用構造方法,因構造方法中x、y均是默認參數,因此不傳參也能夠。 ant_a = Ant() # 實例調用move方法,將2,4賦值給x,y。在move方法內再次調用全局函數coord_chng(x,y)進行取絕對值。 ant_a.move(2,4) # 實例調用move方法,將-9,6賦值給x,y(通過上一步此時x,y爲2,4),而後在調用coord_chng方法進行取絕對值,而後調用edit_point()方法對x,y均進行加等於操做,在調用dis_point()方法進行顯示座標。 ant_a.move(-9,6) 輸出: 當前位置:(0,0) 當前位置:(2,4) 當前位置:(11,10)
類的屬性
類的屬性能夠看做是數據,而類的方法就是用來操做類的屬性(數據)的。在Python語言中類的屬性分爲實例屬性與類屬性兩種,實例屬性即同一個類中的不一樣實例,其值是不相關聯的,定義時使用"self.屬性名",調用時也適用它。類屬性則是同一個類的全部實例都共有的,直接在類體中獨立定義,引用時要使用"類名.類屬性"形式來調用,只要時某個實例對其修改過,就會影響其餘全部實例調用這個類屬性的結果。 class Demo_Property: class_name = "Demo_Property" # 建立類屬性class_name def __init__(self,x = 0): # 構造方法,用於給實例屬性賦值 self.x = x def class_info(self): # 類方法,用於顯示類屬性與實例屬性 print('類屬性值:',Demo_Property.class_name) print('實例變量值:',self.x) def chng(self,x): # 修改實例屬性的方法 self.x = x def chng_cn(self,name): # 修改類屬性的方法 Demo_Property.class_name = name dpa = Demo_Property() # 實例化對象dpa dpb = Demo_Property() # 實例化對象dpb print('初始化兩個實例:') dpa.class_info() dpb.class_info() 輸出: 初始化兩個實例: 類屬性值: Demo_Property 實例變量值: 0 類屬性值: Demo_Property 實例變量值: 0 print('\n修改dpa實例變量:') dpa.chng(3) # 修改實例dpa的屬性 dpa.class_info() dpb.class_info() 輸出: 修改dpa實例變量: 類屬性值: Demo_Property 實例變量值: 3 類屬性值: Demo_Property 實例變量值: 0 print('\n修改dpb實例變量:') dpb.chng(4) dpa.class_info() dpb.class_info() 輸出: 修改dpb實例變量: 類屬性值: Demo_Property 實例變量值: 3 類屬性值: Demo_Property 實例變量值: 4 print('\n使用實例dpa對類的屬性class_name進行修改') dpa.chng_cn('dpa') dpa.class_info() dpb.class_info() 輸出: 使用實例dpa對類的屬性class_name進行修改 類屬性值: dpa 實例變量值: 3 類屬性值: dpa 實例變量值: 4 print('\n使用實例dpb對類的屬性class_name進行修改') dpb.chng_cn('dpb') dpa.class_info() dpb.class_info() 輸出: 使用實例dpb對類的屬性class_name進行修改 類屬性值: dpb 實例變量值: 3 類屬性值: dpb 實例變量值: 4
類的成員方法和靜態方法
類的屬性有類屬性和實例屬性之分,類的方法也有不一樣的種類,主要有: >實例方法:前文案例中類中的方法均爲實例方法,調用時須要實例化。 >類方法:定義時使用裝飾器@classmethod進行裝飾,必須有默認參數cls。調用時可直接由類名進行調用,調用前不須要實例化,固然也可使用任何一個實例來進行調用。 >靜態方法:定義時應使用@staticmethod進行修飾,沒有默認參數。調用時可直接由類名進行調用,調用前不須要實例化,固然也可使用任何一個實例來進行調用。 注意事項:在靜態方法和類方法中不能使用實例屬性,由於可能調用時類尚未實例化。 class DemoMthd: @staticmethod # 靜態方法裝飾器 def static_mthd(): print('調用了靜態方法!') @classmethod # 類方法裝飾器 def class_mthd(cls): print('調用了類方法!') print('\n經過類名來調用靜態方法和類方法:') DemoMthd.static_mthd() # 經過類名調用靜態方法 DemoMthd.class_mthd() # 經過類名調用類方法 輸出: 經過類名來調用靜態方法和類方法: 調用了靜態方法! 調用了類方法! print('\n經過實例來調用靜態方法和類方法:') dm = DemoMthd() #實例化dm dm.static_mthd() #經過實例調用靜態方法 dm.class_mthd() #經過實例調用類方法 輸出: 經過實例來調用靜態方法和類方法: 調用了靜態方法! 調用了類方法!
類的私有屬性和私有方法
一般在Python中可使用雙下劃線開頭的方法或屬性來達到私有函數或私有屬性的目標,但事實上,這個所謂的"私有"更多的是一個強拼硬湊的慣用法。只是一種程序員約定俗稱的規定,加了就表示私有變量,可是你若是要在外部調用的話,仍是能夠調用的。 調用方法: 私有變量:實例._類名__變量名 私有方法:實例._類名__方法名() class person(): def __init__(self,name,salary): self.name = name self.__salary = salary #定義私有屬性 def __showSalary(self): #定義私有方法 print('薪水:',self.__salary) def showInfo(self): # 用於顯示私有屬性的方法,可被外部調用 print("name:%s salary:%s" % (self.name,self.__salary)) p = person('jack',10000) p.showInfo() # 經過方法用於顯示私有屬性 輸出: name:jack salary:10000 print('name:',p.name) 輸出: name: jack p.__showSalary() # 調用私有方法 輸出: Traceback (most recent call last): File "/Users/PycharmProjects/python_basic/python教程/類和對象/alex/私有屬性和方法.py", line 28, in <module> p.__showSalary() # 調用私有方法 AttributeError: 'person' object has no attribute '__showSalary' print('salary:',p.salary) # 調用私有屬性,嘗試不帶兩個下劃線 輸出: File "/Users/PycharmProjects/python_basic/python教程/類和對象/alex/私有屬性和方法.py", line 19, in <module> name: jack print('salary:',p.salary) AttributeError: 'person' object has no attribute 'salary' print('salary:',p.__salary) # 調用私有屬性,嘗試帶兩個下劃線 輸出: Traceback (most recent call last): File "/Users/PycharmProjects/python_basic/python教程/類和對象/alex/私有屬性和方法.py", line 28, in <module> print('salary:',p.__salary) AttributeError: 'person' object has no attribute '__salary' # 接下來,查看正確的調用私有屬性和私有方法的方式: print('調用私有屬性:',p._person__salary) # 實例._類名__屬性名 輸出: 調用私有屬性: 10000 print('調用私有方法:') p._person__showSalary() # 實例._類名__方法名 輸出: 調用私有方法: 薪水: 10000
類的繼承
子類繼承父類以後,就具備了父類的的屬性和方法,但不能繼承父類的私有屬性和私有方法(屬性名或方法名前綴爲兩個下劃線的),子類中還能夠重載來修改父類的方法,以實現與父類不一樣的行爲表現或能力。 class Ant: # 定義父類 def __init__(self,x=0,y=0,color='black'): # 定義構造方法 self.x = x self.y = y self.color = color def crawl(self,x,y): # 定義方法,爬行功能 self.x = x self.y = y print('爬行...') self.info() # 打印位置信息 def info(self): # 打印位置方法 print('當前位置:(%d,%d)' % (self.x,self.y)) def attack(self): # 定義方法,攻擊功能 print("用嘴咬!") class FlyAnt(Ant): # 定義子類FlyAnt類,繼承Ant類,此時FlyAny類擁有Ant的全部非私有方法和屬性了。 def attack(self): # 從新修改父類Ant類的attack()方法:重載。 print("用尾針!") def fly(self,x,y): # 定義特有方法fly(),屬於新添加的方法 print('飛行...') self.x = x self.y = y self.info() flyant = FlyAnt(color='red') flyant.crawl(3,5) flyant.fly(10,14) flyant.attack() # 由於attack()被從新修改了,因此方法由"用嘴咬"改成了"用尾針"。 輸出: 爬行... 當前位置:(3,5) 飛行... 當前位置:(10,14) 用尾針!
多重繼承
Python語言容許多重繼承,即一個類能夠繼承多個類。多重繼承的方式在類定義時的繼承父類的括號中,以","分隔開要多重繼承的父類便可。多重繼承的時候,繼承的順序也是一個很重要的元素,若是繼承的多個元素中有相同的方法名,但在類中使用時未指定父類名,則pyhon解釋器將從左到右搜索,即調用先繼承的類中的同名方法。 class PrntA: namea = 'PrntA' def set_value(self,a): self.a = a def set_namea(self,namea): PrntA.namea = namea def info(self): # 與PrntB有相同的info()方法 print('PrintA:%s,%s' % (PrntA.namea,self.a)) class PrntB: nameb = 'PrntB' def set_nameb(self,nameb): PrntB.nameb = nameb def info(self): # 與PrntA有相同的info()方法 print('PrntB:%s' % (PrntB.nameb)) class Sub(PrntA,PrntB): # 因PrntA與PrntB有相同的info方法,同時參數列表裏PrntA排在PrntB的前邊,若是要調用則優先調用PrntA的info方法。 pass class Sub2(PrntB,PrntA): pass print('使用第一個子類:') sub = Sub() sub.set_value('aaaa') sub.info() # 此處調用PrntA的info方法,打印PrintA:PrntA,aaaa sub.set_nameb('BBBB') sub.info() # 此處仍然調用PrntA的info方法,仍然打印PrintA:PrntA,aaaa 輸出: 使用第一個子類: PrintA:PrntA,aaaa PrintA:PrntA,aaaa print('使用第二個子類:') sub2 = Sub2() sub2.set_value('aaaa') sub2.info() # 此處調用PrntB的info方法,由於上一步的"sub.set_nameb('BBBB')"已將nameb更改成了BBBB,因此打印打印PrntB:BBBB sub2.set_nameb('BBBB') sub2.info() # 此處仍然調用PrntB的info方法,由於上一步的sub2.set_nameb('BBBB')已將nameb再次更改成了BBBB,因此打印PrntB:BBBB 輸出: 使用第二個子類: PrntB:BBBB PrntB:BBBB
class People: # 父類1 def __init__(self,name,age): self.name = name self.age = age def eat(self): print("%s is eatting..." % self.name) def run(self): print("%s is running..." % self.name) def look(self): print("%s is looking... in the People Class" % self.name) class Human: # 父類2 def __init__(self,name,age): self.name = name self.age = age def look(self): print("%s is looking... in the Human Class" % self.name) # 雖然Man類內部無任何屬性和方法,但因其繼承了父類People,自動擁有父類的全部屬性和方法。 # Man是多繼承,繼承順序是People,Human,當People與Human含有相同的方法look的時候,優先繼承前邊的類People中的look方法。 class Man(People,Human): # 子類1 pass # 雖然Woman類內部無任何屬性和方法,但因其繼承了父類People,自動擁有父類的全部屬性和方法。 # Woman是多繼承,繼承順序是Human,People,當People與Human含有相同的方法look的時候,優先繼承前邊的類Human中的look方法。 class Woman(Human,People): # 子類2 pass m1 = Man('jack',20) m1.eat() m1.run() m1.look() # 由於Man類中的繼承順序是People,Human,因此優先繼承People中的look()方法 print() w1 = Woman('rose',19) w1.eat() w1.run() w1.look() # 由於Woman類中的繼承順序是Human,People,因此優先繼承Human中的look()方法 輸出: jack is eatting... jack is running... jack is looking... in the People Class rose is eatting... rose is running... rose is looking... in the Human Class m1 = Man() # 雖然實例化子類,但實例化時括號內的參數仍然要與父類的構造方法相匹配,不然報錯 輸出: Traceback (most recent call last): File "/Users/PycharmProjects/python_basic/python教程/類和對象/alex/jicheng.py", line 24, in <module> m1 = Man() TypeError: __init__() missing 2 required positional arguments: 'name' and 'age'
廣度繼承
class A class B(A) class C(A) class D(B,C)
繼承關係如上所示,廣度繼承是即爲最下層的classD繼承後函數的執行優先順序是B->C-A,以下圖所示:
從如下四個場景來看廣度繼承的關係:
場景1: class D有本身的方法,執行本身的方法
class A : def show(self): print('form A...') class B (A): def show(self): print('from B...') class C (A): def show(self): print('from C...') class D (B,C): def show(self): print('from D...') d = D() d.show() 輸出: from D...
場景2: class D沒有本身的方法,執行class B的方法
class A : def show(self): print('form A...') class B (A): def show(self): print('from B...') class C (A): def show(self): print('from C...') class D (B,C): pass d = D() d.show() 輸出: from B...
場景3:class D沒有本身的方法,class B也沒有本身的方法,執行class C的方法
class A : def show(self): print('form A...') class B (A): pass class C (A): def show(self): print('from C...') class D (B,C): pass d = D() d.show() 輸出: from C...
場景4:class D沒有本身的方法,class B也沒有本身的方法,class C也沒有本身的方法,最後執行class A的方法
class A : def show(self): print('form A...') class B (A): pass class C (A): pass class D (B,C): pass d = D() d.show() 輸出: form A...
方法重載
子類繼承了父類的屬性和方法,但子類想要對繼承來的父類方法進行修改就是方法重載,以實現與父類不一樣的表現行爲與能力。 class Person: # 定義父類 def __init__(self,name,age): self.name = name self.age = age def walks(self): # 父類的walks方法只實現了"走"的功能 print("%s is walking..." % self.name) class OldMan(Person): # 繼承父類Person,並沒作任何修改 pass class Children(Person): def walks(self): # 子類Children繼承了Person,並對walks方法進行修改添加了sing功能,叫作方法重載。 print("%s is walks and sings at the same time" % self.name) om = OldMan('natasha',88) om.walks() # 調用父類的walks方法 cd = Children('akira',17) cd.walks() # 調用重載後的方法 輸出: natasha is walking... akira is walks and sings at the same time
__doc__查看類的描述信息
__doc__ ,用於表達類的表述信息,使用類名.__doc__進行調用。 class Person: ''' 這個類是用來建立人的,建立時須要提供一個name參數。 ''' def __init__(self,name): self.name = name def showName(self,name): print('name:',self.name) print(Person.__doc__) 輸出: 這個類是用來建立人的,建立時須要提供一個name參數。
__module__ & __class__確認類的出自及類名信息
__module__: 輸出模塊所在處 __class__: 輸出類信息 目錄結構: -- 類和對象 ---- lib(Package) ------ car.py ------ __init__.py ---- myTest.py ------------------------------ car.py class Mycar: def __init__(self,car_name): self.name = car_name ------------------------------ myTest.py from lib.car import Mycar mc = Mycar('benz') # 返回Mycar是從哪一個模塊導入的(確認類從哪裏導入的) print(mc.__module__) # 輸出這個類自己 print(mc.__class__) 執行myTest.py輸出: lib.car <class 'lib.car.Mycar'>
__call__:經過對象()調用函數
構造方法的執行是由建立對象觸發的,即:對象 = 類名();而對於__call__方法的執行則是由對象後加括號觸發的,即對象()或類()() 對象經過提供__call__(slef, [,*args [,**kwargs]])方法能夠模擬函數的行爲,若是一個對象x提供了該方法,就能夠像函數同樣使用它,也就是說x(arg1, arg2...) 等同於調用x.__call__(self, arg1, arg2)。 class Person: def __init__(self,name,age): self.name = name self.age = age def info(self): print('%s\'s age is %s' %(self.name,self.age)) def __call__(self, frend): # 定義__call__函數,要求輸入一個frend參數 print('%s\'s friend is %s!' % (self.name,frend)) harry = Person('harry',20) harry.info() # 對象名調用__call__方法 harry('akira') Person('natasha',22)('hanmeimei') 輸出: harry's age is 20 harry's friend is akira! natasha's friend is hanmeimei!
__dict__:查看類或成員當中的全部成員,以字典的形式輸出
class Person: # 定義類屬性 id = 101 address = 'china' def __init__(self,name,age): self.name = name self.age = age def info(self): print('%s\'s age is %s' %(self.name,self.age)) def __call__(self, frend): # 定義__call__函數,要求輸入一個frend參數 print('%s\'s friend is %s!' % (self.name,frend)) harry = Person('harry',20) print(Person.__dict__) # 用類調用__init__,查看類中的全部成員,輸出類屬性,可是不會輸出實例的屬性 print() print(harry.__dict__) # 用實例調用__init__,查看實例中的全部成員 輸出: {'__module__': '__main__', 'id': 101, 'address': 'china', '__init__': <function Person.__init__ at 0x10227a7b8>, 'info': <function Person.info at 0x10227a840>, '__call__': <function Person.__call__ at 0x10227a8c8>, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None} {'name': 'harry', 'age': 20}
__str__ : 若是一個類中定義了__str__方法,打印對象時默認輸出__str__()方法的返回值
class PersonA(): def __init__(self,name): self.name = name class PersonB(): def __init__(self,name): self.name = name def __str__(self): return 'Person : %s' % self.name pa = PersonA('韓梅梅') # 類內部未使用__str__方法 print(pa) pb = PersonB('李雪') # 類內部已使用__str__方法,調用時直接輸出__str__的return值。 print(pb) 輸出: <__main__.PersonA object at 0x101a41cc0> Person : 李雪
1.20 字符編碼轉換
當國內採用UTF-8字符編碼寫出的軟件要在日本使用的時候,因爲兩國間的字符編碼不一樣就會出現亂碼的現象,Python中經過字符編碼轉換可解決這個問題。打個比方,衆所周知的unicode(也叫萬國編碼),若是要想將本來使用GBK編碼寫出的軟件轉換成UTF-8編碼的時候,就能夠藉助unicode做爲中間人來進行轉換。轉換的大體思路以下圖所示:
1.21 錯誤與異常
Python常見的基本錯誤有兩類,一類是語法錯誤,另外一個類是程序異常。語法錯誤:一般使用Pycharm等第三方IDE的時候若是出現語法錯誤在編程的時候會給出提醒,儘可能在程序調試過程當中就消除此類語法錯誤。程序異常:異常不是在編寫代碼時出現的錯誤,而是在程序運行時出現的錯誤,而若是對運行中的程序沒有進行異常處理那麼程序就會終止運行。
語法錯誤:
如下range()右側的括號爲全角括號,不符合代碼規範所以報了語法錯誤。 for i in range(10): print(i) 輸出: /excepDemo.py", line 15 for i in range(10): ^ SyntaxError: invalid character in identifier
異常錯誤:
python程序在程序運行中引起的錯誤稱爲異常,對異常的處理python與其餘語言同樣,也是經過try語句來完成,其語法規範以下所示: try: <語句(塊)> # 可能產生異常的語句(塊) except <異常名1>: # 要處理的異常 <語句(塊)> # 異常處理語句 except <異常名2>: # 要處理的異常 <語句(塊)>: # 異常處理語句 else: <語句(塊)> # 未觸發異常,則執行該語句(塊) finally: <語句(塊)> # 始終執行該語句,通常將來到達釋放資源的目的 def testTry(index,flay=False): userlst = ['jack','akira','harry'] if flay: try: astu = userlst[index] except IndexError: print('IndexError') return 'Try Test Finished!' else: astu = userlst[index] return "No try test !" print('不越界,捕獲異常:') print(testTry(1,True)) 輸出: 不越界,捕獲異常: Try Test Finished! print('\n不越界,不捕獲異常:') print(testTry(1,False)) 輸出: 不越界,不捕獲異常: No try test ! print('\n越界,捕獲異常:') print(testTry(4,True)) 輸出: 越界,捕獲異常: IndexError Try Test Finished! print('\n越界,未捕獲異常:') print(testTry(4,False)) 輸出: 越界,未捕獲異常: File "/Users/pentest/PycharmProjects/python_basic/python教程/錯誤、調試和測試/excepDemo.py", line 46, in testTry No try test ! astu = userlst[index] IndexError: list index out of range
finally語句執行
不管異常是否會發生,終究會執行finally裏面的代碼。如下演示運用finally語句來確保文件使用後能關閉該文件。 def testTryFinally(index): stulist = ['John','Jenny','Tom'] af = open('my.txt','wt+') try: af.write(stulist[index]) except : print('捕獲異常:IndexError') return 0 finally: af.close() print('文件已被關閉,finally已被執行!') testTryFinally(1) # 無越界異常,執行finally關閉文件 輸出: 文件已被關閉,finally已被執行! print(testTryFinally(4)) # 有越界異常,捕獲異常並執行finally關閉文件 輸出: 捕獲異常:IndexError 文件已被關閉,finally已被執行!
except語句用法
>except: # 捕獲全部異常,不管是什麼類型的錯誤統一拋出 >except <異常名>: # 捕獲指定異常 >except (異常名1,異常名2): # 指定捕獲異常1或異常2 # 以捕獲全部異常爲例 def testTryAll(index,i): stulist = ['john','jenney','tom'] try: print(len(stulist[index])/i) except: # 捕獲全部異常 print('Error!') testTryAll(1,2) # 下標未越界,無異常產生 輸出: 3.0 testTryAll(1,0) # 下標未越界,除數爲0異常 輸出: Error! testTryAll(4,0) # 下標已越界異常,除數爲0異常 輸出: Error!
Raise手工拋出異常
程序員能夠自定義異常類型,如對用戶輸入文本的長度有要求,則可使用raise引起異常。使用raise引起異常十分簡單,raise有如下幾種使用方式: >raise 異常名 >raise 異常名,附加數據 >raise 類名 # 如下代碼演示了雖然程序中對代碼進行了異常拋出,可是由於後續沒有對該異常進行捕獲,因此程序運行會被中斷,致使後面的代碼沒法執行 def testRaise(): for i in range(5): if i == 2: raise NameError print(i) print('end...') testRaise() 輸出: Traceback (most recent call last): 0 File "/Users/pentest/PycharmProjects/python_basic/python教程/錯誤、調試和測試/excepDemo.py", line 123, in <module> 1 testRaise() File "/Users/pentest/PycharmProjects/python_basic/python教程/錯誤、調試和測試/excepDemo.py", line 119, in testRaise raise NameError NameError # 綜上所述,在對代碼拋異常對同時進行捕獲,那麼程序運行則不會中斷。 def testRaise(): for i in range(5): try: if i == 2: raise NameError except NameError: print('Raise a NameError!') print(i) print('end...') testRaise() 輸出: 0 1 Raise a NameError! 2 3 4 end...
1.22 裝飾器
定義:
本質是函數,用於裝飾其餘函數,說白了就是爲其餘函數添加附加功能。
原則:
1>不能修改被裝飾的函數的源代碼
2>不能修改被裝飾的函數的調用方式
實例1: 統計程序運行時間的裝飾器
import time def timemer(func): def warpper(*args,**kwargs): start_time = time.time() func(*args,**kwargs) stop_time = time.time() print('the func run time is %s' % (stop_time-start_time)) return warpper @timemer def test1(): time.sleep(3) print('in the test1') test1()
實例2: 在普通函數執行前添加開始與結束語句
def abc(fun): # 定義一個裝飾器abc def wrapper(*args,**kwargs): # 定義包裝器函數 print('裝飾器開始運行...') fun(*args,**kwargs) # 調用被裝飾函數 print('裝飾器結束結束...') return wrapper # 返回包裝器函數 @abc #裝飾函數語句 def demo_decoration(x): # 定義普通函數,被裝飾器裝飾 a = [] for i in range(x): a.append(i) print(a) @abc # 裝飾器語句 def hello(name): # 定義普通函數,被裝飾器裝飾 print('hello',name) if __name__ == '__main__': demo_decoration(5) # 調用被裝飾器裝飾的函數 print() hello('John') # 調用被裝飾器裝飾的函數 輸出: 裝飾器開始運行... [0, 1, 2, 3, 4] 運行結束... 裝飾器開始運行... hello John 運行結束... 輸出(不加@abc裝飾器的狀況下): [0, 1, 2, 3, 4] hello John
1.23 高階函數
高階函數,知足如下兩個條件中任意一個便可稱之爲高階函數
a> 把一個函數名看成實參傳給另一個函數(在不修改被裝飾函數源代碼的狀況下爲其添加功能)
b> 返回值中包含函數名(不修改函數的調用方式)
a>證實: import time def bar(): time.sleep(3) print('in the bar') def test1(func): start_time = time.time() func() stop_time = time.time() print('the func run time is %s' % (stop_time - start_time)) test1(bar) # 傳遞參數時傳遞的是函數(bar是一個函數的內存地址) 輸出: in the bar the func run time is 3.0024850368499756 b>證實: import time def bar(): # 被裝飾的源代碼 time.sleep(3) print('in the bar') def test2(func): # 裝飾器 print(func) print('我是裝飾器!') return func bar = test2(bar) # 先把bar函數看成參數傳遞給裝飾器test2(),輸出結果爲bar的內存地址,而後將內存地址從新賦值給bar bar() # 此時的bar覆蓋原始的bar,而bar()是集裝飾器爲一體的bar函數了,也就是說直接執行bar()就能夠完成帶裝飾器的效果了。 輸出: <function bar at 0x100762e18> 我是裝飾器! in the bar
1.24 生成器
假如一個列表裏有1000萬個元素,若是咱們只想讀取列表裏的前5個數據,那麼程序依然會把包含1000萬個元素的列表一會兒都讀到內存裏,如此一來極大的浪費裏內存空間,也浪費了硬盤空間。Python中的生成器機制能夠生成一個[值的序列]用於迭代,而且這個值的序列不是一次生成的,而是使用一個再生成一個,可使程序節約大量內存。生成器對象是經過使用yield關鍵字定義的函數對象,所以生成器也是一個函數。此外生成對象能夠直接被for循環遍歷,也能夠手工進行遍歷。
實例1:自定義一個遞減數字序列的生成器,使用for循環遍歷
def myYield(n): # 定義一個生成器 while n > 0: print('開始生成...') yield n # yield語句,用於返回給調用者表達式的值 print('完成一次...\n') n -= 1 if __name__ == '__main__': for i in myYield(4): print('遍歷獲得的值:',i) print() 輸出: 開始生成... 遍歷獲得的值: 4 完成一次... 開始生成... 遍歷獲得的值: 3 完成一次... 開始生成... 遍歷獲得的值: 2 完成一次... 開始生成... 遍歷獲得的值: 1 完成一次...
實例2: 自定義一個遞減數字序列的生成器,使用手工遍歷,__next__()
def myYield(n): # 定義一個生成器 while n > 0: print('開始生成...') yield n # yield語句,用於返回給調用者表達式的值 print('完成一次...\n') n -= 1 my_yield = myYield(3) print('第一次調用__next__()方法:') print(my_yield.__next__()) print() print('第二次調用__next__()方法:') # 注意,第二次調用程序開始的位置爲第一次結束位置的下一跳爲起始位置。因此,第二次調用會先打印第一次調用還沒有執行的"完成一次..." print(my_yield.__next__()) 輸出: 第一次調用__next__()方法: 開始生成... 3 第二次調用__next__()方法: 完成一次... 開始生成... 2
實例3: ( i * i for i in range(10)) 使用括號擴起來而後賦值給scq,則scq就是一個生成器了,此時可使用for循環進行遍歷,也可使用手工的方法進行輸出。如下代碼顯示手工輸出到一部分後繼續使用for循環遍歷輸出。
scq = ( i * i for i in range(10)) print(scq,type(scq)) print() print(scq.__next__()) # 手工輸出生成器 print(scq.__next__()) # 手工輸出生成器 print(scq.__next__()) # 手工輸出生成器 print(scq.__next__()) # 手工輸出生成器 print('for循環開始...') # 繼續使用for循環輸出生成器對象 for i in scq : print(i) 輸出: <generator object <genexpr> at 0x102a14410> <class 'generator'> 0 1 4 9 for循環開始... 16 25 36 49 64 81
實例4: 生成器函數,以斐波那契數列爲例,當使用print()打印時則爲普通函數,當使用yield打印時則爲生成器函數。
def fib1(max): n,a,b = 0,0,1 while n < max: print(b) # 使用print()打印b,是普通函數 a,b = b,a+b n = n +1 return 'done' def fib2(max): n,a,b = 0,0,1 while n < max: yield b # 使用yield()打印b,是生成器函數 a,b = b,a+b n = n +1 return 'done' print('fib1類型:',type(fib1(10))) print('fib2類型:',type(fib2(10))) f2 = fib2(10) print(f2.__next__()) # f2是生成器,可使用f2.__next__()進行打印 print(f2.__next__()) print(f2.__next__()) print(f2.__next__()) print(f2.__next__()) 輸出: 1 1 2 3 5 8 13 21 34 55 fib1類型: <class 'str'> fib2類型: <class 'generator'> 1 1 2 3 5
1.25 迭代器
實例1:判斷是不是可迭代對象與是不是迭代器
可迭代對象: 可直接做用於for循環的對象有如下兩種,這些可直接用於for循環的對象統稱爲可迭代對象(Iterable對象)。 > list,tuple,dict,set,str等 > generator,包括生成器和含有yield的generator 迭代器: 能夠被next()函數調用並不斷返回下一個值的對象成爲迭代器:Interator # 如何判斷一個對象是不是可迭代對象,可使用isinstance()判斷 from collections import Iterable # 從collections裏面倒入Iterable(可迭代對象) from collections import Iterator # 從collections裏面倒入Iterator(迭代器) print('列表是不是可迭代對象:',isinstance([],Iterable)) print('列表是不是迭代器:',isinstance([],Iterator)) print() print('字符串是不是可迭代對象:',isinstance('abc',Iterable)) print('字符串是不是迭代器:',isinstance('abc',Iterator)) print() print('數字是不是可迭代對象:',isinstance(123,Iterable)) print('數字是不是迭代器:',isinstance(123,Iterator)) print() print('元組是不是可迭代對象:',isinstance(('1','2',3,'4',[]),Iterable)) print('元組是不是迭代器:',isinstance(('1','2',3,'4',[]),Iterator)) print() print('字典是不是可迭代對象:',isinstance({'abc':123,'def':456},Iterable)) print('字典是不是迭代器:',isinstance({'abc':123,'def':456},Iterator)) print() print('生成器是不是可迭代對象:',isinstance((x * x for x in range(5)),Iterable)) print('生成器是不是迭代器:',isinstance((x * x for x in range(5)),Iterator)) 輸出: 列表是不是可迭代對象: True 列表是不是迭代器: False 字符串是不是可迭代對象: True 字符串是不是迭代器: False 數字是不是可迭代對象: False 數字是不是迭代器: False 元組是不是可迭代對象: True 元組是不是迭代器: False 字典是不是可迭代對象: True 字典是不是迭代器: False 生成器是不是可迭代對象: True 生成器是不是迭代器: True
實例2: 將可迭代對象轉換爲迭代器
經過以上實例能夠看出,是可迭代對象但未必是迭代器,那麼如何將有些是可迭代對象但不是迭代器的對象轉換爲迭代器呢,經過iter()方法便可 l1 = [1,2,3,4,5] print('轉換前,是不是可迭代對象:',isinstance(l1,Iterable)) print('轉換前,是不是迭代器:',isinstance(l1,Iterator)) print() l2 = iter(l1) print('轉換後,是不是可迭代對象:',isinstance(l2,Iterable)) print('轉換後,是不是迭代器:',isinstance(l2,Iterator)) 輸出: 轉換前,是不是可迭代對象: True 轉換前,是不是迭代器: False 轉換後,是不是可迭代對象: True 轉換後,是不是迭代器: True
1.26 序列化
序列化是將Python中的列表、元組、字典等基本數據類型轉換爲字符串的過程;而反序列化是指將字符串轉換爲python的列表、元組、字典等對象的過程,在Python中與序列化相關的兩個模塊:json和pickle。
實例1: 序列化,使用json.dumps()將字典數據類型進行序列化操做,(字典 -> 字符串)
dic = {'k1':'v1'} # 字典類型 print(dic,type(dic)) result = json.dumps(dic) # 序列化操做,由字典類型變成了字符串類型 print(result,type(result)) 輸出: {'k1': 'v1'} <class 'dict'> {"k1": "v1"} <class 'str'>
實例2: 反序列化,使用json.loads()將字符串類型轉化爲字典類型,(字符串->字典)
import json # 將使用雙引號進行裝飾的字符串在進行反序列化時會報錯。報錯內容:json.decoder.JSONDecodeError: Expecting property name enclosed in double quotes: line 1 column 2 (char 1) # s1 = "{'k1':'v1'}"
# 注意,在進行反序列化時諸如'{"k1":"v1"]'這種既不是列表又不是字典的數據類型沒法進行反序列化,請保持數據類型的正確性後在進行反序列化。報錯內容:json.decoder.JSONDecodeError: Expecting ',' delimiter: line 1 column 11 (char 10)
# 將使用單引號進行裝飾的字符串在進行反序列化時不會報錯。 s1 = '{"k1":"v1"}' print(s1,type(s1)) dic = json.loads(s1) # 將字符串類型轉換爲字典類型 print(dic,type(dic)) 輸出: {"k1":"v1"} <class 'str'> {'k1': 'v1'} <class 'dict'>
實例3: 基於天氣API獲取JSON數據(http://wthrcdn.etouch.cn/weather_mini?city=上海)
import requests import json response = requests.get('http://wthrcdn.etouch.cn/weather_mini?city=上海') response.encoding = 'utf-8' print('獲取到的天氣API類型:',type(response.text)) # 查看獲取到的天氣API內容爲字符串類型 print(response.text) # 經過response.text獲取拿到的字符串內容 輸出: 獲取到的天氣API類型: <class 'str'> {"data":{"yesterday":{"date":"26日星期三","high":"高溫 37℃","fx":"東風","low":"低溫 29℃","fl":"微風","type":"陰"},"city":"上海","aqi":"99","forecast":[{"date":"27日星期四","high":"高溫 37℃","fengli":"微風級","low":"低溫 29℃","fengxiang":"東南風","type":"多雲"},{"date":"28日星期五","high":"高溫 37℃","fengli":"3-4級","low":"低溫 29℃","fengxiang":"東南風","type":"陰"},{"date":"29日星期六","high":"高溫 36℃","fengli":"3-4級","low":"低溫 29℃","fengxiang":"東風","type":"小雨"},{"date":"30日星期天","high":"高溫 35℃","fengli":"3-4級","low":"低溫 28℃","fengxiang":"北風","type":"小雨"},{"date":"31日星期一","high":"高溫 34℃","fengli":"微風級","low":"低溫 28℃","fengxiang":"東北風","type":"中雨"}],"ganmao":"各項氣象條件適宜,發生感冒機率較低。但請避免長期處於空調房間中,以防感冒。","wendu":"33"},"status":1000,"desc":"OK"} # 以上經過request獲取的是字符串類型,可是若是想更方便的被本地程序利用的化則須要再次將字符串類型反序列化成字典類型 dic = json.loads(response.text) print('反序列化後獲得的類型:',type(dic)) print(dic) 輸出: 反序列化後獲得的類型: <class 'dict'> {'data': {'yesterday': {'date': '26日星期三', 'high': '高溫 37℃', 'fx': '東風', 'low': '低溫 29℃', 'fl': '微風', 'type': '陰'}, 'city': '上海', 'aqi': '99', 'forecast': [{'date': '27日星期四', 'high': '高溫 37℃', 'fengli': '微風級', 'low': '低溫 29℃', 'fengxiang': '東南風', 'type': '多雲'}, {'date': '28日星期五', 'high': '高溫 37℃', 'fengli': '3-4級', 'low': '低溫 29℃', 'fengxiang': '東南風', 'type': '陰'}, {'date': '29日星期六', 'high': '高溫 36℃', 'fengli': '3-4級', 'low': '低溫 29℃', 'fengxiang': '東風', 'type': '小雨'}, {'date': '30日星期天', 'high': '高溫 35℃', 'fengli': '3-4級', 'low': '低溫 28℃', 'fengxiang': '北風', 'type': '小雨'}, {'date': '31日星期一', 'high': '高溫 34℃', 'fengli': '微風級', 'low': '低溫 28℃', 'fengxiang': '東北風', 'type': '中雨'}], 'ganmao': '各項氣象條件適宜,發生感冒機率較低。但請避免長期處於空調房間中,以防感冒。', 'wendu': '33'}, 'status': 1000, 'desc': 'OK'}
實例4: 序列化,使用pickle.dumps()將列表數據類型進行序列化操做,(列表 -> 字符串)
import pickle li_1 = [11,22,33] result = pickle.dumps(li_1) print(result,type(result)) # 輸出結果與json的輸出結果不一樣,但python語言之間能夠識別 輸出: b'\x80\x03]q\x00(K\x0bK\x16K!e.' <class 'bytes'>
以上代碼使用pickle.dumps()將python列表序列化成了字節類型,這種輸出方式雖然人沒法識但在python之間是能夠識別。另外,若是想要反序列化成列表格式可使用pickle.loads()方法:
li_2 = pickle.loads(result) print(li_2,type(li_2)) 輸出: [11, 22, 33] <class 'list'>
實例5: json與pickle的序列化區別
數據類型區別: > json只能在簡單數據類型(列表、字典、元組等)中進行序列化和反序列化 > pickle能夠處理類的對象這種高級數據類型 跨語言區別: > json能夠跨語言進行信息傳遞 > pickle只能在python語言之間進行信息傳遞
1.27 Python反射
Python反射包括四個方法:getattr、hasattr、setattr、delattr,分別用於獲取成員、檢查成員、設置成員、刪除成員。
hasattr(obj,attr) : 這個方法用於檢查obj是否有一個名爲attr的值的屬性,返回一個布爾值。 getattr(obj,attr) : 獲取obj這個對象裏的attr屬性或方法,若是attr對應的是屬性則直接返回屬性,若是attr對應的是方法,則返回次方法的內存地址,須要加一個括號而且給齊所需參數才能調用對應的方法。 setattr(obj, attr, val): 調用這個方法將給obj的名爲attr的值的屬性賦值爲val。例如若是attr爲'bar',則至關於obj.bar = val。 delattr(obj,attr):調用這個方法將obj的名爲attr的屬性刪除。
獲取一個來自客戶端的參數,進行反射案例演示
def talk(self): print('%s is jiaoing...' % self.name) class Dog(object): def __init__(self,name): self.name = name def eat(self,food): print('%s is eatting %s...' % (self.name,food)) d = Dog('Dahuang') # 先建立一個Dog類的對象。 choice = input('Please enter attribute or method and the program will check if it exists >>:').strip() # [hasattr],判斷d這個對象裏面是否存在choice這個字符串的屬性 if hasattr(d,choice): try: # [getattr]獲取對象原本就有的方法, 存在函數(eat)走如下代碼,返回值func爲內存地址,須要加一個括號而且給齊所需參數才能調用對應的方法。 func = getattr(d,choice) func('gouliang') except TypeError: # 獲取對象原本就有的屬性:若是終端輸入的是"name"的時候走如下代碼 print('name is %s' % getattr(d,choice)) else: if choice == "talk": # 若是用戶輸入的是"talk",則爲對象建立talk方法 setattr(d,choice,talk) d.talk(d) print(d.__dict__) else: # 若是對象輸入除了talk之外的字段,則爲對象建立屬性 setattr(d, choice, 22) print(getattr(d, choice)) print('\n查看對象有那些屬性:') print(d.__dict__) 輸出: Please enter attribute or method and the program will check if it exists >>:name name is Dahuang Please enter attribute or method and the program will check if it exists >>:eat Dahuang is eatting gouliang... Please enter attribute or method and the program will check if it exists >>:talk Dahuang is jiaoing... {'name': 'Dahuang', 'talk': <function talk at 0x100562e18>} Please enter attribute or method and the program will check if it exists >>:age 22 查看對象有那些屬性: {'name': 'Dahuang', 'age': 22}
class Person(): def __init__(self,name,age): self.name = name self.age = age def run(self): print('%s is running...' % self.name) p1 = Person('akira',20) print(hasattr(p1,'name')) print(hasattr(p1,'height')) 輸出: True False p_name = getattr(p1,'name') print(p_name) 輸出: akira p_run = getattr(p1,'run') print(p_run) # 打印的是方法的內存地址,調用具體值須要加括號 print(p_run()) 輸出: <bound method Person.run of <__main__.Person object at 0x10225f2b0>> akira is running... print('setattr前:',getattr(p1,'age')) setattr(p1,'age',30) print('setattr後:',getattr(p1,'age')) 輸出: setattr前: 20 setattr後: 30 print(getattr(p1,'age')) delattr(p1,'age') print(getattr(p1,'age')) 輸出: 報錯AttributeError: 'Person' object has no attribute 'age'
1.28 Socket編程
網絡概念:
TCP協議負責在兩臺計算機之間創建可靠鏈接,保證數據包按順序到達。TCP協議會經過握手創建鏈接,而後,對每一個IP包編號,確保對方按順序收到,若是包丟掉了,就自動重發。 許多經常使用的更高級的協議都是創建在TCP協議基礎上的,好比用於瀏覽器的HTTP協議、發送郵件的SMTP協議等。一個IP包除了包含要傳輸的數據外,還包含源IP地址和目標IP地址,源端口和目標端口。 端口的做用就是在兩臺計算機通訊時,只發IP地址是不夠的,由於同一臺計算機上跑着多個網絡程序。一個IP包來了以後,究竟是交給瀏覽器仍是QQ,就須要端口號來區分。每一個網絡程序都向操做系統申請惟一的端口號,這樣,兩個進程在兩臺計算機之間創建網絡鏈接就須要各自的IP地址和各自的端口號。 一個進程也可能同時與多個計算機創建連接,所以它會申請不少端口。
socket編程
Socket是網絡編程的一個抽象概念。一般咱們用一個Socket表示「打開了一個網絡連接」,而打開一個Socket須要知道目標計算機的IP地址和端口號,再指定協議類型便可。
客戶端和服務端
大多數鏈接都是可靠的TCP鏈接。建立TCP鏈接時,主動發起鏈接的叫客戶端,被動響應鏈接的叫服務器。
socket服務端創建鏈接流程圖
Socket客戶端創建鏈接流程
實例代碼,本地搭建客戶端與服務端模擬通訊
服務端:
import socket # ip地址爲空表示本地地址 HOST = '' # 設置端口 PORT = 10888 #初始化socket對象,AF_INET(IPV4),SOCK_STREAM(TCP協議) s = socket.socket(socket.AF_INET,socket.SOCK_STREAM) # 綁定操做,使socket和服務器服務地址相關聯 s.bind((HOST,PORT)) # 指定鏈接數,最小值爲0 ,最多設置到5就能夠了 s.listen(1) #等待接入的連接,返回值是由一個socket鏈接和客戶端的IP地址組成元組。 conn,addr = s.accept() print('Client\'s address:',addr) while True: # recv 接收並返回遠程鏈接發來的信息,1024爲設定緩衝區大小。 data = conn.recv(1024) if not data: break print('Receive Data:',data.decode('utf-8')) conn.send(data) # 將接收到的數據再次發送出去 conn.close() # 關閉鏈接
客戶端:
import socket HOST = 'localhost' PORT = 10888 # 初始化socket對象,使用IPv4,TCP協議 s = socket.socket(socket.AF_INET,socket.SOCK_STREAM) # 創建鏈接 s.connect((HOST,PORT)) data = '你好' while data: # 鏈接創建後向服務端發送data='你好' s.sendall(data.encode('utf-8')) # 接收socket服務器端發來的信息並保存於data中,data的緩存大小設置爲512 data = s.recv(512) # 將data進行解碼後輸出 print('Receive from server:',data.decode('utf-8')) # 接收用戶輸入的內容而後在下一次循環中繼續發送到服務端。 data = input('please input a info:\n') # 關閉鏈接 s.close()
實例代碼:運行服務端使之處於監聽狀態,在客戶端發起請求
客戶端: Receive from server: 你好 please input a info: hello world Receive from server: hello world please input a info: hello python Receive from server: hello python please input a info: 服務端: Client's address: ('127.0.0.1', 62285) Receive Data: 你好 Receive Data: hello world Receive Data: hello python
實例代碼:socket實現簡單SSH功能
服務端:
#! /usr/bin/env python # -*- coding:utf-8 -*- # Author: Tdcqma import socket import os server = socket.socket() server.bind(('localhost',9761)) server.listen() print('connection waitting...') while True: conn,addr = server.accept() print('new connectiong:',addr) while True: print('等待新指令:') data = conn.recv(1024) if not data: print('客戶端已斷開') break print('執行指令:',data) cmd_res = os.popen(data.decode()).read() print('before send',len(cmd_res),type(cmd_res)) if len(cmd_res) == 0: cmd_res = 'cmd has no output...' conn.send( str(len(cmd_res.encode())).encode('utf-8') ) conn.send(cmd_res.encode('utf-8')) print('send done') server.close()
客戶端:
#! /usr/bin/env python # -*- coding:utf-8 -*- # Author: Tdcqma import socket client = socket.socket() client.connect(('localhost',9761)) while True: cmd = input('>>:').strip() if len(cmd) == 0: continue client.send(cmd.encode('utf-8')) cmd_res_size = client.recv(1024) print('命令結果大小:',cmd_res_size.decode()) received_size = 0 received_data = b'' while received_size < int(cmd_res_size.decode()): data = client.recv(1024) received_size += len(data) received_data += data else: print('cmd res receive done...',received_size) print(received_data.decode()) client.close()
測試SSH鏈接:
客戶端:
>>:ls -l
命令結果大小: 146
cmd res receive done... 146
total 16
-rw-r--r-- 1 pentest staff 666 Aug 28 15:47 sock_server_client.py
-rw-r--r-- 1 pentest staff 804 Aug 28 15:47 sock_server_ssh.py
>>:id
命令結果大小: 317
cmd res receive done... 317
uid=501(pentest) gid=20(staff) groups=20(staff),701(com.apple.sharepoint.group.1),12(everyone),61(localaccounts),79(_appserverusr),80(admin),81(_appserveradm),98(_lpadmin),33(_appstore),100(_lpoperator),204(_developer),395(com.apple.access_ftp),398(com.apple.access_screensharing-disabled),399(com.apple.access_ssh)
>>:df
命令結果大小: 424
cmd res receive done... 424
Filesystem 512-blocks Used Available Capacity iused ifree %iused Mounted on
/dev/disk1 487830528 258698920 228619608 54% 1172485 4293794794 0% /
devfs 367 367 0 100% 636 0 100% /dev
map -hosts 0 0 0 100% 0 0 100% /net
map auto_home 0 0 0 100% 0 0 100% /home
>>:
服務端:
connection waitting...
new connectiong: ('127.0.0.1', 50863)
等待新指令:
執行指令: b'ls -l'
before send 146 <class 'str'>
send done
等待新指令:
執行指令: b'id'
before send 317 <class 'str'>
send done
等待新指令:
執行指令: b'df'
before send 424 <class 'str'>
send done
等待新指令:
實例代碼:socket實現簡單FTP功能(測試環境爲ubuntu,其中服務端與客戶端均在同一臺機器)
服務端:
#! /usr/bin/env python # -*- coding:utf-8 -*- # Author: Tdcqma import socket import os server = socket.socket() server.bind(('localhost',9761)) server.listen() print('connection waitting...') while True: conn,addr = server.accept() print('new connectiong:',addr) while True: print('等待新指令:') data = conn.recv(1024) if not data: print('客戶端已斷開') break cmd,filename = data.decode().split() if os.path.isfile(filename): f = open(filename,"rb") file_size = os.stat(filename).st_size # get size of filename conn.send( str(file_size).encode() ) # send server's file size conn.recv(1024) # wait ack from client for line in f: conn.send(line) f.close() print('send done') server.close()
客戶端:
#! /usr/bin/env python # -*- coding:utf-8 -*- # Author: Tdcqma import socket client = socket.socket() client.connect(('localhost',9761)) while True: cmd = input('>>:').strip() if len(cmd) == 0: continue if cmd.startswith("get"): client.send(cmd.encode()) server_response = client.recv(1024) print("server response:",server_response) # receive size of server's file client.send(b"ready to recv file ") # send ack to server file_total_size = int(server_response.decode()) received_size = 0 filename = cmd.split()[1] # get filename from "get filname" f = open(filename + ".new","wb") # save file and named filename.new while received_size < file_total_size: data = client.recv(1024) received_size += len(data) f.write(data) #print(file_total_size,received_size) # print received size and total size. else: print("file recv done!") f.close() client.close()
測試FTP文件發送
# 確認當前文件夾裏的內容: -rwxrwxr-x 1 pentester pentester 979 8月 28 19:49 ftp_socket_client.py* -rwxrwxr-x 1 pentester pentester 867 8月 28 19:49 ftp_socket_server.py* -rw-r--r-- 1 root root 226745856 8月 28 19:36 test.dd # 服務端開啓服務,並等待鏈接 pentester@pentest-machine:~/MyPythonObj/FTP$ ./ftp_socket_server.py connection waitting... new connectiong: ('127.0.0.1', 56498) 等待新指令: send done 等待新指令: # 客戶端發起鏈接,並要求下載server端的test.dd保存到本地,並添加文件的後綴名.new pentester@pentest-machine:~/MyPythonObj/FTP$ ./ftp_socket_client.py >>:get test.dd server response: b'226745856' file recv done! # 查看已下載到文件 pentester@pentest-machine:~/MyPythonObj/FTP$ ls ftp_socket_client.py ftp_socket_server.py test.dd test.dd.new pentester@pentest-machine:~/MyPythonObj/FTP$ du -h test.dd.new 217M test.dd.new
用socketserver模塊創建服務器
socketserver框架將處理請求分爲了兩個部分,分別對應請求處理類和服務器類。服務器類處理通訊問題,請求處理類處理數據交換和傳送。socketserver模塊中使用的使用的服務器類主要有TCPServer、UDPServer、ThreadingTCPServer、ThreadingUDPServer、ForkingTCPServer,ForkingUDPServer其中有Threading的是多線程類,有Forking的是多進程類。要建立不一樣類型的服務器程序只須要繼承其中之一或直接實例化,而後調用服務器類方法serve_forever()便可。 這些服務器的構造方法參數主要有: > server_address # 由IP地址和端口組成的元組 >RequestHandlerClass # 處理器類,共服務器類調用處理數據 socketserver模塊中使用的處理器類主要有StreamRequestHandler(基於TCP協議的)和DatagramRequestHandler(基於UDP協議的),只要繼承其中之一,就能夠自定義一個處理器類。經過覆蓋一下三個方法,實現自定義: > setup() 爲請求準備請求處理器(請求處理的初始化工做) > handler() 完成具體的請求處理工做(解析請求、處理數據、發出響應) > finish() 清理請求處理器相關數據
代碼部分(服務端)
import socketserver class MyTCPHandler(socketserver.BaseRequestHandler): def handle(self): while True: try: self.data = self.request.recv(1024).strip() if not self.data: server.shutdown() break print("{} wrote:".format(self.client_address[0])) print(self.data) self.request.send(self.data.upper()) except ConnectionResetError as e: print('err:',e) break if __name__ == "__main__": HOST,PORT = 'localhost',9999 server = socketserver.ThreadingTCPServer((HOST,PORT),MyTCPHandler) server.serve_forever()
代碼部分(客戶端)
import socket client = socket.socket() client.connect(('localhost',9999)) while True: msg = input(">>:").strip() if len(msg) == 0 : continue client.send(msg.encode('utf-8')) data = client.recv(1024) print("recv:",data.decode()) client.close()
代碼測試:
socketServer_client1: >>:from client_1 recv: FROM CLIENT_1 >>: socketServer_client2: recv: FROM CLIENT_2 >>: socketServer_server: 127.0.0.1 wrote: b'from client_1' 127.0.0.1 wrote: b'from client_2'
1.29 Paramiko
paramiko是一個基於SSH用於鏈接遠程服務器並執行相關操做的一個模塊,其中SSHClient能夠實現SSH的功能,SFTPClinet能夠實現SCP的功能。
實例代碼:paramiko實現簡單SSH功能
#! /usr/bin/env python # -*- coding:utf-8 -*- # Author: Tdcqma import paramiko # 接收用戶輸入的命令 com = input('please input your command:').strip() # 建立SSH鏈接對象 ssh = paramiko.SSHClient() # 容許鏈接不在know_hosts文件中的主機 ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) # 鏈接服務器,其中hostname爲被鏈接服務器hostname或ip,port爲ssh端口,username與password爲遠程鏈接的用戶名密碼。 ssh.connect(hostname='192.192.168.168',port=22,username='root',password='123456') # 執行命令,返回值中包括標準輸入、標準輸出以及標準錯誤。 stdin,stdout,stderr = ssh.exec_command(com) # 獲取命令執行結果 res,err = stdout.read(),stderr.read() result = res if res else err # 因爲result是bytes類型,轉化爲utf-8類型後便可恢復原是命令行格式 #print(result,type(result)) # 使用utf-8進行編碼,格式化輸出 print('命令執行結果:'.center(50,'-')) print(result.decode('utf-8')) # 關閉ssh鏈接 ssh.close() 輸出: /myPython/paramikoTest$ python3 ssh.py please input your command:uname -a ---------------------命令執行結果:---------------------- Linux jumpserver 2.6.32-573.26.1.el6.x86_64 #1 SMP Wed May 4 00:57:44 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux
實例代碼:paramiko調用SFTPClient方法,實現scp功能
import paramiko # 綁定鏈接和登陸信息 transport = paramiko.Transport(('192.192.168.168',22)) transport.connect(username='root',password='123456') # paramiko調用SFTPClient方法,實現Linux的scp功能 sftp = paramiko.SFTPClient.from_transport(transport) # 上傳文件到服務器,其中putfile_test爲本地文件,/tmp/putfile爲遠程服務器的路徑及保存文件名 sftp.put('putfile_test','/tmp/putfile.txt') # 下載服務器文件到本地,其中/tmp/remote_file.txt爲遠程服務器上/tmp路徑下的文件,保存到本地當前目錄,保存到文件名爲local_file.txt sftp.get('/tmp/remote_file.txt','local_file.txt') # 關閉鏈接 transport.close()
實例代碼:paramiko基於公鑰認證明現SSH鏈接
#! /usr/bin/env python # -*- coding:utf-8 -*- # Author: Tdcqma ''' 主意:在作基於公鑰認證時須要如今本地生成公鑰祕鑰對,linux下可使用ssh-keygen生成,windows下能夠經過xshell生成。而後將公鑰內容複製粘貼到要訪問服務器指定用戶的家目錄下.ssh/authorized_keys裏,而paramiko.RSAKey.from_private_key_file()裏則是指本地生成的私鑰,切勿弄混。 ''' import paramiko private_key = paramiko.RSAKey.from_private_key_file("/home/pentest/.ssh/id_rsa") # 建立SSH對象 ssh = paramiko.SSHClient() # 容許鏈接不在know_hosts文件中的主機 ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) # 鏈接服務器,此處僅制定hostname、port、username及pkey便可,不須要密碼了。 ssh.connect(hostname='192.192.168.168', port=22, username='root', pkey=private_key) # 執行命令 stdin, stdout, stderr = ssh.exec_command('ifconfig') # 獲取命令結果 result = stdout.read() # 打印輸出命令執行結果 print(result.decode()) # 關閉鏈接 ssh.close() 輸出: python3 ssh_rsa.py docker0 Link encap:Ethernet HWaddr 06:D1:E4:E6:41:EE inet addr:172.17.42.1 Bcast:0.0.0.0 Mask:255.255.0.0 inet6 addr: fe80::44cc:ddff:fe91:722c/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:1408 errors:0 dropped:0 overruns:0 frame:0 TX packets:1235 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:3662398 (3.4 MiB) TX bytes:285595 (278.9 KiB) ...
1.30 爬蟲
爬蟲簡介...
Requests模塊:發送get請求
response = requests.get('https://www.sogou.com/web?query=python') print(response.text)
Requests模塊:發送post請求,嘗試登陸操做,post登陸請求數據須要借用瀏覽器查看元素(網絡),例如查看登陸數據的內容
form_data = { 'phone':'13311111111', 'password':'111111', 'oneMonth':'1' } response = requests.post( url = 'http://dig.chouti.com/login', data = form_data ) print(response.text)
《持續更新中》