新聞中心
python編程中編寫(xiě)循環(huán)的技巧?
編寫(xiě)循環(huán)的技巧,for循環(huán)包含了常見(jiàn)的計(jì)數(shù)器式循環(huán)。由于通常for循環(huán)比while循環(huán)更容易寫(xiě),也執(zhí)行得更快,所以for循環(huán)一般是你遍歷序列或其他可迭代對(duì)象時(shí)的首選。事實(shí)上,作為一條通用法則,你應(yīng)該克制在Python中使用計(jì)數(shù)方式的誘惑——Python提供的迭代工具,能幫你把像C這樣低級(jí)語(yǔ)言中循環(huán)集合體的工作自動(dòng)化。不過(guò),有些情況下你還是需要以更為特定的方式進(jìn)行迭代。例如,如果你需要在列表中每隔一個(gè)元素或每隔兩個(gè)元素進(jìn)行訪問(wèn),或是要同時(shí)修改列表呢?如果在同一個(gè)for循環(huán)內(nèi),并行遍歷一個(gè)以上的序列呢?如果你也需要進(jìn)行索引呢?
讓客戶(hù)滿(mǎn)意是我們工作的目標(biāo),不斷超越客戶(hù)的期望值來(lái)自于我們對(duì)這個(gè)行業(yè)的熱愛(ài)。我們立志把好的技術(shù)通過(guò)有效、簡(jiǎn)單的方式提供給客戶(hù),將通過(guò)不懈努力成為客戶(hù)在信息化領(lǐng)域值得信任、有價(jià)值的長(zhǎng)期合作伙伴,公司提供的服務(wù)項(xiàng)目有:主機(jī)域名、網(wǎng)頁(yè)空間、營(yíng)銷(xiāo)軟件、網(wǎng)站建設(shè)、麻江網(wǎng)站維護(hù)、網(wǎng)站推廣。
你總是可以用while循環(huán)和手動(dòng)索引運(yùn)算來(lái)編寫(xiě)這些獨(dú)特的循環(huán),但是python提供了一套內(nèi)置函數(shù),可以幫你在for循環(huán)內(nèi)定制迭代:·內(nèi)置函數(shù)range (Python 0.X及之后版本可用)返回一系列連續(xù)增加的整數(shù),可作為for中的索引。內(nèi)置函數(shù)zip (Python 2.0及之后版本可用)返回一系列并行元素的元組,可用于在for中內(nèi)遍歷多個(gè)序列。內(nèi)置函數(shù)enumerate (Python 2.3及之后版本可用)同時(shí)生成可迭代對(duì)象中元素的值和索引,因而我們不必再手動(dòng)計(jì)數(shù)。內(nèi)置函數(shù)map (Python 1.0及之后版本可用)在Python 2.X中與zip有著相似的效果,但是在3.X中 map 的這一角色被移除了。因?yàn)閒or循環(huán)可能會(huì)比基于while的計(jì)數(shù)器循環(huán)運(yùn)行得更快,所以借助這些工具并盡可能地使用for循環(huán),會(huì)讓你受益匪淺。讓我們?cè)诔R?jiàn)的使用場(chǎng)景下,依次看一看這些內(nèi)置函數(shù)吧。我們將會(huì)看到,它們的用法在Python 2.X和3.X中稍有不同,同時(shí)它們中的一些要比其他的更加有效。
python中將函數(shù)和變量封裝成類(lèi)的好處
封裝成類(lèi)的好處,總結(jié)歸納有2個(gè):一個(gè)是保護(hù)隱私,一個(gè)是降低程序復(fù)雜度
使用python簡(jiǎn)單封裝selenium常用函數(shù)
年前走查腳本代碼時(shí),發(fā)現(xiàn)大家對(duì)selenium功能都在重復(fù)造輪子,而且容易出現(xiàn)一些常見(jiàn)低級(jí)bug。于是在閑暇之余,封裝一些常用的selenium功能。
在某些網(wǎng)頁(yè)中,存在多個(gè)frame嵌套。而selenium提供的find_element函數(shù)只能在當(dāng)前frame中查找,不能切換到其他frame中,需要從最上級(jí)frame中逐步切換(當(dāng)然也可以指定xpath的絕對(duì)路徑,但是一般沒(méi)人這么做)。在我們寫(xiě)代碼過(guò)程中,需要明確知道當(dāng)前frame位置和需要尋找元素的frame位置。在frame切換過(guò)程中,容易因?yàn)槭韬鰧?dǎo)致frame切換錯(cuò)誤導(dǎo)致元素?zé)o法找到的bug。
頁(yè)面中分布的frame,可以理解為樹(shù)狀結(jié)構(gòu)。因此我們可以采用遞歸的方式, 沿著某條搜索路線frame節(jié)點(diǎn),依次對(duì)樹(shù)中每個(gè)節(jié)點(diǎn)均做一次訪問(wèn)。
我們以163網(wǎng)址上的登錄框?yàn)槔狐c(diǎn)擊登錄按鈕,彈出登錄iframe頁(yè)面。輸入框位置在iframe中,因此我們不能使用xpath獲取元素位置,需要進(jìn)入iframe中,然后獲取元素。
手動(dòng)切換ifame可能會(huì)產(chǎn)生bug,因此需要一套自動(dòng)切換和檢索frame的機(jī)制。具體代碼如下:
需要注意的是:如果頁(yè)面中多個(gè)frame中,存在相同的xpath元素。還是需要指定frame的路徑,否則會(huì)返回搜索到的第一個(gè)元素。
強(qiáng)制等待
直接調(diào)用系統(tǒng)time.sleep函數(shù),不管頁(yè)面加載情況一定會(huì)等待指定的時(shí)間, 即使元素已被加載 。
1.如果設(shè)置的時(shí)間較長(zhǎng),會(huì)浪費(fèi)時(shí)間
2.如果設(shè)置的時(shí)間較短,元素可能沒(méi)有加載。
頁(yè)面中某元素如果未能立即加載,隱式等待告訴WebDriver需等待一定的時(shí)間,然后去查找元素。默認(rèn)不等待,隱式等待作用于整個(gè)WebDriver周期,只需設(shè)置一次即可。
1.在上文的find_element函數(shù)中,采用遞歸方式在所有frame尋找元素。若采用隱式等待,則在每個(gè)frame中都需要等待設(shè)定的時(shí)間,耗時(shí)非常長(zhǎng)。
2.某些頁(yè)面我們想要的元素已經(jīng)加載完畢,但是部分其他資源未加載。隱式等待必須等待所有元素加載完畢,增加額外等待時(shí)間。
顯示等待一般作用于某一個(gè)元素,在設(shè)定的時(shí)間范圍內(nèi),默認(rèn)每間隔0.5秒查找元素。返回被加載的元素,若超過(guò)設(shè)定的時(shí)間范圍未能查找則報(bào)錯(cuò)。顯示等待作為selenium常用的等待機(jī)制,我們來(lái)看下他的源碼和機(jī)制。
driver 注釋中解釋為WebDriver實(shí)例,但是代碼中并未有相關(guān)檢測(cè),因此可以傳入任何對(duì)象
但是__repr__函數(shù)中使用到session_id屬性,如果需要顯示屬性或者轉(zhuǎn)為str對(duì)象,最好在driver對(duì)象中添加session_id屬性
在until函數(shù)中,我們可以看到driver對(duì)象傳入method函數(shù)。在計(jì)時(shí)結(jié)束前,在不斷循環(huán)執(zhí)行method函數(shù),如果method函數(shù)有正常返回值則退出循環(huán),否則報(bào)TimeoutException錯(cuò)誤。
可以采用裝飾器對(duì)隱式等待進(jìn)行封裝,這樣代碼更加精簡(jiǎn)
同樣的,采用裝飾器對(duì)其他常用的函數(shù)進(jìn)行封裝,例如強(qiáng)制等待、點(diǎn)擊、輸入文本等。
裝飾器雖然很方便,但也會(huì)產(chǎn)生一些麻煩。例如在find_element函數(shù)遞歸調(diào)用過(guò)程中,理應(yīng)只要執(zhí)行一次裝飾器函數(shù)。但因?yàn)檠b飾器已經(jīng)裝飾完畢,導(dǎo)致每次遞歸都會(huì)執(zhí)行。例如強(qiáng)制等待的sleep函數(shù),如果遞歸次數(shù)越多等待時(shí)間越長(zhǎng)。
解除裝飾器一般有兩種做法:一是約定參數(shù),當(dāng)遞歸第二次調(diào)用時(shí)則不生效。例如
這種方式實(shí)現(xiàn)簡(jiǎn)單,容易理解。但是增加了參數(shù)限制,在fun函數(shù)中就不能使用first_sleep參數(shù)。
二是采用裝飾器采用wrapped實(shí)現(xiàn),通過(guò)訪問(wèn)wrapped屬性獲得原始函數(shù)。例如
但是某一個(gè)函數(shù)被多個(gè)裝飾器裝飾時(shí),需要遞歸解除裝飾器。例如
最后整體代碼如下
這次的封裝其實(shí)還存在很多問(wèn)題
1.find_element函數(shù)不僅僅只是提供查找元素功能,還提供一些其他功能,因此叫element_operation更為合適。
2.find_element函數(shù)的參數(shù)過(guò)多,并且很多參數(shù)的使用并不在函數(shù)本身中,對(duì)代碼閱讀很不友好。
3.得小心避免參數(shù)重復(fù)問(wèn)題,假設(shè)裝飾器sleep和裝飾器wait_time都使用time這個(gè)參數(shù),將無(wú)法區(qū)分具體是哪個(gè)函數(shù)使用。
4.不利于擴(kuò)展和維護(hù),當(dāng)功能過(guò)多時(shí)find_element的參數(shù)過(guò)于龐大。
如果只是簡(jiǎn)單地封裝和使用,上面這種方式也能達(dá)到較好的效果。如果想進(jìn)一步封裝,建議采用鏈?zhǔn)秸{(diào)用方式,裝飾器輔助封裝。例如
這樣函數(shù)的擴(kuò)展性和可閱讀性有較大的提升
將下面Python代碼封裝成函數(shù)
Python:常用函數(shù)封裝:
def is_chinese(uchar):
"""判斷一個(gè)unicode是否是漢字"""
if uchar = u'\u4e00' and uchar=u'\u9fa5':
return True
else:
return False
def is_number(uchar):
"""判斷一個(gè)unicode是否是數(shù)字"""
if uchar = u'\u0030' and uchar=u'\u0039':
return True
else:
return False
def is_alphabet(uchar):
"""判斷一個(gè)unicode是否是英文字母"""
if (uchar = u'\u0041' and uchar=u'\u005a') or (uchar = u'\u0061' and uchar=u'\u007a'):
return True
else:
return False
def is_other(uchar):
"""判斷是否非漢字,數(shù)字和英文字符"""
if not (is_chinese(uchar) or is_number(uchar) or is_alphabet(uchar)):
return True
else:
return False
def B2Q(uchar):
"""半角轉(zhuǎn)全角"""
inside_code=ord(uchar)
if inside_code0x0020 or inside_code0x7e: #不是半角字符就返回原來(lái)的字符
return uchar
if inside_code==0x0020: #除了空格其他的全角半角的公式為:半角=全角-0xfee0
inside_code=0x3000
else:
inside_code+=0xfee0
return unichr(inside_code)
def Q2B(uchar):
"""全角轉(zhuǎn)半角"""
inside_code=ord(uchar)
if inside_code==0x3000:
inside_code=0x0020
else:
inside_code-=0xfee0
if inside_code0x0020 or inside_code0x7e: #轉(zhuǎn)完之后不是半角字符返回原來(lái)的字符
return uchar
return unichr(inside_code)
def stringQ2B(ustring):
"""把字符串全角轉(zhuǎn)半角"""
return "".join([Q2B(uchar) for uchar in ustring])
def uniform(ustring):
"""格式化字符串,完成全角轉(zhuǎn)半角,大寫(xiě)轉(zhuǎn)小寫(xiě)的工作"""
return stringQ2B(ustring).lower()
def string2List(ustring):
"""將ustring按照中文,字母,數(shù)字分開(kāi)"""
retList=[]
utmp=[]
for uchar in ustring:
if is_other(uchar):
if len(utmp)==0:
continue
else:
retList.append("".join(utmp))
utmp=[]
else:
utmp.append(uchar)
if len(utmp)!=0:
retList.append("".join(utmp))
return retList
如何用Python封裝C語(yǔ)言的字符串處理函數(shù)
在C語(yǔ)言中,字符串處理是每天都要面對(duì)的問(wèn)題。我們都知道C語(yǔ)言中其實(shí)并沒(méi)有一種原生的字符串類(lèi)型,‘字符串’在C語(yǔ)言里只是一種特殊的以''結(jié)尾的字符數(shù)組。因此,如何將C語(yǔ)言與更高層次的Python語(yǔ)言在‘字符串’處理這個(gè)問(wèn)題上對(duì)接是一個(gè)有難度的問(wèn)題。所幸有swig這種強(qiáng)大的工具。
如何封裝一個(gè)函數(shù),它修改參數(shù)字符串的內(nèi)容
假如有這樣一個(gè)C語(yǔ)言的函數(shù),
!-- lang: cpp --
void FillZero(char* pc,size_t * piLen)
{
size_t i=0;
while(i++*piLen/2 )
*pc++ = '0';
*pc = 0;
*piLen = i+1;
}
這個(gè)函數(shù)的功能是把字符串變成n個(gè)0。不過(guò)我們更關(guān)注函數(shù)的形式。這樣的函數(shù),表面上看char* pc是函數(shù)的參數(shù),可是實(shí)際上它才是函數(shù)的返回值和執(zhí)行的結(jié)果。piLen這個(gè)參數(shù)既是pc的最大長(zhǎng)度,也是新的字符串的長(zhǎng)度。我們直接用python封裝,看看運(yùn)行結(jié)果。
Type "help", "copyright", "credits" or "license" for more information.
import cchar
s='123456'
cchar.FillZero(s,6)
Traceback (most recent call last):
File "stdin", line 1, in module
TypeError: in method 'FillZero', argument 2 of type 'size_t *'
結(jié)果差強(qiáng)人意,不是我們想要得到的結(jié)果。函數(shù)的第二個(gè)參數(shù)為size_t* 我們很難用python來(lái)表示,而且python中也不存在既是輸入,也是輸出的參數(shù)。
swig有一個(gè)標(biāo)準(zhǔn)庫(kù),其中有一個(gè)cstring.i文件就是用來(lái)解決C語(yǔ)言字符串類(lèi)型的問(wèn)題。
我們?cè)?i文件中加入這樣幾行
!-- lang: cpp --
%include "cstring.i"
%cstring_output_withsize(char* pc,size_t* pi)
void FillZero(char* pc, size_t* pi);
然后運(yùn)行看結(jié)果
Type "help", "copyright", "credits" or "license" for more information.
import cchar
cchar.FillZero(10)
'00000\x00'
s=cchar.FillZero(10)
print s
00000
我們看函數(shù)的變化。首先在python里, FillZero變成了只有一個(gè)參數(shù)的函數(shù)。然后函數(shù)的返回值變成了一個(gè)字符串。其實(shí)cstring_output_size其實(shí)是一個(gè)宏,通過(guò)這個(gè)宏的定義改變了函數(shù)的形式,直接在Python中得到我們想要的結(jié)果。
其實(shí)類(lèi)似cstring_output_size的宏還有好幾個(gè),我列舉一下:
cstring_output_allocate(char *s,free($1));
第一個(gè)參數(shù)是指向字符串地址的指針,第二個(gè)參數(shù)為釋放空間的方法。
大家考慮這一下這樣的函數(shù):
void foo(char* s)
{
s = (char*)malloc(10);
memcpy(s,"123456789",9);
}
s這個(gè)參數(shù)表面上看是輸入,實(shí)際上是函數(shù)真正的輸出。 函數(shù)中真正改變的東西是chars指向的字符串的值。而且char這個(gè)類(lèi)型,
python或者其他腳本語(yǔ)言里應(yīng)該都沒(méi)有對(duì)應(yīng)的類(lèi)型。那么我們用cstring_output_allocate將這個(gè)函數(shù)轉(zhuǎn)換成另外一個(gè)形式的python或者其他腳本語(yǔ)言的函數(shù)。轉(zhuǎn)換后的函數(shù)其實(shí)是這樣的,以python為例str
foo()。
!-- lang: cpp --
%module a
%include "cstring.i"
%{
void foo(char* s);
%}
%cstring_output_allocate(char *s, free(*$1));
void foo(char *s);
在python中的調(diào)用:
!-- lang: python --
import a
a.foo()
'123456789'
cstring_output_maxsize(char *path, int maxpath);
第一個(gè)參數(shù)也是可以改變的字符串首地址,第二個(gè)參數(shù)為字符串的最大長(zhǎng)度。在Python中調(diào)用的時(shí)候,只有maxpath這個(gè)參數(shù),返回字符串。
cstring_output_allocate(char *s, free($1));
第一個(gè)參數(shù)為指向字符串首地址的指針,第二個(gè)參數(shù)為釋放指針的方法。這個(gè)宏主要是封裝一種直接在函數(shù)內(nèi)部malloc空間的函數(shù)。在Python中調(diào)用時(shí)沒(méi)有參數(shù),直接返回字符串。
cstring_output_allocate_size(char *s, int slen, free(*$1));
這個(gè)相當(dāng)于前面兩個(gè)函數(shù)的組合。在函數(shù)內(nèi)部malloc空間,然后將字符串長(zhǎng)度通過(guò)slen返回。其實(shí)在調(diào)用的時(shí)候非常簡(jiǎn)單,沒(méi)有參數(shù),直接返回字符串。
如何處理c++的std::string
std::string是C++標(biāo)準(zhǔn)類(lèi)庫(kù)STL中常見(jiàn)的類(lèi)。在平時(shí)工作中大家肯定是沒(méi)少用。在python中如何封裝std::string? swig提供了標(biāo)準(zhǔn)庫(kù)
例如函數(shù):
!-- lang: cpp --
string Repeat(const string s)
{
return s+s;
}
只要在swig中加入這樣幾行:
!-- lang: cpp --
%include "std_string.i"
using namespace std;
string Repeat(const string s);
運(yùn)行結(jié)果:
Python 2.6.6 (r266:84292, Dec 27 2010, 00:02:40)
[GCC 4.4.5] on linux2
Type "help", "copyright", "credits" or "license" for more information.
import cchar
cchar.Repeat('123')
'123123'
使用起來(lái)很方便,但需要注意的是,假如函數(shù)的參數(shù)的內(nèi)容是可以被修改,就不能用這種方式封裝。
例如:
!-- lang: cpp --
void repeat(string s)
{
s+=s;
}
這樣的函數(shù)直接使用 'std_string.i' 就是無(wú)效的。遇到這種函數(shù),只能用C語(yǔ)言封裝成 void repeat(chars, int maxsize), 再用swig調(diào)用 'cstring_output_withsize' 這個(gè)宏再封裝一次了。
Python如何把一段代碼封裝起來(lái)重復(fù)使用
你可以用類(lèi)或者函數(shù)將其封裝一下,將需要后期變動(dòng)的變量作為參數(shù)放在其中,可以使用默認(rèn)值傳參。
舉個(gè)簡(jiǎn)單函數(shù)和類(lèi)的栗子:
#?函數(shù)封裝
def?sum(a,?b=3):
return?a?+?b
#?類(lèi)封裝
class?S(object):
def?__init__(self,?a=2,?b=3)
self.a?=?a
self.b?=?b
def?sum(self):
return?self.a?+?self.b
標(biāo)題名稱(chēng):python循環(huán)封裝函數(shù),python封裝函數(shù)的調(diào)用
路徑分享:http://www.dlmjj.cn/article/dsissej.html