編寫高質量代碼--改善python程式的建議(七)

来源:http://www.cnblogs.com/cotyb/archive/2016/01/11/5122350.html
-Advertisement-
Play Games

原文發表在我的 "博客主頁" ,轉載請註明出處! 建議三十四:掌握字元串的基本用法 編程有兩件事,一件是處理數值,另一件是處理字元串,在商業應用編程來說,處理字元串的代碼超過八成,所以需要重點掌握。 首先有個小技巧,python遇到未閉合的小括弧時會自動將多行代碼拼接為一行,同時把相鄰的兩個字...


原文發表在我的博客主頁,轉載請註明出處!

建議三十四:掌握字元串的基本用法
編程有兩件事,一件是處理數值,另一件是處理字元串,在商業應用編程來說,處理字元串的代碼超過八成,所以需要重點掌握。
首先有個小技巧,python遇到未閉合的小括弧時會自動將多行代碼拼接為一行,同時把相鄰的兩個字元串字面量拼接再議,比如下麵的兩個代碼是等價的。

s = ('SELECT *'
     'FROM atable'
     'WHERE afield = "value"')
'SELECT *FROM atableWHERE afield = "value"'

除此之外,python的字元串有str和unicode兩種,判斷一個變數s是不是字元串應使用isinstance(s, basestring)

#input
a = "hi"
b = u"Hi"
print isinstance(b, str)
print isinstance(b, basestring)
print isinstance(b, unicode)
print isinstance(a, unicode)
#output
False
True
True
False

通過上面的例子可以總結:

  • isinstance(a, str)用於判斷一個字元串是不是普通字元串,也就是說其類型是否為str
  • isinstance(a, unicode)用來判斷一個字元串是不是Unicode
  • 因此判斷一個變數是不是字元串,應該使用isinstance(a, basestring),basestring是str和Unicode的基類
    下麵簡單來列舉下字元串的使用
  • 性質判定
    str對象有以下幾個方法:isalnum(), isalpha(), isdigit(), islower(), isupper(), isspace(), istitle(), startwith(prefix[,start[,end]]),endwith(suffix[,start[,end]])
  • 查找替換
    有以下函數:count(sub[,start[,end]]),find(sub[,start[,end]]), index(sub[,start[,end]]), rfind(sub[,start[,end]]), rindex(sub[,start[,end]]),replace(old,new[,count]),其中find()函數族找不到時返回-1,index()函數族則拋出異常。
  • 分切與連接
    主要掌握兩個:partition(sep), split([sep[,maxsplit]]),前者接受一個字元串參數,並返回一個3個元素的元組對象,如果sep沒有出現,返回值是(sep,","),否則返回值的第一個元素是sep左邊的部分,第二個元素是sep本身,第三個元素是sep右端的部分。而split()的參數maxsplit是分切的次數,即最大的分切次數,所以返回值做多有maxsplit+1個元素。
  • 變形
    主要是一些常用函數,lower(),upper(),capitalize(),swapcase(),title()
  • 填充與刪除
    如果strip([chars]),lstrip([chars]),rstrip([chars])中的chars參數沒有指定,就是刪除空白符。填充則用於字元串的輸出,藉助於它們能夠排出漂亮的版面。center(width[,fillchar]),ljust(width[,fillchar]),rjust(width[,fillchar]),zfill(width),expandtabs([tabsize])這些完成的居中,左對齊,右對齊,零填充等功能。

建議三十五:按需選擇sort()或者sorted()
兩者的函數形式如下:

sorted(iterable[,cmp[,key[,reverse]]])
s.sort([cmp[,key[,reverse]]])
#cmp為用戶定義的任何比較函數,函數的參數為兩個可比較的元素(來自iterable或者s),函數根據第一個和第二個參數的關係返回-1,0,1,預設值為None
#key是帶一個參數的函數,用來為每個元素提取比較值,預設為None(即直接比較每個元素)
#reverse表示排序結果是否反轉
#exampe
p = [{'name':'Jon','age':32},{'name':'Alan','age':50},{'name':'Jon','age':23}]
print sorted(p,key=lambda x: (x['name'], -x['age']))

