真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯網站制作重慶分公司

函數返回對象python js函數返回對象

python中return是什么意思呢?

題主你好,

創(chuàng)新互聯建站網站建設提供從項目策劃、軟件開發(fā),軟件安全維護、網站優(yōu)化(SEO)、網站分析、效果評估等整套的建站服務,主營業(yè)務為成都網站設計、做網站,app軟件開發(fā)以傳統(tǒng)方式定制建設網站,并提供域名空間備案等一條龍服務,秉承以專業(yè)、用心的態(tài)度為用戶提供真誠的服務。創(chuàng)新互聯建站深信只要達到每一位用戶的要求,就會得到認可,從而選擇與我們長期合作。這樣,我們也可以走得更遠!

每門語言中都有自己語法, python中return關鍵字的用法是:

也就是說return后面要接的是表達式, 但如果按題主所說的,寫成:

要注意 "person = {xxx}" 這是一個語句, 而非一個表達式, 和python中定義的return語法是相背的,所以不能這么寫.

希望可以幫到題主, 歡迎追問.

函數range()返回對象

在python3中,執(zhí)行下面的語句

得到結果是 range(0,10) ,但是如果換一種方式

得到的結果就是[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

那為什么會這樣呢?其實在Python3中range()函數返回的對象很像一個列表,但是它確實不是一個列表,它只是在迭代的情況下返回指定索引的值,它并不會在內存中產生一個列表對象,官方解釋說這樣做是為了節(jié)約內存空間。通常我們稱這種對象是可迭代的,或者是可迭代對象。

這里就要引入另外一個叫迭代器的概念,迭代器可以從一個可迭代對象中連續(xù)獲取指定索引的值,直到索引結束。比如list()函數,所以在上面的例子中,我們可以用list()這個迭代器將range()函數返回的對象變成一個列表。

由此可以看出:range()函數返回的是一個可迭代對象(類型是對象),而不是列表類型;list() 函數是對象迭代器,把對象轉為一個列表,返回的變量類型為列表。

Python 里為什么函數可以返回一個函數內部定義的函數

“在Python中,函數本身也是對象”

這一本質。那不妨慢慢來,從最基本的概念開始,討論一下這個問題:

1. Python中一切皆對象

這恐怕是學習Python最有用的一句話。想必你已經知道Python中的list, tuple, dict等內置數據結構,當你執(zhí)行:

alist = [1, 2, 3]

時,你就創(chuàng)建了一個列表對象,并且用alist這個變量引用它:

當然你也可以自己定義一個類:

class House(object):

def __init__(self, area, city):

self.area = area

self.city = city

def sell(self, price):

[...] #other code

return price

然后創(chuàng)建一個類的對象:

house = House(200, 'Shanghai')

OK,你立馬就在上海有了一套200平米的房子,它有一些屬性(area, city),和一些方法(__init__, self):

2. 函數是第一類對象

和list, tuple, dict以及用House創(chuàng)建的對象一樣,當你定義一個函數時,函數也是對象:

def func(a, b):

return a+b

在全局域,函數對象被函數名引用著,它接收兩個參數a和b,計算這兩個參數的和作為返回值。

所謂第一類對象,意思是可以用標識符給對象命名,并且對象可以被當作數據處理,例如賦值、作為參數傳遞給函數,或者作為返回值return 等

因此,你完全可以用其他變量名引用這個函數對象:

add = func

這樣,你就可以像調用func(1, 2)一樣,通過新的引用調用函數了:

print func(1, 2)

print add(1, 2) #the same as func(1, 2)

或者將函數對象作為參數,傳遞給另一個函數:

def caller_func(f):

return f(1, 2)

if __name__ == "__main__":

print caller_func(func)

可以看到,

函數對象func作為參數傳遞給caller_func函數,傳參過程類似于一個賦值操作f=func;

于是func函數對象,被caller_func函數作用域中的局部變量f引用,f實際指向了函數func;cc

當執(zhí)行return f(1, 2)的時候,相當于執(zhí)行了return func(1, 2);

因此輸出結果為3。

3. 函數對象 vs 函數調用

無論是把函數賦值給新的標識符,還是作為參數傳遞給新的函數,針對的都是函數對象本身,而不是函數的調用。

用一個更加簡單,但從外觀上看,更容易產生混淆的例子來說明這個問題。例如定義了下面這個函數:

def func():

return "hello,world"

然后分別執(zhí)行兩次賦值:

ref1 = func #將函數對象賦值給ref1

ref2 = func() #調用函數,將函數的返回值("hello,world"字符串)賦值給ref2

很多初學者會混淆這兩種賦值,通過Python內建的type函數,可以查看一下這兩次賦值的結果:

In [4]: type(ref1)

Out[4]: function

In [5]: type(ref2)

Out[5]: str

可以看到,ref1引用了函數對象本身,而ref2則引用了函數的返回值。通過內建的callable函數,可以進一步驗證ref1是可調用的,而ref2是不可調用的:

In [9]: callable(ref1)

Out[9]: True

In [10]: callable(ref2)

Out[10]: False

傳參的效果與之類似。

4. 閉包LEGB法則

所謂閉包,就是將組成函數的語句和這些語句的執(zhí)行環(huán)境打包在一起時,得到的對象

聽上去的確有些復雜,還是用一個栗子來幫助理解一下。假設我們在foo.py模塊中做了如下定義:

#foo.py

filename = "foo.py"

def call_func(f):

return f() #如前面介紹的,f引用一個函數對象,然后調用它

在另一個func.py模塊中,寫下了這樣的代碼:

#func.py

import foo #導入foo.py

filename = "func.py"

def show_filename():

return "filename: %s" % filename

if __name__ == "__main__":

print foo.call_func(show_filename) #注意:實際發(fā)生調用的位置,是在foo.call_func函數中

當我們用python func.py命令執(zhí)行func.py時輸出結果為:

chiyu@chiyu-PC:~$ python func.py

filename:func.py

很顯然show_filename()函數使用的filename變量的值,是在與它相同環(huán)境(func.py模塊)中定義的那個。盡管foo.py模塊中也定義了同名的filename變量,而且實際調用show_filename的位置也是在foo.py的call_func內部。

而對于嵌套函數,這一機制則會表現的更加明顯:閉包將會捕捉內層函數執(zhí)行所需的整個環(huán)境:

#enclosed.py

import foo

def wrapper():

filename = "enclosed.py"

def show_filename():

return "filename: %s" % filename

print foo.call_func(show_filename) #輸出:filename: enclosed.py

實際上,每一個函數對象,都有一個指向了該函數定義時所在全局名稱空間的__globals__屬性:

#show_filename inside wrapper

#show_filename.__globals__

{

'__builtins__': module '__builtin__' (built-in), #內建作用域環(huán)境

'__file__': 'enclosed.py',

'wrapper': function wrapper at 0x7f84768b6578, #直接外圍環(huán)境

'__package__': None,

'__name__': '__main__',

'foo': module 'foo' from '/home/chiyu/foo.pyc', #全局環(huán)境

'__doc__': None

}

當代碼執(zhí)行到show_filename中的return "filename: %s" % filename語句時,解析器按照下面的順序查找filename變量:

Local - 本地函數(show_filename)內部,通過任何方式賦值的,而且沒有被global關鍵字聲明為全局變量的filename變量;

Enclosing - 直接外圍空間(上層函數wrapper)的本地作用域,查找filename變量(如果有多層嵌套,則由內而外逐層查找,直至最外層的函數);

Global - 全局空間(模塊enclosed.py),在模塊頂層賦值的filename變量;

Builtin - 內置模塊(__builtin__)中預定義的變量名中查找filename變量;

在任何一層先找到了符合要求的filename變量,則不再向更外層查找。如果直到Builtin層仍然沒有找到符合要求的變量,則拋出NameError異常。這就是變量名解析的:LEGB法則。

總結:

閉包最重要的使用價值在于:封存函數執(zhí)行的上下文環(huán)境;

閉包在其捕捉的執(zhí)行環(huán)境(def語句塊所在上下文)中,也遵循LEGB規(guī)則逐層查找,直至找到符合要求的變量,或者拋出異常。

5. 裝飾器語法糖(syntax sugar)

那么閉包和裝飾器又有什么關系呢?

上文提到閉包的重要特性:封存上下文,這一特性可以巧妙的被用于現有函數的包裝,從而為現有函數更加功能。而這就是裝飾器。

還是舉個例子,代碼如下:

#alist = [1, 2, 3, ..., 100] -- 1+2+3+...+100 = 5050

def lazy_sum():

return reduce(lambda x, y: x+y, alist)

我們定義了一個函數lazy_sum,作用是對alist中的所有元素求和后返回。alist假設為1到100的整數列表:

alist = range(1, 101)

但是出于某種原因,我并不想馬上返回計算結果,而是在之后的某個地方,通過顯示的調用輸出結果。于是我用一個wrapper函數對其進行包裝:

def wrapper():

alist = range(1, 101)

def lazy_sum():

return reduce(lambda x, y: x+y, alist)

return lazy_sum

lazy_sum = wrapper() #wrapper() 返回的是lazy_sum函數對象

if __name__ == "__main__":

lazy_sum() #5050

這是一個典型的Lazy Evaluation的例子。我們知道,一般情況下,局部變量在函數返回時,就會被垃圾回收器回收,而不能再被使用。但是這里的alist卻沒有,它隨著lazy_sum函數對象的返回被一并返回了(這個說法不準確,實際是包含在了lazy_sum的執(zhí)行環(huán)境中,通過__globals__),從而延長了生命周期。

當在if語句塊中調用lazy_sum()的時候,解析器會從上下文中(這里是Enclosing層的wrapper函數的局部作用域中)找到alist列表,計算結果,返回5050。

當你需要動態(tài)的給已定義的函數增加功能時,比如:參數檢查,類似的原理就變得很有用:

def add(a, b):

return a+b

這是很簡單的一個函數:計算a+b的和返回,但我們知道Python是 動態(tài)類型+強類型 的語言,你并不能保證用戶傳入的參數a和b一定是兩個整型,他有可能傳入了一個整型和一個字符串類型的值:

In [2]: add(1, 2)

Out[2]: 3

In [3]: add(1.2, 3.45)

Out[3]: 4.65

In [4]: add(5, 'hello')

---------------------------------------------------------------------------

TypeError Traceback (most recent call last)

/home/chiyu/ipython-input-4-f2f9e8aa5eae in module()

---- 1 add(5, 'hello')

/home/chiyu/ipython-input-1-02b3d3d6caec in add(a, b)

1 def add(a, b):

---- 2 return a+b

TypeError: unsupported operand type(s) for +: 'int' and 'str'

于是,解析器無情的拋出了一個TypeError異常。

動態(tài)類型:在運行期間確定變量的類型,python確定一個變量的類型是在你第一次給他賦值的時候;

強類型:有強制的類型定義,你有一個整數,除非顯示的類型轉換,否則絕不能將它當作一個字符串(例如直接嘗試將一個整型和一個字符串做+運算);

因此,為了更加優(yōu)雅的使用add函數,我們需要在執(zhí)行+運算前,對a和b進行參數檢查。這時候裝飾器就顯得非常有用:

import logging

logging.basicConfig(level = logging.INFO)

def add(a, b):

return a + b

def checkParams(fn):

def wrapper(a, b):

if isinstance(a, (int, float)) and isinstance(b, (int, float)): #檢查參數a和b是否都為整型或浮點型

return fn(a, b) #是則調用fn(a, b)返回計算結果

#否則通過logging記錄錯誤信息,并友好退出

logging.warning("variable 'a' and 'b' cannot be added")

return

return wrapper #fn引用add,被封存在閉包的執(zhí)行環(huán)境中返回

if __name__ == "__main__":

#將add函數對象傳入,fn指向add

#等號左側的add,指向checkParams的返回值wrapper

add = checkParams(add)

add(3, 'hello') #經過類型檢查,不會計算結果,而是記錄日志并退出

注意checkParams函數:

首先看參數fn,當我們調用checkParams(add)的時候,它將成為函數對象add的一個本地(Local)引用;

在checkParams內部,我們定義了一個wrapper函數,添加了參數類型檢查的功能,然后調用了fn(a, b),根據LEGB法則,解釋器將搜索幾個作用域,并最終在(Enclosing層)checkParams函數的本地作用域中找到fn;

注意最后的return wrapper,這將創(chuàng)建一個閉包,fn變量(add函數對象的一個引用)將會封存在閉包的執(zhí)行環(huán)境中,不會隨著checkParams的返回而被回收;

當調用add = checkParams(add)時,add指向了新的wrapper對象,它添加了參數檢查和記錄日志的功能,同時又能夠通過封存的fn,繼續(xù)調用原始的add進行+運算。

因此調用add(3, 'hello')將不會返回計算結果,而是打印出日志:

chiyu@chiyu-PC:~$ python func.py

WARNING:root:variable 'a' and 'b' cannot be added

有人覺得add = checkParams(add)這樣的寫法未免太過麻煩,于是python提供了一種更優(yōu)雅的寫法,被稱為語法糖:

@checkParams

def add(a, b):

return a + b

這只是一種寫法上的優(yōu)化,解釋器仍然會將它轉化為add = checkParams(add)來執(zhí)行。

6. 回歸問題

def addspam(fn):

def new(*args):

print "spam,spam,spam"

return fn(*args)

return new

@addspam

def useful(a,b):

print a**2+b**2

首先看第二段代碼:

@addspam裝飾器,相當于執(zhí)行了useful = addspam(useful)。在這里題主有一個理解誤區(qū):傳遞給addspam的參數,是useful這個函數對象本身,而不是它的一個調用結果;

再回到addspam函數體:

return new 返回一個閉包,fn被封存在閉包的執(zhí)行環(huán)境中,不會隨著addspam函數的返回被回收;

而fn此時是useful的一個引用,當執(zhí)行return fn(*args)時,實際相當于執(zhí)行了return useful(*args);

最后附上一張代碼執(zhí)行過程中的引用關系圖,希望能幫助你理解:

python中l(wèi)ist(range())、range()、list()函數的用法

轉自

Python? range() 函數返回的是一個可迭代對象(類型是對象),而不是列表類型, 所以打印的時候不會打印列表。

函數語法:

range(stop)range(start,stop,step)//默認start為0,step為1

Python? list() 函數是對象迭代器,可以把range()返回的可迭代對象轉為一個列表,返回的變量類型為列表。

list() 方法用于將元組轉換為列表。

注: 元組與列表是非常類似的,區(qū)別在于元組的元素值不能修改,元組是放在括號中( ),列表是放于方括號中[ ]。

元組中只包含一個元素時,需要在元素后面添加逗號

tup1=(50,)

list、元組與字符串的索引一樣,列表索引從0開始。列表可以進行截取、組合等。

python xpath解析返回對象怎么處理

在進行網頁抓取的時候,分析定位html節(jié)點是獲取抓取信息的關鍵,目前我用的是lxml模塊(用來分析XML文檔結構的,當然也能分析html結構), 利用其lxml.html的xpath對html進行分析,獲取抓取信息。

首先,我們需要安裝一個支持xpath的python庫。目前在libxml2的網站上被推薦的python binding是lxml,也有beautifulsoup,不嫌麻煩的話還可以自己用正則表達式去構建,本文以lxml為例講解。

假設有如下的HTML文檔:

1 html 2 ? body 3 ? ? form 4 ? ? ? div id='leftmenu' 5 ? ? ? ? h3text/h3 6 ? ? ? ? ul id=’china’!-- first location -- 7 ? ? ? ? ? li.../li 8 ? ? ? ? ? li.../li 9 ?? ? ? ? ? ? ......10 ? ? ? ? /ul11 ? ? ? ? ul id=’england’!-- second location--12 ? ? ? ? ? li.../li13 ? ? ? ? ? li.../li14 ?? ? ? ? ? ? ......15 ? ? ? ? /ul16 ? ? ? /div17 ? ? /form18 ? /body19 /html ? ? ? ?

直接使用lxml處理:

1 import codecs2 from lxml import etree3 f=codecs.open("ceshi.html","r","utf-8")4 content=f.read()5 f.close()6 tree=etree.HTML(content)

etree提供了HTML這個解析函數,現在我們可以直接對HTML使用xpath了,是不是有點小激動,現在就嘗試下吧。

在使用xpath之前我們先來看看作為對照的jQuery和RE。

在jQuery里要處理這種東西就很簡單,特別是假如那個ul節(jié)點有id的話(比如是ul id=’china’):

$("#china").each(function(){...});

具體到此處是:

$("#leftmenu").children("h3:contains('text')").next("ul").each(function(){...});

找到id為leftmenu的節(jié)點,在其下找到一個內容包含為”text”的h3節(jié)點,再取其接下來的一個ul節(jié)點。

在python里要是用RE來處理就略麻煩一些:

block_pattern=re.compile(u"h3檔案/h3(.*?)h3", re.I | re.S)

m=block_pattern.findall(content)

item_pattern=re.compile(u"li(.*?)/li", re.I | re.S)

items=item_pattern.findall(m[0])for i in items: ? ?print i

那么用xpath要怎么做呢?其實跟jQuery是差不多的:

nodes=tree.xpath("/descendant::ul[@id='china']")

當然,現在沒有id的話也就只能用類似于jQuery的方法了。完整的xpath應該是這樣寫的(注意,原文件中的TAG有大小寫的情況,但是在XPATH里只能用小寫):

nodes=tree.xpath(u"/html/body/form/div[@id='leftmenu']/h3[text()='text']/following-sibling::ul[1]")

更簡單的方法就是像jQuery那樣直接根據id定位:

nodes=tree.xpath(u"http://div[@id='leftmenu']/h3[text()='text']/following-sibling::ul[1]")

這兩種方法返回的結果中,nodes[0]就是那個“text”的h3節(jié)點后面緊跟的第一個ul節(jié)點,這樣就可以列出后面所有的ul節(jié)點內容了。

如果ul節(jié)點下面還有其他的節(jié)點,我們要找到更深節(jié)點的內容,如下的循環(huán)就是把這些節(jié)點的文本內容列出:

nodes=nodes[0].xpath("li/a")for n in nodes: ? ?print n.text

對比三種方法應該可以看出xpath和jQuery對于頁面的解析都是基于XML的語義進行,而RE則純粹是基于plain

text。RE對付簡單的頁面是沒有問題,如果頁面結構復雜度較高的時候(比如一堆的DIV來回嵌套之類),設計一個恰當的RE

pattern可能會遠比寫一個xpath要復雜。特別是目前主流的基于CSS的頁面設計方式,其中大部分關鍵節(jié)點都會有id――對于使用jQuery的頁面來說則更是如此,這時xpath相比RE就有了決定性的優(yōu)勢。

附錄:基本XPATH語法介紹,詳細請參考XPath的官方文檔

XPATH基本上是用一種類似目錄樹的方法來描述在XML文檔中的路徑。比如用“/”來作為上下層級間的分隔。第一個“/”表示文檔的根節(jié)點(注意,不是指文檔最外層的tag節(jié)點,而是指文檔本身)。比如對于一個HTML文件來說,最外層的節(jié)點應該是”/html”。

同樣的,“..”和“.”分別被用來表示父節(jié)點和本節(jié)點。

XPATH返回的不一定就是唯一的節(jié)點,而是符合條件的所有節(jié)點。比如在HTML文檔里使用“/html/head/scrpt”就會把head里的所有script節(jié)點都取出來。

為了縮小定位范圍,往往還需要增加過濾條件。過濾的方法就是用“[”“]”把過濾條件加上。比如在HTML文檔里使用“/html/body/div[@id='main']”,即可取出body里id為main的div節(jié)點。

其中@id表示屬性id,類似的還可以使用如@name, @value, @href, @src, @class….

函數text()的意思則是取得節(jié)點包含的文本。比如:divhellopworld/p

/div中,用”div[text()='hello']“即可取得這個div,而world則是p的text()。

函數position()的意思是取得節(jié)點的位置。比如“l(fā)i[position()=2]”表示取得第二個li節(jié)點,它也可以被省略為“l(fā)i[2]”。

不過要注意的是數字定位和過濾

條件的順序。比如“ul/li[5][@name='hello']”表示取ul下第五項li,并且其name必須是hello,否則返回空。而如果用

“ul/li[@name='hello'][5]”的意思就不同,它表示尋找ul下第五個name為”hello“的li節(jié)點。

此外,“*”可以代替所有的節(jié)點名,比如用”/html/body/*/span”可以取出body下第二級的所有span,而不管它上一級是div還是p或是其它什么東東。

“descendant::”前綴可以指代任意多層的中間節(jié)點,它也可以被省略成一個“/”。比如在整個HTML文檔中查找id為“l(fā)eftmenu”的

div,可以用“/descendant::div[@id='leftmenu']”,也可以簡單地使用“

//div[@id='leftmenu']”。

至于“following-sibling::”前綴就如其名所說,表示同一層的下一個節(jié)點。”following-sibling::*”就是任意下一個節(jié)點,而“following-sibling::ul”就是下一個ul節(jié)點。

python range() 函數返回的是?

返回的是一個可迭代對象,不是返回列表。

比如說list(range(1,10))

list是一個迭代器接受range返回的可迭代對象生成一個列表


網頁標題:函數返回對象python js函數返回對象
分享URL:http://weahome.cn/article/hgiesj.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部