1. 程式人生 > >python基礎五:模塊

python基礎五:模塊

read oss serial 對象序列化 問題 package 反序 很多 env

模塊&包

模塊(Module)的概念:在計算機程序的開發過程中,隨著程序代碼越寫越多,在一個文件裏的代碼會越來越長,維護也越來越不易。為了編寫可維護的代碼,我們把很多函數分組,分別放在不同的文件裏,很多語言都采用這個組織代碼的方式,在python中一個.py文件就稱之為模塊。
使用模塊的好處:大大提高代碼的可維護性。其次,編寫代碼不必從零開始。當一個模塊編寫完畢,就可以被其他地方引用。我們在編寫程序的時候,也經常引用其他模塊,包括Python內置的模塊和來自第三方的模塊。

所以,模塊一共三種:

  1. python標準庫
  2. 第三方模塊
  3. 應用程序自定義模塊

另外,使用模塊還可以避免函數名和變量名沖突。相同名字的函數和變量完全可以分別存在不同的模塊中,因此,我們自己在編寫模塊時,不必考慮名字會與其他模塊沖突。但是也要註意,盡量不要與內置函數名字沖突。

模塊導入方法

1 import 語句

import module1[, module2[,... moduleN]

當我們使用import語句的時候,Python解釋器是怎樣找到對應的文件的呢?答案就是解釋器有自己的搜索路徑,存在sys.path裏。  

[‘‘, ‘/usr/lib/python3.4‘, ‘/usr/lib/python3.4/plat-x86_64-linux-gnu‘, 
‘/usr/lib/python3.4/lib-dynload‘, ‘/usr/local/lib/python3.4/dist-packages‘, ‘/usr/lib/python3/dist-packages‘] 
``` 
因此若像我一樣在當前目錄下存在與要引入模塊同名的文件,就會把要引入的模塊屏蔽掉。

### 2  from…import 語句

from modname import name1[, name2[, ... nameN]]

這個聲明不會把整個modulename模塊導入到當前的命名空間中,只會將它裏面的name1或name2單個引入到執行這個聲明的模塊的全局符號表。

### 3  From…import* 語句

from modname import *

這提供了一個簡單的方法來導入一個模塊中的所有項目。然而這種聲明不該被過多地使用。大多數情況, Python程序員不使用這種方法,因為引入的其它來源的命名,很可能覆蓋了已有的定義。

### 4 運行本質 

#1 import test
#2 from test import add

```  
無論1還是2,首先通過sys.path找到test.py,然後執行test腳本(全部執行),區別是1會將test這個變量名加載到名字空間,而2只會將add這個變量名加載進來。  

os模塊

os模塊是與操作系統交互的一個接口

os.getcwd() 獲取當前工作目錄,即當前python腳本工作的目錄路徑
os.chdir("dirname")  改變當前腳本工作目錄;相當於shell下cd
os.curdir  返回當前目錄: (‘.‘)
os.pardir  獲取當前目錄的父目錄字符串名:(‘..‘)
os.makedirs(‘dirname1/dirname2‘)    可生成多層遞歸目錄
os.removedirs(‘dirname1‘)    若目錄為空,則刪除,並遞歸到上一級目錄,如若也為空,則刪除,依此類推
os.mkdir(‘dirname‘)    生成單級目錄;相當於shell中mkdir dirname
os.rmdir(‘dirname‘)    刪除單級空目錄,若目錄不為空則無法刪除,報錯;相當於shell中rmdir dirname
os.listdir(‘dirname‘)    列出指定目錄下的所有文件和子目錄,包括隱藏文件,並以列表方式打印
os.remove()  刪除一個文件
os.rename("oldname","newname")  重命名文件/目錄
os.stat(‘path/filename‘)  獲取文件/目錄信息
os.sep    輸出操作系統特定的路徑分隔符,win下為"\\",Linux下為"/"
os.linesep    輸出當前平臺使用的行終止符,win下為"\t\n",Linux下為"\n"
os.pathsep    輸出用於分割文件路徑的字符串 win下為;,Linux下為:
os.name    輸出字符串指示當前使用平臺。win->‘nt‘; Linux->‘posix‘
os.system("bash command")  運行shell命令,直接顯示
os.environ  獲取系統環境變量
os.path.abspath(path)  返回path規範化的絕對路徑
os.path.split(path)  將path分割成目錄和文件名二元組返回
os.path.dirname(path)  返回path的目錄。其實就是os.path.split(path)的第一個元素
os.path.basename(path)  返回path最後的文件名。如何path以/或\結尾,那麽就會返回空值。即os.path.split(path)的第二個元素
os.path.exists(path)  如果path存在,返回True;如果path不存在,返回False
os.path.isabs(path)  如果path是絕對路徑,返回True
os.path.isfile(path)  如果path是一個存在的文件,返回True。否則返回False
os.path.isdir(path)  如果path是一個存在的目錄,則返回True。否則返回False
os.path.join(path1[, path2[, ...]])  將多個路徑組合後返回,第一個絕對路徑之前的參數將被忽略
os.path.getatime(path)  返回path所指向的文件或者目錄的最後存取時間
os.path.getmtime(path)  返回path所指向的文件或者目錄的最後修改時間

sys模塊

sys.argv           命令行參數List,第一個元素是程序本身路徑
sys.exit(n)        退出程序,正常退出時exit(0)
sys.version        獲取Python解釋程序的版本信息
sys.maxint         最大的Int值
sys.path           返回模塊的搜索路徑,初始化時使用PYTHONPATH環境變量的值
sys.platform       返回操作系統平臺名稱

小實例:進度條

import sys,time
for i in range(10):
    sys.stdout.write(‘#‘)
    time.sleep(1)
    sys.stdout.flush()

JSON模塊

之前我們學習過用eval內置方法可以將一個字符串轉成python對象,不過,eval方法是有局限性的,對於普通的數據類型,json.loads和eval都能用,但遇到特殊類型的時候,eval就不管用了,所以eval的重點還是通常用來執行一個字符串表達式,並返回表達式的值。

import json
x="[null,true,false,1]"
print(eval(x))
print(json.loads(x))

什麽是序列化?

我們把對象(變量)從內存中變成可存儲或傳輸的過程稱之為序列化,在Python中叫pickling,在其他語言中也被稱之為serialization,marshalling,flattening等等,都是一個意思。

序列化之後,就可以把序列化後的內容寫入磁盤,或者通過網絡傳輸到別的機器上。

反過來,把變量內容從序列化的對象重新讀到內存裏稱之為反序列化,即unpickling。

如果我們要在不同的編程語言之間傳遞對象,就必須把對象序列化為標準格式,比如XML,但更好的方法是序列化為JSON,因為JSON表示出來就是一個字符串,可以被所有語言讀取,也可以方便地存儲到磁盤或者通過網絡傳輸。JSON不僅是標準格式,並且比XML更快,而且可以直接在Web頁面中讀取,非常方便。

JSON表示的對象就是標準的JavaScript語言的對象,JSON和Python內置的數據類型對應如下:
技術分享圖片

#----------------------------序列化
import json

dic={‘name‘:‘alvin‘,‘age‘:23,‘sex‘:‘male‘}
print(type(dic))#<class ‘dict‘>

j=json.dumps(dic)
print(type(j))#<class ‘str‘>

f=open(‘序列化對象‘,‘w‘)
f.write(j)  #-------------------等價於json.dump(dic,f)
f.close()
#-----------------------------反序列化

import json
f=open(‘序列化對象‘)
data=json.loads(f.read())#  等價於data=json.load(f)

需要註意的是:

import json
#dct="{‘1‘:111}"#json 不認單引號
#dct=str({"1":111})#報錯,因為生成的數據還是單引號:{‘one‘: 1}

dct=‘{"1":"111"}‘
print(json.loads(dct))

#conclusion:
#        無論數據是怎樣創建的,只要滿足json格式,就可以json.loads出來,不一定非要dumps的數據才能loads

pickle模塊

##----------------------------序列化
import pickle

dic={‘name‘:‘alvin‘,‘age‘:23,‘sex‘:‘male‘}

print(type(dic))#<class ‘dict‘>

j=pickle.dumps(dic)
print(type(j))#<class ‘bytes‘>

f=open(‘序列化對象_pickle‘,‘wb‘)#註意是w是寫入str,wb是寫入bytes,j是‘bytes‘
f.write(j)  #-------------------等價於pickle.dump(dic,f)

f.close()
#-------------------------反序列化
import pickle
f=open(‘序列化對象_pickle‘,‘rb‘)

data=pickle.loads(f.read())#  等價於data=pickle.load(f)

print(data[‘age‘])    

Pickle的問題和所有其他編程語言特有的序列化問題一樣,就是它只能用於Python,並且可能不同版本的Python彼此都不兼容,因此,只能用Pickle保存那些不重要的數據,不能成功地反序列化也沒關系。

shelve模塊

shelve模塊比pickle模塊簡單,只有一個open函數,返回類似字典的對象,可讀可寫;key必須為字符串,而值可以是python所支持的數據類型。(了解)

import shelve

f = shelve.open(r‘shelve.txt‘)

# f[‘stu1_info‘]={‘name‘:‘alex‘,‘age‘:‘18‘}
# f[‘stu2_info‘]={‘name‘:‘alvin‘,‘age‘:‘20‘}
# f[‘school_info‘]={‘website‘:‘oldboyedu.com‘,‘city‘:‘beijing‘}
#
#
# f.close()

print(f.get(‘stu_info‘)[‘age‘])

XML模塊

xml是實現不同語言或程序之間進行數據交換的協議,跟json差不多,但json使用起來更簡單,不過,古時候,在json還沒誕生的黑暗年代,大家只能選擇用xml呀,至今很多傳統公司如金融行業的很多系統的接口還主要是xml。

xml的格式如下,就是通過<>節點來區別數據結構的:

<?xml version="1.0"?>
<data>
    <country name="Liechtenstein">
        <rank updated="yes">2</rank>
        <year>2008</year>
        <gdppc>141100</gdppc>
        <neighbor name="Austria" direction="E"/>
        <neighbor name="Switzerland" direction="W"/>
    </country>
    <country name="Singapore">
        <rank updated="yes">5</rank>
        <year>2011</year>
        <gdppc>59900</gdppc>
        <neighbor name="Malaysia" direction="N"/>
    </country>
    <country name="Panama">
        <rank updated="yes">69</rank>
        <year>2011</year>
        <gdppc>13600</gdppc>
        <neighbor name="Costa Rica" direction="W"/>
        <neighbor name="Colombia" direction="E"/>
    </country>
</data>

xml協議在各個語言裏的都 是支持的,在python中可以用以下模塊操作xml:

import xml.etree.ElementTree as ET

tree = ET.parse("xmltest.xml")
root = tree.getroot()
print(root.tag)

#遍歷xml文檔
for child in root:
    print(child.tag, child.attrib)
    for i in child:
        print(i.tag,i.text)

#只遍歷year 節點
for node in root.iter(‘year‘):
    print(node.tag,node.text)
#---------------------------------------

import xml.etree.ElementTree as ET

tree = ET.parse("xmltest.xml")
root = tree.getroot()

#修改
for node in root.iter(‘year‘):
    new_year = int(node.text) + 1
    node.text = str(new_year)
    node.set("updated","yes")

tree.write("xmltest.xml")

#刪除node
for country in root.findall(‘country‘):
   rank = int(country.find(‘rank‘).text)
   if rank > 50:
     root.remove(country)

tree.write(‘output.xml‘)

自己創建xml文檔:

import xml.etree.ElementTree as ET

new_xml = ET.Element("namelist")
name = ET.SubElement(new_xml,"name",attrib={"enrolled":"yes"})
age = ET.SubElement(name,"age",attrib={"checked":"no"})
sex = ET.SubElement(name,"sex")
sex.text = ‘33‘
name2 = ET.SubElement(new_xml,"name",attrib={"enrolled":"no"})
age = ET.SubElement(name2,"age")
age.text = ‘19‘

et = ET.ElementTree(new_xml) #生成文檔對象
et.write("test.xml", encoding="utf-8",xml_declaration=True)

ET.dump(new_xml) #打印生成的格式

re模塊

技術分享圖片

import re

ret=re.findall(‘a..in‘,‘helloalvin‘)
print(ret)#[‘alvin‘]

ret=re.findall(‘^a...n‘,‘alvinhelloawwwn‘)
print(ret)#[‘alvin‘]

ret=re.findall(‘a...n$‘,‘alvinhelloawwwn‘)
print(ret)#[‘awwwn‘]

ret=re.findall(‘a...n$‘,‘alvinhelloawwwn‘)
print(ret)#[‘awwwn‘]

ret=re.findall(‘abc*‘,‘abcccc‘)#貪婪匹配[0,+oo]   
print(ret)#[‘abcccc‘]

ret=re.findall(‘abc+‘,‘abccc‘)#[1,+oo]
print(ret)#[‘abccc‘]

ret=re.findall(‘abc?‘,‘abccc‘)#[0,1]
print(ret)#[‘abc‘]

ret=re.findall(‘abc{1,4}‘,‘abccc‘)
print(ret)#[‘abccc‘] 貪婪匹配

註意:前面的*,+,?等都是貪婪匹配,也就是盡可能匹配,後面加?號使其變成惰性匹配

ret=re.findall(‘abc*?‘,‘abcccccc‘)
print(ret)#[‘ab‘]

python基礎五:模塊