兩者區別如下:

  • sorted()用於任意可迭代對象,而sort()一般作用於列表
  • 當排序對象為列表的時候兩者適用的場景不同,sorted()會返回一個排序後的列表,原有列表保持不變,而sort()函數會直接修改原有列表,函數返回None
  • 不論用哪個,傳入參數key都要比傳入參數cmp效率高,cmp傳入的函數在整個排序過程中會調用多次,函數開銷較大,而key針對每個元素僅作一次處理。

建議三十六:使用copy模塊深拷貝對象
淺拷貝:構造一個新的複合對象並將從原對象中發現的引用插入該對象中。淺拷貝的實現方式主要有:工廠函數,切片操作,copy模塊中的copy操作
深拷貝:構造一個新的複合對象,遇到引用會繼續遞歸拷貝其所指向的具體內容,它會針對引用所指向的對象繼續執行拷貝,產生的對象不受其他引用對象操作的影響。
在包含引用的數據結構中,淺拷貝並不能進行徹底的拷貝,當存在列表、字典等對象的時候,它僅僅拷貝其引用地址,修改拷貝的對象可能會改變原對象的值,要解決這個問題需要用到深拷貝,深拷貝不僅拷貝引用也拷貝引用所指向的對象,深拷貝得到的對象和原對象是相互獨立的。使用如下:

import copy
copy.deepcopy(x)

建議三十七:使用Counter進行計數統計
計數統計具有非常廣泛的用途,逐一來看實現方式:

  • 使用dict

    data = ['a','2',2,3,4,'2','b','a','b',3,4,'a']
    count_frq = {}
    for item in data:
    if item in count_frq:
        count_frq[item] += 1
    else:
        count_frq[item] = 1
    print count_frq
  • 使用defaultdict

    from collections import defaultdict
    data = ['a','2',2,3,4,'2','b','a','b',3,4,'a']
    count_frq = defaultdict(int)
    for item in data:
    count_frq[item] += 1
    print count_frq
  • 使用set和list

    data = ['a','2',2,3,4,'2','b','a','b',3,4,'a']
    count_set = set(data)
    count_frq = []
    for item in count_set:
    count_frq.append((item,data.count(item)))
    print count_frq

    上面的方法都比較naive,更加pythonic的如下:

    from collections import Counter
    data = ['a','2',2,3,4,'2','b','a','b',3,4,'a']
    print Counter(data)

    Counter屬於字典類的子類,是一個容器對象,主要用來統計散列對象,支持集合操作,提供了三種初始化方式:

    Counter('success')
    Counter(s=3,c=2,e=1,u=1)
    Counter('s':3,'c':2,'u':1,'e':1)

    可以使用elements()方法來獲取Counter中的key值,利用most_common(N)方法獲取N個出現頻率最高的元素以及對應的次數,當訪問元素不存在時候,預設返回0。

    from collections import Counter
    data = ['a','2',2,3,4,'2','b','a','b',3,4,'a']
    print list(Counter(data).elements())
    print Counter(data).most_common(3)
    print Counter(data)['z']

建議三十八:深入掌握ConfigParser
幾乎所有的應用程式真正運行起來的時候,都會讀取一個或幾個配置文件,配置文件的意義在於用戶不需要修改代碼,就可以改變應用程式的行為。常見的配置文件格式有XML和ini等。這裡強調幾點用法:

  • getboolean()函數,其根據一定的規則將配置項的值轉化為布爾值,如:

    [section1]
    option1 = 0
    當調用getboolean('section1','option1')時,將返回False。不過他的真值規則值得一說:處了0以外,no, false, off都會轉義為False,對應的1, yes, true, on都會轉義為True,其他值會拋出異常。
  • 配置項的查找規則
    首先,在ConfigParser支持的配置文件格式里,有一個[DEFAULT]節,當讀取的配置項不在指定的節里時,ConfigParser將會到[DEFAULT]節中查找。

    #cyj.conf
    [DEFAULT]
    in_default = 'if you have a dream, you have to protect it'
    [section1]
    #test.py
    import ConfigParser
    conf = ConfigParser.ConfigParser()
    conf.read('cyj.conf')
    print conf.get('section1','in_default')
    #output
    'if you have a dream, you have to protect it'

    除此之外,還有一些機制導致項目配置的查找更複雜,這就是class ConfigParser構造函數中的defaults形參以及其get(section,option[,raw[,vars]])中的全名參數vars。如果把這些機制全部用上,查找規則如下:

    • 如果找不到節名,就拋出NoSectionError
    • 如果給定的配置項出現在get()方法的vars參數中,則返回vars參數中的值
    • 如果在指定的節中含有給定的配置項,則返回值
    • 如果在[DEFAULT]中含有指定的配置項,返回值
    • 如果在構造函數的defaults參數中有指定的配置項,則返回值
    • 拋出NoOptionError
  • ConfigParser其他配置方法
    python字元串的格式化可以使用如下語法:

    site = {'protocol':'http','server':'115.159.48.140','port':80}
    print '%(protocol)s://%(server)s:%(port)s/' %site

    ConfigParser支持類似的用法,所以在配置文件中可以使用,比如:

    #cyj.conf
    [DEFAULT]
    conn_str = %(dbn)s://%(user)s:%(pw)s@%(host)s:%(port)s/%(db)s
    dbn = mysql
    user = root
    host = localhost
    port = 3306
    [db1]
    user = aaa
    pw = ppp
    db = example
    [db2]
    host = 192.168.0.110
    pw = www
    db = example
    #test.py
    import ConfigParser
    conf = ConfigParser.ConfigParser()
    conf.read('cyj.conf')
    print conf.get('db1','conn_str')
    print conf.get('db2','conn_str')
    #output
    mysql://aaa:ppp@localhost:3306/example
    mysql://root:[email protected]:3306/example

