python_字符_函數
一、字符集和字符編碼
1.定義
計算機中儲存的信息都是用二進制數表示的,而我們在屏幕上看到的英文、漢字等字符是二進制數轉換之後的結果。通俗的說,按照何種規則將字符存儲在計算機中,如‘a‘用什麽表示,稱為"編碼";反之,將存儲在計算機中的二進制數解析顯示出來,稱為"解碼",如同密碼學中的加密和解密。在解碼過程中,如果使用了錯誤的解碼規則,則導致‘a‘解析成‘b‘或者亂碼。
字符(Character):是一個信息單位,在計算機裏面,一個中文漢字是一個字符,一個英文字母是一個字符,一個阿拉伯數字是一個字符,一個標點符號也是一個字符。
字符集(Charset):是一個系統支持的所有抽象字符的集合。通常以二維表的形式存在,二維表的內容和大小是由使用者的語言而定,可以是英語,是漢語,或者阿拉伯語。
字符編碼(Character Encoding):是一套法則,使用該法則能夠對自然語言的字符的一個集合(如字母表或音節表),與其他東西的一個集合(如號碼或電脈沖)進行配對。在這裏我們把字符集中的字符編碼為特定的二進制數,以便在計算機中存儲。編碼方式一般就是對二維表的橫縱坐標進行變換的算法。即在符號集合與數字系統之間建立對應關系,它是信息處理的一項基本技術。即:字符--------(翻譯過程)------->二進制數
2.常用的字符集和字符編碼
字符集和字符編碼一般都是成對出現的,如ASCII、GBK、Unicode、UTF-8等,都是即表示了字符集又表示了對應的字符編碼,以後統稱為編碼。
3.字符編碼的發展史
第一階段:起源,ASCII
計算機是美國人發明的,人家用的是美式英語,字符比較少,所以一開始就設計了一個不大的二維表,128個字符,取名叫ASCII(American Standard Code for Information Interchange)。但是7位編碼的字符集只能支持128個字符,為了表示更多的歐洲常用字符對ASCII進行了擴展,ASCII擴展字符集使用8位(bits)表示一個字符,共256字符。即其最多只能用 8 位來表示(一個字節)。
第二階段:GBK
當計算機傳到了亞洲,尤其是東亞,國際標準被秒殺了,路邊小孩隨便說句話,256個碼位就不夠用了。於是,中國定制了GBK。用2個字節代表一個字符(漢字)。其他國家也紛紛定制了自己的編碼,例如:
日本把日文編到Shift_JIS
裏,韓國把韓文編到Euc-kr
裏。
第三階段:unicode
當互聯網席卷了全球,地域限制被打破了,不同國家和地區的計算機在交換數據的過程中,就會出現亂碼的問題,跟語言上的地理隔離差不多。為了解決這個問題,一個偉大的創想產生了——Unicode(萬國碼)。Unicode編碼系統為表達任意語言的任意字符而設計。
規定所有的字符和符號最少由 16 位來表示(2個字節),即:2 **16 = 65536,註:此處說的的是至少2個字節(16位),可能更多。
第四階段:UTF-8
unicode的編碼方式雖然包容萬國,但是對於英文等字符就會浪費太多存儲空間。於是出現了UTF-8,是對Unicode編碼的壓縮和優化,遵循能用最少的表示就用最少的表示,他不再使用最少使用2個字節,而是將所有的字符和符號進行分類:ascii碼中的內容用1個字節保存、歐洲的字符用2個字節保存,東亞的字符用3個字節保存。
補充:
unicode:包容萬國,優點是字符->數字的轉換速度快,缺點是占用空間大 utf-8:精準,對不同的字符用不同的長度表示,優點是節省空間,缺點是:字符->數字的轉換速度慢,因為每次都需要計算出字符需要多長的Bytes才能夠準確表示
內存中使用的編碼是unicode,用空間換時間,為了快
因為程序都需要加載到內存才能運行,因而內存應該是盡可能的保證快。
硬盤中或者網絡傳輸用utf-8,網絡I/O延遲或磁盤I/O延遲要遠大與utf-8的轉換延遲,而且I/O應該是盡可能地節省帶寬,保證數據傳輸的穩定性。
因為數據的傳輸,追求的是穩定,高效,數據量越小數據傳輸就越靠譜,於是都轉成utf-8格式的,而不是unicode。
如下圖:
4.字符編碼的使用
1)文本編輯器存取文件的原理(nodepad++,pycharm,word)
打開編輯器就打開了啟動了一個進程,是在內存中的,所以在編輯器編寫的內容也都是存放與內存中的,斷電後數據丟失。因而需要保存到硬盤上,點擊保存按鈕,就從內存中把數據刷到了硬盤上。在這一點上,我們編寫一個py文件(沒有執行),跟編寫其他文件沒有任何區別,都只是在編寫一堆字符而已。
無論是何種編輯器,要防止文件出現亂碼,核心法則就是,文件以什麽編碼保存的,就以什麽編碼方式打開。
2)python解釋器執行py文件的原理 (python test.py)
第一階段:python解釋器啟動,此時就相當於啟動了一個文本編輯器
第二階段:python解釋器相當於文本編輯器,去打開test.py文件,從硬盤上將test.py的文件內容讀入到內存中
第三階段:python解釋器解釋執行剛剛加載到內存中test.py的代碼
補充:
所以,在寫代碼時,為了不出現亂碼,推薦使用UTF-8,會加入 # -*- coding: utf-8 -*-
即
#!/usr/bin/env python # -*- coding: utf-8 -*- print "你好,世界"
python解釋器會讀取test.py的第二行內容,# -*- coding: utf-8 -*-,來決定以什麽編碼格式來讀入內存,這一行就是來設定python解釋器這個軟件的編碼使用的編碼格式這個編碼。
如果不在python文件指定頭信息#-*-coding:utf-8-*-,那就使用默認的python2中默認使用ascii,python3中默認使用utf-8
總結:
1)python解釋器是解釋執行文件內容的,因而python解釋器具備讀py文件的功能,這一點與文本編輯器一樣
2)與文本編輯器不一樣的地方在於,python解釋器不僅可以讀文件內容,還可以執行文件內容
5.python2和python3的一些不同
1) python2中默認使用ascii,python3中默認使用utf-8
2) Python2中,str就是編碼後的結果bytes,str=bytes,所以s只能decode。
3) python3中的字符串與python2中的u‘字符串‘,都是unicode,只能encode,所以無論如何打印都不會亂碼,因為可以理解為從內存打印到內存,即內存->內存,unicode->unicode
4) python3中,str是unicode,當程序執行時,無需加u,str也會被以unicode形式保存新的內存空間中,str可以直接encode成任意編碼格式,s.encode(‘utf-8‘),s.encode(‘gbk‘)
#unicode(str)-----encode---->utf-8(bytes) #utf-8(bytes)-----decode---->unicode
5)在windows終端編碼為gbk,linux是UTF-8.
二、文件操作
1.文件處理的流程
1)打開文件,得到文件句柄並賦值給一個變量
2)通過句柄對文件進行操作
3)關閉文件
例如:
f = open(‘chenli.txt‘) #打開文件 first_line = f.readline() print(‘first line:‘,first_line) #讀一行 data = f.read()# 讀取剩下的所有內容,文件大時不要用 print(data) #打印讀取內容 f.close() #關閉文件
2.文件操作基本用法
1)基本用法:
file_object = open(file_name, access_mode = ‘r’, buffering = -1)
open函數有很多的參數,常用的是file_name,mode和encoding
file_name:打開的文件名,若非當前路徑,需指出具體路徑
access_mode文件打開模式
buffering的可取值有0,1,>1三個,0代表buffer關閉(只適用於二進制模式),1代表line buffer(只適用於文本模式),>1表示初始化的buffer大小;
encoding表示的是返回的數據采用何種編碼,一般采用utf8或者gbk;
2)文件打開模式
- r ,只讀模式【默認模式,文件必須存在,不存在則拋出異常】
- w,只寫模式【不可讀;不存在則創建;存在則清空內容】
- x, 只寫模式【不可讀;不存在則創建,存在則報錯】
- a, 追加模式【可讀; 不存在則創建;存在則只追加內容】,文件指針自動移到文件尾。
"+" 表示可以同時讀寫某個文件
- r+, 讀寫【可讀,可寫】
- w+,寫讀【可讀,可寫】,消除文件內容,然後以讀寫方式打開文件。
- x+ ,寫讀【可讀,可寫】
- a+, 寫讀【可讀,可寫】,以讀寫方式打開文件,並把文件指針移到文件尾。
"b"表示以字節的方式操作,以二進制模式打開文件,而不是以文本模式。
- rb 或 r+b
- wb 或 w+b
- xb 或 w+b
- ab 或 a+b
註:以b方式打開時,讀取到的內容是字節類型,寫入時也需要提供字節類型,不能指定編碼
3)以讀r的方式打開文件
#!/usr/bin/env python # -*- coding:utf-8 -*- f=open(‘1.txt‘,encoding=‘utf-8‘,mode=‘r‘) print(f) data1=f.read() print(data1)
1.txt
55542342 123
輸出:
<_io.TextIOWrapper name=‘1.txt‘ mode=‘r‘ encoding=‘utf-8‘> 55542342 123
補充:
1)python中有三個方法來處理文件內容的讀取: read() #一次讀取全部的文件內容。 readline() #每次讀取文件的一行。 readlines() #讀取文件的所有行,返回一個字符串列表。 2)print(f.readable()) #判斷文件是否是r模式打開的
3)print(f.closed) #判斷文件是否是關閉狀態
4)python中在文本文件內容移動的操作 file.seek(offset,whence=0) #從文件中給移動指針,從whence(0起始,1當前,2末尾)偏移offset個字節,正往結束方向移動,負往開始方向移動 file.tell() #返回當前文件中的位置。獲得文件指針位置
5) file.truncate(size=file.tell()) #截取文件到最大size個字節,默認為當前文件位置
4)以w方式寫入文件
f=open(‘a.txt‘,‘w‘,encoding=‘utf-8‘) # f=open(‘b.txt‘,‘r‘,encoding=‘utf-8‘) #以讀的方式打開文件,文件不存在則報錯 f=open(‘b.txt‘,‘w‘,encoding=‘utf-8‘) # print(f.writable()) f.write(‘111111\n22222222‘) f.seek(0) f.write(‘\n333333\n444444‘) f.writelines([‘\n55555\n‘,‘6666\n‘,‘77777\n‘]) f.close()
a.txt 為空
b.txt
333333 444444 55555 6666 77777
補充:
file.write(str) #向文件中寫入字符串(文本或二進制) file.writelines(seq) #寫入多行,向文件中寫入一個字符串列表,註意,要自己加入每行的換行符 file.flush() #刷新文件內部緩沖,直接把內部緩沖區的數據立刻寫入文件, 而不是被動的等待輸出緩沖區寫入.
5)文件修改
#!/usr/bin/env python # -*- coding:utf-8 -*- import os read_f=open(‘b.txt‘,‘r‘) write_f=open(‘.b.txt.swap‘,‘w‘) for line in read_f.readlines(): if line.startswith(‘1111‘): line=‘2222222222\n‘ write_f.write(line) read_f.close() write_f.close() os.remove(‘b.txt‘) os.rename(‘.b.txt.swap‘,‘b.txt‘)
3.上下文管理with語句
當你做文件處理,你需要獲取一個文件句柄,從文件中讀取數據,然後關閉文件句柄。
正常情況下,代碼如下:
file = open("/tmp/foo.txt") data = file.read() file.close()
這裏有兩個問題。一是可能忘記關閉文件句柄;二是文件讀取數據發生異常,沒有進行任何處理。
然而with可以很好的處理上下文環境產生的異常。下面是with版本的代碼:
with open("/tmp /foo.txt") as file: data = file.read()
with的基本思想是with所求值的對象必須有一個__enter__()方法,一個__exit__()方法。緊跟with後面的語句被求值後,返回對象的__enter__()方法被調用,這個方法的返回值將被賦值給as後面的變量。當with後面的代碼塊全部被執行完之後,將調用前面返回對象的__exit__()方法。
補充:
模擬 tail -f access.log
#!/usr/bin/env python # -*- coding:utf-8 -*- # tail -f access.log import time with open(‘access.log‘,‘r‘,encoding=‘utf-8‘) as f: f.seek(0,2) while True: line=f.readline().strip() if line: print(‘新增一行日誌‘,line) time.sleep(0.5)
三、函數
1.什麽是函數?
函數是組織好的,可重復使用的,用來實現單一,或相關聯功能的代碼段。
函數能提高應用的模塊性,和代碼的重復利用率,可擴展性強。
2.函數的分類
在python中函數分兩類:內置函數,自定義函數
1)內置函數
python本身自己定義的函數,可直接調用
sum max min a=len(‘hello‘) print(a) b=max([1,2,3]) print(b)
2)自定義函數
自己根據需求,按照函數定義方法去自定函數
3.函數的定義
1)為什麽要定義函數?
先定義後使用,如果沒有定義而直接使用,就相當於引用了一個不存在的變量名
函數的使用包含兩個階段:定義階段和使用階段
註:定義函數,只檢測語法,不執行代碼
2)函數定義的語法
def functionname( parameters ): "函數_文檔字符串" function_suite return [expression]
例如:
def printme( str ):
print str
return
3)定義函數的三種形式
#一:無參數函數:如果函數的功能僅僅只是執行一些操作而已,就定義成無參函數,無參函數通常沒有返回值 def print_star(): print(‘#‘*6) #二:定義有參函數:函數的功能的執行依賴於外部傳入的參數,有參函數通常都有返回值 # def my_max(x,y): # res=x if x >y else y # return res # 三元表達式 x=10 y=2 # if x > y: # print(x) # else: # print(y) #
res=x if x > y else y print(res)
#三:空函數
在一開始思考代碼架構時,可以先把擴展功能寫下來,後期完善
# def auth(): # """認證功能""" # pass # auth() def insert(): """插入功能""" pass def select(): """查詢功能""" pass def delete(): """刪除功能""" pass def update(): """更新功能""" pass
4)函數的調用
def foo(): print(‘from foo‘) def bar(name): print(‘bar===>‘,name) #按照有參和無參可以將函數調用分兩種 foo() #定義時無參,調用時也無需傳入參數 bar(‘egon‘) #定義時有參,調用時也必須有參數 #按照函數的調用形式和出現的位置,分三種 foo() #調用函數的語句形式 def my_max(x,y): res=x if x >y else y return res # res=my_max(1,2)*10000000 #調用函數的表達式形式 # print(res) res=my_max(my_max(10,20),30) #把函數調用當中另外一個函數的參數 print(res)
5)函數的參數
函數的參數分兩種:形參(變量名),實參(值)
#定義階段 def foo(x,y): #x=1,y=2 print(x) print(y) #調用階段 foo(1,2)
詳細的區分函數的參數分為五種:
位置參數,關鍵字參數,默認參數,可變長參數(*args,**kwargs),命名關鍵字參數
- 位置參數
def foo(x,y,z):#位置形參:必須被傳值的參數 print(x,y,z) foo(1,2,3) #位置實參數:與形參一一對應
輸出:
1 2 3
- 關鍵字參數
def foo(x,y,z): print(x,y,z) foo(z=3,x=1,y=2) #關鍵字參數需要註意的問題: # 1:關鍵字實參必須在位置實參後面 # 2: 不能重復對一個形參數傳值
# foo(1,z=3,y=2) #正確 # foo(x=1,2,z=3) #錯誤 # foo(1,x=1,y=2,z=3)
- 默認參數
# def register(name,age,sex=‘male‘): #形參:默認參數 # print(name,age,sex) # # register(‘asb‘,age=40) # register(‘a1sb‘,39) # register(‘a2sb‘,30) # register(‘a3sb‘,29) # # register(‘鋼蛋‘,20,‘female‘) # register(‘鋼蛋‘,sex=‘female‘,age=19) #默認參數需要註意的問題: #一:默認參數必須跟在非默認參數後 # def register(sex=‘male‘,name,age): #在定義階段就會報錯 # print(name,age,sex) #(了解)二:默認參數在定義階段就已經賦值了,而且只在定義階段賦值一次 # a=100000000 # def foo(x,y=a): # print(x,y) # a=0 # foo(1) #三:默認參數的值通常定義成不可變類型
- 可變長參數
*args *會把溢出的按位置定義的實參都接收,以元組的形式賦值給args
def foo(x,y,*args): #*會把溢出的按位置定義的實參都接收,以元組的形式賦值給args print(x,y) print(args) #
foo(1,2,3,4,5)
例如:
# def add(*args): # res=0 # for i in args: # res+=i # return res # print(add(1,2,3,4)) # print(add(1,2))
輸出:
10 3
**kwargs **會把溢出的按關鍵字定義的實參都接收,以字典的形式賦值給kwargs
# def foo(x, y, **kwargs): # **會把溢出的按關鍵字定義的實參都接收,以字典的形式賦值給kwargs # print(x, y) # print(kwargs) # foo(1,2,a=1,name=‘egon‘,age=18)
例如:
def foo(name,age,**kwargs): print(name,age) if ‘sex‘ in kwargs: print(kwargs[‘sex‘]) if ‘height‘ in kwargs: print(kwargs[‘height‘]) foo(‘egon‘,18,sex=‘male‘,height=‘185‘) foo(‘egon‘,18,sex=‘male‘)
輸出:
egon 18 male 185 egon 18 male
foo(*[1,2,3]) #foo(1,2,3)
foo(**{‘x‘:1,‘b‘:2} #foo(x=1,b=2)
- 命名關鍵字參數
# def foo(name,age,*,sex=‘male‘,height): # print(name,age) # print(sex) # print(height) # #*後定義的參數為命名關鍵字參數,這類參數,必須被傳值,而且必須以關鍵字實參的形式去傳值 # foo(‘egon‘,17,height=‘185‘)
例如
def foo(x,y,z): print(‘from foo‘,x,y,z) def wrapper(*args,**kwargs): print(args) #args=(1,2,3) print(kwargs) #kwargs={‘a‘:1,‘b‘:2} foo(*args,**kwargs) #foo(*(1,2,3),**{‘a‘:1,‘b‘:2}) #foo(1,2,3,b=2,a=1) # wrapper(1,2,3,a=1,b=2) wrapper(1,z=2,y=3)
輸出
(1,) {‘z‘: 2, ‘y‘: 3} from foo 1 3 2
6)函數的返回值
return語句[表達式]退出函數,選擇性地向調用方返回一個表達式。不帶參數值的return語句返回None。
例如
def foo(): print(‘from foo‘) return None res=foo() print(res)
輸出
from foo None
補充:
以三種情況返回值都為None:
沒有return return 什麽都不寫 return None
return 一個值 函數調用返回的結果就是這個值
def foo(): print(‘from foo‘) x=1 return x res=foo() print(res)
輸出:
from foo 1
return 值1,值2,值3,... 返回結果:(值1,值2,值3,...)
def foo(): print(‘from foo‘) x=1 return 1,[2,3],(4,5),{} res=foo() print(res) #打印結果:(1,[2,3],(4,5),{}) a,b,c,d=foo() print(d)
輸出:
from foo (1, [2, 3], (4, 5), {}) from foo {}
python_字符_函數