1. 程式人生 > >python_字符_函數

python_字符_函數

追加內容 獲得 狀態 指針 ted 讀取內容 軟件 常用 title

一、字符集和字符編碼

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_字符_函數