建議三十九:使用argparse處理命令行參數
儘管應用程式通常能夠通過配置文件在不修改代碼的情況下改變行為,但提供靈活易用的命令行參數依然非常有意義,比如:減輕用戶的學習成本,通常命令行參數的用法只需要在應用程式名後加--help參數就能獲得。
現在比較流行的庫為
argparse*庫,他子optparse脫胎而來,先生成一個parser實例,然後增加參數聲明。比如:

import argparse
parser = argparse.ArgumentParser()
parser.add_argument('-o','--output')
parser.add_argument('-v',dest='verbose',action='store_true')
args = parser.parse_args()

add_argument()方法用以增加一個參數聲明,他支持的類型比較多,語法直觀,type參數的值不再是一個字元串,而是一個可調用對象。此外,add_argument()提供了對必填參數的支持,只要把required參數設置為True傳遞進去,當缺失這一參數時,argparser就會自動退出程式,並提示用戶。
ArgumentParser還支持參數分組,add_argument_group()可以在輸出幫助信息時更加清晰。

test.py
import argparse
parser = argparse.ArgumentParser(prog='PROG',add_help=False)
group1 = parser.add_argument_group('group1','python')
group1.add_argument('foo',help='foo help')
group2 = parser.add_argument_group('group2','nice')
group2.add_argument('--bar',help='bar help')
print parser.print_help()

建議四十:使用pandas處理大型CSV文件
CSV(Comma Separated Values)作為一種逗號分隔型值的純文本文件,在實際應用中經常用到,如資料庫數據的導入導出,數據分析中記錄的存儲等。首先來看下python提供的CSV處理相關的API:

  • csv.reader(csvfile[,dialect='excel'][,fmtparam]),用於CSV文件的讀取,返回一個reader對象用於在CSV文件內容上進行行迭代
  • csv.writer(csvfile,dialect='excel',**fmtparams)用於寫入CSV文件

    import csv
    with open('data.csv','wb') as csvfile:
    csvwriter = csv.writer(csvfile, dialect='excel', delimiter='|', quotechar='"', quoting=csv.QUOTE_MINIMAL)
    csvwriter.writerow(["1/3/09 14:44","'Product1'","1200''","Visa","Gouya"])
  • csv.DictReader(csvfile, fieldnames=None, restkey=None, restval=None, dialect='excel',*args,**kwargs),和reader()類似,不同的是將讀入的信息映射到一個字典中去,其中字典的key由fieldnames指定,省略的話CSV文件第一行的數據作為key值。如果讀入行的欄位的個數大於fieldnames中指定的個數,多餘的欄位名將會存放在restkey中,而restval主要用於當讀取行的域的個數小於fieldnames的時候,它的值將會被用作剩下的key對應的值
  • csv.DictWriter(csvfile, fieldnames, restval='',extrasaction='raise',dialect='excel',*args,**kwds)用於支持字典寫入

上面的使用可以滿足大部分需求,但是如果處理大文件會拋出MemoryError異常,這種情況下可以使用pandas模塊。
Pandas,支持多種文件格式處理,包括CSV,HDF5,HTML等,兩種數據結構:Series和DataFrame。

