return語句用于終止一個函數的執行,同時將一個返回值返回給這個函數的調用者。因此,return語句必須要被包含在函數之中;否則,程序就會出錯。如果沒有為return語句指明它的返回值,那么它就默認返回undefined。
如果一個函數中沒有顯式的寫明return語句,那么在函數執行時JavaScript會在該函數執行流程的末尾自動添加一條未指明返回值的return語句。return語句也可以被添加在函數的前面部分,這通常用于當滿足某個條件時而提前退出函數。
return語句的語法結構如下所示:
return [expression];
其中expression可以是JavaScript中任意合法的表達式,它的計算結果就是return語句的返回值,在函數終止的時候會被返回給該函數的調用者。如果省略了expression,那么return語句的返回值就默認為undefined。
如果要顯式指明expression,那么它和return關鍵字必須寫在同一行上,即它們之間不能有換行符。否則,JavaScript會自動在return關鍵字的后面添加分號。此時,該return語句其實是一個未指明返回值的return語句,而expression在return語句之后永遠都不會被執行到。
<script>
// 定義一個函數,計算一個數的兩倍
function twice(x) {
var result = x * 2;
return result;
}
// 調用該函數,并打印返回值
var value1 = twice(9);
console.log("value1 = " + value1);
</script>
以上代碼的執行結果如下圖所示。我們用實參9調用函數twice(),它先計算9的兩倍然后再返回該結果,隨后該返回值被賦值給了變量value1。第10行的代碼打印出value1的值,可以看到它的值確實為18。
該示例中的twice()函數還可以簡寫為下面的形式,即計算兩倍的表達式被包含在return語句中,它的結果被直接返回。這樣就不需要先聲明一個變量臨時保存計算結果,再用return語句返回該變量。
<script>
// 和上面代碼中的twice函數完全等價
function twice(x) {
return x * 2;
}
</script>
<script>
// 定義一個函數,它的最后是一條沒有指明返回值的return語句
function abc() {
console.log("執行函數abc().");
return;
}
// 調用該函數,并打印返回值
var value2 = abc();
console.log("value2 = " + value2);
</script>
從下圖的執行結果中我們可以看到,首先打印出了字符串"執行函數abc().",說明函數abc()確實被執行了。第10行的代碼打印出的變量value2的值為undefined,這正是return語句的默認返回值。
<script>
// 定義一個函數,它省略了return語句
function abc() {
console.log("執行函數abc().");
}
// 調用該函數,并打印返回值
var value3 = abc();
console.log("value3 = " + value3);
</script>
下圖中的執行結果表明,該示例和上一個例子的執行結果完全一致(除了變量被命名為value3之外)。該例子的成功執行表明,當一個函數的執行流程的最后一條語句是沒有顯式指定返回值的return語句時,該return語句可以被省略。
當一個函數的執行流程的最后缺少return語句的時候,JavaScript會自動在該執行流程的最后添加一條沒有返回值的return語句,當然該函數的返回值就為undefined了。
<script>
// return 語句在函數之外:這會導致程序出錯
return;
console.log("青石野草");
</script>
以上代碼的執行結果如下圖所示,我們可以看到瀏覽器明確指出第3行的return語句是錯誤的。
return語句不一定非要是函數的最后一條語句,它也可以處于函數的前面或中間,用于提前終止函數的執行。示例代碼如下所示:
<script>
// 定義一個函數,它計算一個數的相反數;
// 當參數為0時,它會被提前終止
function opposite(x) {
if(x == 0) {
console.log("0的相反數是它自身。");
return 0;
}
console.log("不為0的數的相反數是它的負數。");
return -x;
}
// 調用函數,并打印返回值
var value4 = opposite(0);
console.log("value4 = " + value4);
</script>
我們使用實參0調用函數opposite(),當實參為0的時候,會執行if語句中的代碼。它首先打印字符串"0的相反數是它自身。",然后遇到語句return 0;。這條return語句提前終止函數的執行,并返回0。因此,if語句后面的那一條打印語句和return -x;均不會被執行。下圖中的執行結果正印證了這一執行流程。
這個例子也說明了一個函數可以包含多個return語句,用于根據不同的情況而退出函數。
<script>
// 定義一個函數,它和第一個例子中的函數幾乎一樣;
// 只是原本的return語句被拆分成了兩行。
function twice(x) {
var result = x * 2;
return
result;
}
// 調用函數,并打印返回值
var value5 = twice(9);
console.log("value5 = " + value5);
</script>
該示例的執行結果如下圖所示,可以看到第11行打印出的變量value5的值為undefined,而不是我們原本期望的數字18。這是怎么回事呢?
這個示例和第一個例子唯一的不同就是我們把return語句拆成了兩行,return關鍵字和它的返回值result被寫在了不同的行上。在其它編程語言或者JavaScript的某些其它語句中,這樣的拆行不會對原程序有任何影響。
但JavaScript的return語句是個例外,在本文的開頭我們就說過如果return關鍵字和它的返回值之間有換行符的話,JavaScript會自動在return關鍵字之后插入一個分號,此時該return語句的意義就和我們所期望的不同了。
這樣自動插入分號的結果就會讓該示例中的twice()函數實際等同于下面的代碼。此時無論傳遞的參數是多少,return語句都會提前終止函數并默認返回undefined,而變量result始終都不會被返回。
<script>
// 定義一個函數,它和第一個例子中的函數幾乎一樣;
// 只是原本的return語句被拆分成了兩行。
function twice(x) {
var result = x * 2;
return; // 注意,這個分號是JavaScript自動插入的;它改變了程序的語義。
result;
}
</script>
如果你真的想要將return語句寫在多行上,那么你可以將返回值用括號括起來。但請一定要注意,此時左括號也必須要和return關鍵字寫在同一行上,就像下面的代碼這樣:
<script>
/* 要將return語句寫在多行上,可以用括號將返回值括起來;
* 但是,左括號也必須要和return關鍵字寫在同一行上。
*/
function twice(x) {
return (
x * 2
);
}
</script>
(完)
源: AI入門學習
作者:小伍哥
apply()堪稱Pandas中最好用的方法,其使用方式跟map()很像,主要傳入的主要參數都是接受輸入返回輸出。
但相較于昨天介紹的map()針對單列Series進行處理,一條apply()語句可以對單列或多列進行運算,覆蓋非常多的使用場景。
參考上篇:Pandas中的寶藏函數-map
基本語法:
DataFrame.apply(func, axis=0, raw=False, result_type=None,
args=(), **kwargs)
參 數:
func : function 應用到每行或每列的函數。
axis :{0 or 'index', 1 or 'columns'}, default 0 函數應用所沿著的軸。
0 or index : 在每一列上應用函數。
1 or columns : 在每一行上應用函數。
raw : bool, default False 確定行或列以Series還是ndarray對象傳遞。
False : 將每一行或每一列作為一個Series傳遞給函數。
True : 傳遞的函數將接收ndarray 對象。如果你只是應用一個 NumPy 還原函數,這將獲得更好的性能。
result_type : {'expand', 'reduce', 'broadcast', None}, default None 只有在axis=1列時才會發揮作用。
expand : 列表式的結果將被轉化為列。
reduce : 如果可能的話,返回一個Series,而不是展開類似列表的結果。這與 expand 相反。
broadcast : 結果將被廣播到 DataFrame 的原始形狀,原始索引和列將被保留。
默認行為(None)取決于應用函數的返回值:類似列表的結果將作為這些結果的 Series 返回。但是,如果應用函數返回一個 Series ,這些結果將被擴展為列。
args : tuple 除了數組/序列之外,要傳遞給函數的位置參數。
**kwds: 作為關鍵字參數傳遞給函數的附加關鍵字參數。
官方:https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.apply.html
先構造一個數據集
data = pd.DataFrame(
{"name":['Jack', 'Alice', 'Lily', 'Mshis', 'Gdli', 'Agosh', 'Filu', 'Mack', 'Lucy', 'Pony'],
"gender":['F', 'M', 'F', 'F', 'M', 'F', 'M', 'M', 'F', 'F'],
"age":[25, 34, 49, 42, 28, 23, 45, 21, 34, 29]}
)
data
name gender age
0 Jack F 25
1 Alice M 34
2 Lily F 49
3 Mshis F 42
4 Gdli M 28
5 Agosh F 23
6 Filu M 45
7 Mack M 21
8 Lucy F 34
9 Pony F 29
這里我們參照2.1向apply()中傳入lambda函數:
data.gender.apply(lambda x:'女性' if x is 'F' else '男性')
0 女性
1 男性
2 女性
3 女性
4 男性
5 女性
6 男性
7 男性
8 女性
9 女性
可以看到這里實現了跟map()一樣的功能。
apply()最特別的地方在于其可以同時處理多列數據,我們先來了解一下如何處理多列數據輸入單列數據輸出的情況。
譬如這里我們編寫一個使用到多列數據的函數用于拼成對于每一行描述性的話,并在apply()用lambda函數傳遞多個值進編寫好的函數中
注意:當調用DataFrame.apply()時,apply()在串行過程中實際處理的是每一行數據,而不是Series.apply()那樣每次處理單個值,在處理多個值時要給apply()添加參數axis=1
def fun_all(name, gender, age):
gender = '女性' if gender is 'F' else '男性'
return '有個名字叫{}的人,性別為{},年齡為{}。'.format(name, gender, age)
data.apply(lambda row:fun_all(row['name'],row['gender'],row['age']), axis = 1)
0 有個名字叫Jack的人,性別為女性,年齡為25。
1 有個名字叫Alice的人,性別為男性,年齡為34。
2 有個名字叫Lily的人,性別為女性,年齡為49。
3 有個名字叫Mshis的人,性別為女性,年齡為42。
4 有個名字叫Gdli的人,性別為男性,年齡為28。
5 有個名字叫Agosh的人,性別為女性,年齡為23。
6 有個名字叫Filu的人,性別為男性,年齡為45。
7 有個名字叫Mack的人,性別為男性,年齡為21。
8 有個名字叫Lucy的人,性別為女性,年齡為34。
9 有個名字叫Pony的人,性別為女性,年齡為29。
def intro(r):
#r代指dataframe中的任意行,是series類型數據,擁有類似字典的使用方法。
return '大家好,我是{name},性別是{gender},今年{age}歲了!'.format(name=r['name'], gender=r['gender'],age=r['age'])
data.apply(intro, axis=1)
Out[81]:
0 大家好,我是Jack,性別是F,今年25歲了!
1 大家好,我是Alice,性別是M,今年34歲了!
2 大家好,我是Lily,性別是F,今年49歲了!
3 大家好,我是Mshis,性別是F,今年42歲了!
4 大家好,我是Gdli,性別是M,今年28歲了!
5 大家好,我是Agosh,性別是F,今年23歲了!
6 大家好,我是Filu,性別是M,今年45歲了!
7 大家好,我是Mack,性別是M,今年21歲了!
8 大家好,我是Lucy,性別是F,今年34歲了!
9 大家好,我是Pony,性別是F,今年29歲了!
dtype: object
#其實這樣寫也是可以的,更簡單些
def intro(r):
return '大家好,我是{},性別是{},今年{}歲了!'.format(r['name'], r['gender'],r['age'])
data.apply(intro, axis=1)
有些時候我們利用apply()會遇到希望同時輸出多列數據的情況,在apply()中同時輸出多列時實際上返回的是一個Series,這個Series中每個元素是與apply()中傳入函數的返回值順序對應的元組。
比如下面我們利用apply()來提取name列中的首字母和剩余部分字母:
data.apply(lambda row: (row['name'][0], row['name'][1:]), axis=1)
0 (J, ack)
1 (A, lice)
2 (L, ily)
3 (M, shis)
4 (G, dli)
5 (A, gosh)
6 (F, ilu)
7 (M, ack)
8 (L, ucy)
9 (P, ony)
可以看到,這里返回的是單列結果,每個元素是返回值組成的元組,這時若想直接得到各列分開的結果,需要用到zip(*zipped)來解開元組序列,從而得到分離的多列返回值:
a, b = zip(*data.apply(lambda row: (row['name'][0], row['name'][1:]), axis=1))
a
('J', 'A', 'L', 'M', 'G', 'A', 'F', 'M', 'L', 'P')
b
('ack', 'lice', 'ily', 'shis', 'dli', 'gosh', 'ilu', 'ack', 'ucy', 'ony')
我們知道apply()在運算時實際上仍然是一行一行遍歷的方式,因此在計算量很大時如果有一個進度條來監視運行進度就很舒服。
tqdm:用于添加代碼進度條的第三方庫
tqdm對pandas也是有著很好的支持。
我們可以使用progress_apply()代替apply(),并在運行progress_apply()之前添加tqdm.tqdm.pandas(desc='')來啟動對apply過程的監視。
其中desc參數傳入對進度進行說明的字符串,下面我們在上一小部分示例的基礎上進行改造來添加進度條功能:
from tqdm import tqdm
def fun_all(name, gender, age):
gender = '女性' if gender is 'F' else '男性'
return '有個名字叫{}的人,性別為{},年齡為{}。'.format(name, gender, age)
#啟動對緊跟著的apply過程的監視
from tqdm import tqdm
tqdm.pandas(desc='apply')
data.progress_apply(lambda row:fun_all(row['name'],row['gender'],
row['age']), axis = 1)
apply: 100%|██████████| 10/10 [00:00<00:00, 5011.71it/s]
0 有個名字叫Jack的人,性別為女性,年齡為25。
1 有個名字叫Alice的人,性別為男性,年齡為34。
2 有個名字叫Lily的人,性別為女性,年齡為49。
3 有個名字叫Mshis的人,性別為女性,年齡為42。
4 有個名字叫Gdli的人,性別為男性,年齡為28。
5 有個名字叫Agosh的人,性別為女性,年齡為23。
6 有個名字叫Filu的人,性別為男性,年齡為45。
7 有個名字叫Mack的人,性別為男性,年齡為21。
8 有個名字叫Lucy的人,性別為女性,年齡為34。
9 有個名字叫Pony的人,性別為女性,年齡為2
可以看到在jupyter lab中運行程序的過程中,下方出現了監視過程的進度條,這樣就可以實時了解apply過程跑到什么地方了。
結合tqdm_notebook()給apply()過程添加美觀進度條,熟悉tqdm的朋友都知道其針對jupyter notebook開發了ui更加美觀的tqdm_notebook()。而要想在jupyter notebook/jupyter lab平臺上為pandas的apply過程添加美觀進度條,可以參照如下示例:
eturn 定義:
return 語句會 終止函數的執行 并 返回函數的值。
注意這兩個: 1.終止函數的執行 2.返回函數的值
返回函數的值這里就不過多敘述了,就是 return 變量
先看下面的例子:
<!DOCTYPE html> <html> <head> <title>return測試</title> </head> <body> <a href="#"></a> <a onclick="fun1()">111</a> <a onclick="fun2()">222</a> <a onclick="fun3()">333</a> <a onclick="fun4()">444</a> <script type="text/javascript"> function fun1() { return ; console.log('111 這個不會執行') } function fun2() { return false console.log('222 這個不會執行') } function fun3() { return true console.log('333 這個不會執行') } function fun4() { console.log('444 這個會執行') } </script> </body> </html>
通過上面的例子 可以看出 return ; return false return true 在函數內部都中斷了函數的執行
接著看看 他們返回的結果是個啥 代碼如下:
function fun1() { return ; } function fun2() { return false } function fun3() { return true } console.log(fun1()) // undefined console.log(fun2()) // false console.log(fun3()) // true
返回的結果分別是 undefined false true 注:(undefine != false)
有個知識點 : 表單提交的時候 如果函數返回 false 表單就不提交了 ,切記!
首先看看能提交的情況,代碼如下:
<!DOCTYPE html> <html> <head> <title>return測試</title> </head> <body> <form method="post" onsubmit="return submitFunction()"> <input type="text" name="nameId"> <button type="submit" id="submit">提交</button> </form> <script type="text/javascript"> function submitFunction () { return ; } </script> </body> </html>
效果如下: 右邊出現了請求(注意:表單請求會刷新頁面)
阻止表單提交的代碼如下:
<!DOCTYPE html> <html> <head> <title>return測試</title> </head> <body> <form method="post" onsubmit="return submitFunction()"> <input type="text" name="nameId"> <button type="submit" id="submit">提交</button> </form> <script type="text/javascript"> function submitFunction () { return false; } </script> </body> </html>
效果如下:右邊沒有出現請求,請求被阻止了
總結如下:
1. return ; return false return true 都會在函數內部阻止程序的執行。
2. 只有 return false 會阻止表單的提交。
對前端的技術,架構技術感興趣的同學關注我的頭條號,并在后臺私信發送關鍵字:“前端”即可獲取免費的架構師學習資料
知識體系已整理好,歡迎免費領取。還有面試視頻分享可以免費獲取。關注我,可以獲得沒有的架構經驗哦!!
*請認真填寫需求信息,我們會在24小時內與您取得聯系。