Series:是一種類似數組的帶索引的一維數據結構,支持的類型與NumPy相容,如果不指定索引,預設從0到N-1,通過obj.values()和obj.index()分別獲取值和索引,當給Series傳遞一個字典的時候,Series的索引將根據字典中的鍵排序,如果傳入字典的時候重新制訂了index參數,當index與字典中的鍵不匹配的時候,會出現數據丟失的情況,標記為NaN。
DataFrame:類似於電子錶格,其數據結構為排好序的數據列的集合,每一列都可以是不同的數據類型,類似於二維數組,支持行和列的索引。可以通過colums指定序列的順序。

import pandas
data = {'OrderDate': ['1-6-10', '1-23-10', '2-9-10', '2-26-10', '3-15-10'],
         'Region': ['East', 'Central', 'Central', 'West', 'East'],
         'Rep': ['Jones', 'Kivell', 'Jardine', 'Gill', 'Sorvino']}
print pandas.DataFrame(data,columns=['OrderDate','Rep','Region'])

pandas中處理CSV文件的主要函數為read_csv()和to_csv(),前者讀取文件的內容返回DataFrame,後者為其逆過程。下麵簡單講述其用法:

  • 指定讀取部分列和文件的行數

    df = pd.read_csv('data.csv',nrows=5,usecols=[])
    #nrows指定讀取文件的行數
    #usecols指定索要讀取的列的列名,沒有列名可用索引
  • 設置CSV文件和excel相容
    如果文件格式改為使用“|”分隔符,則需要設置dialect相關的參數,error_bad_lines設置為False,當記錄不符合要求的時候,可直接忽略。
  • 對文件進行分塊處理並返回一個可迭代的對象
    為了防止記憶體消耗過大,可以分批載入記憶體,參數chunksize設置分塊的文件行數,將參數iterator設置為True時,返回值為TextFileReader,是一個可迭代對象

    reader = pd.read_table("data.csv",chunksize=10,iterator=True)
    iter(reader).next()
  • 當文件格式相似的時候,支持多個文件合併處理

    dfs = [pd.read_csv(f) for f in fileset]
    totol_fg = pd.concat(dfs)

參考:編寫高質量代碼--改善python程式的91個建議


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • golang interface記憶體佈局
  • 複製當前行:ctrl+alt+↓刪除當前行:Ctrl+d行註釋:Ctrl+/快註釋(先選中要註釋的代碼):Ctrl+shift+/提示助手(方便函數等補全):alt+/代碼格式化:Ctrl+shift+F最牛逼的快捷鍵(可以顯示所有的快捷鍵):Ctrl+shift+l
  • 前言 其實cloudera已經做了這個事了,只是把kafka的包和cdh的parcel包分離了,只要我們把分離開的kafka的服務描述jar包和服務parcel包下載了,就可以實現完美集成了。具體實現的簡要步驟可參照cloudera官網提供的文檔:http://www.cloudera.com...
  • Spring Boot 項目(參考1) 提供了一個類似ASP.NET MVC的預設模板一樣的標準樣板,直接集成了一系列的組件並使用了預設的配置。使用Spring Boot 不會降低學習成本,甚至增加了學習成本,但顯著降低了使用成本並提高了開發效率。如果沒有Spring基礎不建議直接上手。1.基礎項目...
  • 三層菜單,根據用戶所選數字,進入子菜單。一級一級呈現。 1 menu = { 2 'Beijing': { 3 "ChaoYang": { 4 "CBD": ['CICC', 'CCTV'], 5 "JinRongJie": [...
  • 在AN65209中 有一些應用筆記集錦,希望對大家有用。當然AN65209這篇應用筆記很重要,希望大家一定要看!!!一定要看!!!!
  • 註:在看這篇文章之前,如果對CopyOnWriteArrayList底層不清楚的話,建議先去看看CopyOnWriteArrayList源碼解析。http://www.cnblogs.com/java-zhao/p/5121944.html1、對於CopyOnWriteArraySet需要掌握以下幾...
  • 1 /*1.在Main.storyboard中找到,ScrollView和PageControl並添加到ViewController中。 2 2.在ScrollView中添加ImageView,新手引導頁有幾個圖片就添加幾個,然後設置ImageView的image,就是準備好的圖片。 3 3.要設....
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...