小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

Python 和 JS 有什么相似?

 達(dá)坂城大豆 2017-11-21

作者:牧云云

來源:http:///posts/a9d08041/

Python 是一門運(yùn)用很廣泛的語(yǔ)言,自動(dòng)化腳本、爬蟲,甚至在深度學(xué)習(xí)領(lǐng)域也都有 Python 的身影。作為一名前端開發(fā)者,也了解 ES6 中的很多特性借鑒自 Python (比如默認(rèn)參數(shù)、解構(gòu)賦值、Decorator等),同時(shí)本文會(huì)對(duì) Python 的一些用法與 JS 進(jìn)行類比。不管是提升自己的知識(shí)廣度,還是更好地迎接 AI 時(shí)代,Python 都是一門值得學(xué)習(xí)的語(yǔ)言。

數(shù)據(jù)類型

在 Python 中,最常用的能夠直接處理的數(shù)據(jù)類型有以下幾種:

  • 數(shù)字[整數(shù)(int)、浮點(diǎn)型(float)、長(zhǎng)整型(long)、復(fù)數(shù)(complex)]

  • 字符串(str)

  • 布爾值(bool)

  • 空值(None)

除此之外,Python 還提供了列表[list]、字典[dict] 等多種數(shù)據(jù)類型,這在下文中會(huì)介紹。

類型轉(zhuǎn)換與類型判斷

與 JS 十分類似,python 也能實(shí)現(xiàn)不同數(shù)據(jù)類型間的強(qiáng)制與隱式轉(zhuǎn)換,例子如下:

強(qiáng)制類型轉(zhuǎn)換:

  1. int('3') # 3

  2. str(3.14) # '3.14'

  3. float('3.14') # 3.14

  4. # 區(qū)別于 JS 只有 Number 一種類型,Python 中數(shù)字中的不同類型也能相互強(qiáng)制轉(zhuǎn)換

  5. float(3) # 3.0

  6. bool(3) # True

  7. bool(0) # False

隱式類型轉(zhuǎn)換:

  1. 1 + 1.0 # 2.0

  2. 1 + False # 1

  3. 1.0 + True # 2.0

  4. # 區(qū)別于 JS 的 String + Number = String, py 中 str + int 會(huì)報(bào)錯(cuò)

  5. 1 + '1' # TypeError: cannot concatenate 'str' and 'int' objects

此外寫代碼的時(shí)候經(jīng)常會(huì)需要判斷值的類型,可以 使用 python 提供的 type() 函數(shù)獲取變量的類型,或者使用 isinstance(x, type) 來判斷 x 是否屬于相應(yīng)的 type 類型。

  1. type(1.3) == float # True

  2. isinstance('a', str) # True

  3. isinstance(1.3, int) # False

  4. isinstance(True, bool) # True

  5. isinstance([], list) # True

  6. isinstance({}, dict) # True

有序集合類型

集合是指包含一組元素的數(shù)據(jù)結(jié)構(gòu),有序集合即集合里面的元素是是按照順序排列的,Python 中的有序集合大概有以下幾類:list, tuple, str, unicode。

list 類型

Python 中 List 類型類似于 JS 中的 Array,

  1. L = [1, 2, 3]

  2. print L[-1] # '3'

  3. L.append(4) # 末尾添加元素

  4. print L # [1, 2, 3, 4]

  5. L.insert(0, 'hi') # 指定索引位置添加元素

  6. print L # ['hi', 1, 2, 3, 4]

  7. L.pop() # 末尾移除元素 L.pop(2) ?????? 2 ???

  8. print L # ['hi', 1, 2, 3]

tuple 類型

tuple 類型是另一種有序的列表,中文翻譯為' 元組 '。tuple 和 list 非常類似,但是,tuple 一旦創(chuàng)建完畢,就不能修改了。

  1. t = (1, 2, 3)

  2. print t[0] # 1

  3. t[0] = 11 # TypeError: 'tuple' object does not support item assignment

  4. t = (1)

  5. print t # 1  t 的結(jié)果是整數(shù) 1

  6. t = (1,) # 為了避免出現(xiàn)如上有歧義的單元素 tuple,所以 Python 規(guī)定,單元素 tuple 要多加一個(gè)逗號(hào)','

  7. print t # (1,)

無序集合類型

dict 類型

Python 中的 dict 類型類似于 JS 中的 {} (最大的不同是它是沒有順序的), 它有如下特點(diǎn):

  • 查找速度快 (無論 dict 有 10 個(gè)元素還是 10 萬(wàn)個(gè)元素,查找速度都一樣)

  • 占用內(nèi)存大 (與 list 類型相反)

  • dict 中的 key 不能重復(fù)

  • dict 中存儲(chǔ)的 key-value 序?qū)κ菦]有順序的

  1. d = {

  2.    'a': 1,

  3.    'b': 2,

  4.    'c': 3

  5. }

  6. print d # {'a': 1, 'c': 3, 'b': 2}  可以看出打印出的序?qū)]有按正常的順序打出

  7. # 遍歷 dict

  8. for key,value in d.items():

  9.    print('%s: %s' % (key,value))

  10. # a: 1

  11. # c: 3

  12. # b: 2

set 類型

有的時(shí)候,我們只想要 dict 的 key,不關(guān)心 key 對(duì)應(yīng)的 value,而且要保證這個(gè)集合的元素不會(huì)重復(fù),這時(shí),set 類型就派上用場(chǎng)了。set 類型有如下特點(diǎn):

  • set 存儲(chǔ)的元素和 dict 的 key 類似,必須是不變對(duì)象

  • set 存儲(chǔ)的元素也是沒有順序的

  1. s = set(['A', 'B', 'C', 'C'])

  2. print s # set(['A', 'C', 'B'])

  3. s.add('D')

  4. print s # set(['A', 'C', 'B', 'D'])

  5. s.remove('D')

  6. print s # set(['A', 'C', 'B'])

Python 中的迭代

在介紹完 Python 中的有序集合和無序集合類型后,必然存在遍歷集合的 for 循環(huán)。但是和其它語(yǔ)言的標(biāo)準(zhǔn) for 循環(huán)不同,Python 中的所有迭代是通過 for ... in 來完成的。以下給出一些常用的迭代 demos:

索引迭代:

  1. L = ['apple', 'banana', 'orange']

  2. for index, name in enumerate(L):  # enumerate() 函數(shù)把 ['apple', 'banana', 'orange'] 變成了類似 [(0, 'apple), (1, 'banana'), (2, 'orange')] 的形式

  3.    print index, '-', name

  4. # 0 - apple

  5. # 1 - banana

  6. # 2 - orange

迭代 dict 的 value:

  1. d = { 'apple': 6, 'banana': 8, 'orange': 5 }

  2. print d.values() # [6, 8, 5]

  3. for v in d.values()

  4.    print v

  5. # 6

  6. # 8

  7. # 5

迭代 dict 的 key 和 value:

  1. d = { 'apple': 6, 'banana': 8, 'orange': 5 }

  2. for key, value in d.items()

  3.    print key, ':', value

  4. # apple : 6

  5. # banana: 8

  6. # orange: 5

切片操作符

Python 提供的切片操作符類似于 JS 提供的原生函數(shù) slice()。有了切片操作符,大大簡(jiǎn)化了一些原來得用循環(huán)的操作。

  1. L = ['apple', 'banana', 'orange', 'pear']

  2. L[0:2] # ['apple', 'banana'] 取前 2 個(gè)元素

  3. L[:2] # ['apple', 'banana'] 如果第一個(gè)索引是 0,可以省略

  4. L[:] # ['apple', 'banana', 'orange', 'pear'] 只用一個(gè) : ,表示從頭到尾

  5. L[::2] # ['apple', 'orange'] 第三個(gè)參數(shù)表示每 N 個(gè)取一個(gè),這里表示從頭開始,每 2 個(gè)元素取出一個(gè)來

列表生成器

如果要生成 [1x1, 2x2, 3x3, ..., 10x10] 怎么做?方法一是循環(huán):

  1. L = []

  2. for x in range(1, 11):

  3.    L.append(x * x)

但是循環(huán)太繁瑣,而列表生成式則可以用一行語(yǔ)句代替循環(huán)生成上面的 list:

  1. # 把要生成的元素 x * x 放到前面,后面跟 for 循環(huán),就可以把 list 創(chuàng)建出來

  2. [x * x for x in range(1, 11)]

  3. # [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

列表生成式的 for 循環(huán)后面還可以加上 if 判斷(類似于 JS 中的 filter() 函數(shù)),示例如下:

  1. [x * x for x in range(1, 11) if x % 2 == 0]

  2. # [4, 16, 36, 64, 100]

for 循環(huán)可以嵌套,因此,在列表生成式中,也可以用多層 for 循環(huán)來生成列表。

  1. [m + n for m in 'ABC' for n in '123']

  2. # ['A1', 'A2', 'A3', 'B1', 'B2', 'B3', 'C1', 'C2', 'C3']

Python 函數(shù)

默認(rèn)參數(shù)

JS 中 ES6 的 默認(rèn)參數(shù)正是借鑒于 Python,用法如下:

  1. def greet(name='World'):

  2.    print 'Hello, ' + name + '.'

  3. greet() # Hello, World.

  4. greet('Python') # Hello, Python.

可變參數(shù)

類似于 JS 函數(shù)中自動(dòng)識(shí)別傳入?yún)?shù)的個(gè)數(shù),Python 也提供了定義可變參數(shù),即在可變參數(shù)的名字前面帶上個(gè) * 號(hào)。

  1. def fn(*args):

  2.    print args

  3. fn()  # ()

  4. fn('a') # ('a',)

  5. fn('a', 'b') # ('a', 'b')

Python 解釋器會(huì)把傳入的一組參數(shù)組裝成一個(gè) tuple 傳遞給可變參數(shù),因此,在函數(shù)內(nèi)部,直接把變量 args 看成一個(gè) tuple 就好了。

常用高階函數(shù)

Python 中常用的函數(shù) (map、reduce、filter) 的作用和 JS 中一致,只是用法稍微不同。

  • map 函數(shù): 接收一個(gè)函數(shù) f 和一個(gè) list,并通過把函數(shù) f 依次作用在 list 的每個(gè)元素上,得到一個(gè)新的 list 并返回。

  1. def f(x):

  2.    return x * x

  3. print map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9]) # [1, 4, 9, 16, 25, 36, 49, 64, 81]

  • reduce 函數(shù): 接收一個(gè)函數(shù) f 和一個(gè) list(可以接受第三個(gè)值作為初始值),reduce() 對(duì) list 的每個(gè)元素反復(fù)調(diào)用函數(shù) f,并返回最終結(jié)果值。

  1. def f(x, y):

  2.    return x * y

  3. reduce(f, [1, 3, 5]) # 15

  • filter 函數(shù): 接收一個(gè)函數(shù) f 和一個(gè)list,這個(gè)函數(shù) f 的作用是對(duì)每個(gè)元素進(jìn)行判斷,返回 True或 False,filter() 根據(jù)判斷結(jié)果自動(dòng)過濾掉不符合條件的元素,返回由符合條件元素組成的新 list。

  1. def is_odd(x):

  2.    return x % 2 == 1

  3. filter(is_odd, [1, 4, 6, 7, 9, 12, 17]) # [1, 7, 9, 17]

匿名函數(shù)

和 JS 的匿名函數(shù)不同的地方是,Python 的匿名函數(shù)中只能有一個(gè)表達(dá)式,且不能寫 return。拿 map() 函數(shù)為例:

  1. map(lambda x: x * x, [1, 2, 3, 4, 5, 6, 7, 8, 9]) # [1, 4, 9, 16, 25, 36, 49, 64, 81]

關(guān)鍵詞 lambda 表示匿名函數(shù),冒號(hào)前面的 x 表示函數(shù)參數(shù),可以看出匿名函數(shù) lambda x: x* x實(shí)際上就是:

  1. def f(x):

  2.    return x * x

閉包

之前寫過一些關(guān)于 JS 閉包的文章,比如 深入淺出JavaScript之閉包(Closure)、以及 讀書筆記-你不知道的 JavaScript (上),Python 中閉包的定義和 JS 中的是一致的即:內(nèi)層函數(shù)引用了外層函數(shù)的變量,然后返回內(nèi)層函數(shù)。下面來看下 Py 中閉包之 for 循環(huán)經(jīng)典問題:

  1. # 希望一次返回3個(gè)函數(shù),分別計(jì)算1x1,2x2,3x3:

  2. def count():

  3.    fs = []

  4.    for i in range(1, 4):

  5.        def f():

  6.            return i * i

  7.        fs.append(f)

  8.    return fs

  9. f1, f2, f3 = count() # 這種寫法相當(dāng)于 ES6 中的解構(gòu)賦值

  10. print f1(), f2(), f3() # 9 9 9

老問題了,f1(), f2(), f3() 結(jié)果不應(yīng)該是 1, 4, 9 嗎,實(shí)際結(jié)果為什么都是 9 呢?

原因就是當(dāng) count() 函數(shù)返回了 3 個(gè)函數(shù)時(shí),這 3 個(gè)函數(shù)所引用的變量 i 的值已經(jīng)變成了 3。由于 f1、f2、f3 并沒有被調(diào)用,所以,此時(shí)他們并未計(jì)算 i*i,當(dāng) f1 被調(diào)用時(shí),i 已經(jīng)變?yōu)?3 了。

要正確使用閉包,就要確保引用的局部變量在函數(shù)返回后不能變。代碼修改如下:

方法一: 可以理解為創(chuàng)建了一個(gè)封閉的作用域,i 的 值傳給 j 之后,就和 i 沒任何關(guān)系了。每次循環(huán)形成的閉包都存進(jìn)了內(nèi)存中。

  1. def count():

  2.    fs = []

  3.    for i in range(1, 4):

  4.        def f(j):

  5.            def g(): # 方法一

  6.                return j * j

  7.            return g

  8.        r = f(i)

  9.        fs.append(r)

  10.    return fs

  11. f1, f2, f3 = count()

  12. print f1(), f2(), f3() # 1 4 9

方法二:思路比較巧妙,用到了默認(rèn)參數(shù) j 在函數(shù)定義時(shí)可以獲取到 i 的值,雖然沒有用到閉包,但是和方法一有異曲同工之處。

  1. def count():

  2.    fs = []

  3.    for i in range(1, 4):

  4.        def f(j = i): # 方法二

  5.            return j * j

  6.        fs.append(f)

  7.    return fs

  8. f1, f2, f3 = count()

  9. print f1(), f2(), f3() # 1 4 9

decorator 裝飾器

ES6 的語(yǔ)法中的 decorator 正是借鑒了 Python 的 decorator。decorator 本質(zhì)上就是 一個(gè)高階函數(shù),它接收一個(gè)函數(shù)作為參數(shù),然后返回一個(gè)新函數(shù)。

那裝飾器的作用在哪呢?先上一段日常項(xiàng)目中用 ts 寫的網(wǎng)關(guān)代碼:

  1. @Post('/rider/detail')  // URL 路由

  2. @log()                   // 打印日志

  3.  @ResponseBody

  4.  public async getRiderBasicInfo(

  5.    @RequestBody('riderId') riderId: number,

  6.    @RequestBody('cityId') cityId: number,

  7.  ) {

  8.    const result = await this.riderManager.findDetail(cityId, riderId)

  9.    return result

  10.  }

可以看出使用裝飾器可以極大地簡(jiǎn)化代碼,避免每個(gè)函數(shù)(比如日志、路由、性能檢測(cè))編寫重復(fù)性代碼。

回到 Python 上,Python 提供的 @ 語(yǔ)法來使用 decorator, @ 等價(jià)于 f = decorate(f)。下面來看看 @log() 在 Python 中的實(shí)現(xiàn):

  1. # 我們想把調(diào)用的函數(shù)名字給打印出來

  2. @log()

  3. def factorial(n):

  4.    return reduce(lambda x,y: x*y, range(1, n+1))

  5. print factorial(10)

  6. # 來看看 @log() 的定義

  7. def log():

  8.    def log_decorator(f):

  9.        def fn(x):

  10.            print '調(diào)用了函數(shù)' + f.__name__ + '()'

  11.            return f(x)

  12.        return fn

  13.    return log_decorator

  14. # 結(jié)果

  15. # 調(diào)用了函數(shù) factorial()

  16. # 3628800

class

面向?qū)ο缶幊?/h4>

面向?qū)ο缶幊淌且环N程序設(shè)計(jì)范式,基本思想是:用類定義抽象類型,然后根據(jù)類的定義創(chuàng)建出實(shí)例。在掌握其它語(yǔ)言的基礎(chǔ)上,還是比較容易理解這塊知識(shí)點(diǎn)的,比如從下面兩種寫法可以看出不同語(yǔ)言的語(yǔ)言特性間竟然有如此多的共性。

es6: (附:本文的主題是 python,所以只是初略展示下 js 中類的定義以及實(shí)例的創(chuàng)建,為了說明寫法的相似性)

  1. class Person {

  2.    constructor(name, age) {

  3.        this.name = name

  4.        this.age = age

  5.    }

  6. }

  7. const child1 = new Person('Xiao Ming', 10)

Python: (核心要點(diǎn)寫在注釋中)

  1. # 定義一個(gè) Person 類:根據(jù) Person 類就可以造成很多 child 實(shí)例

  2. class Person(object):

  3.    address = 'Earth' # 類屬性 (實(shí)例公有)

  4.    def __init__(self, name, age): # 創(chuàng)建實(shí)例時(shí),__init__()方法被自動(dòng)調(diào)用

  5.        self.name = name

  6.        self.age = age

  7.    def get_age(self): # 定義實(shí)例方法,它的第一個(gè)參數(shù)永遠(yuǎn)是 self,指向調(diào)用該方法的實(shí)例本身,其他參數(shù)和普通函數(shù)是一樣的

  8.        return self.age

  9. child1 = Person('Xiao Ming', 10)

  10. child2 = Person('Xiao Hong', 9)

  11. print child1.name # 'Xiao Ming'

  12. print child2.get_age() # 9

  13. print child1.address # 'Earth'

  14. print child2.address # 'Earth'

繼承

child 屬于 Student 類,Student 類屬于 People 類,這就引出了繼承: 即獲得了父類的方法屬性后又能添加自己的方法屬性。

  1. class Person(object):

  2.    def __init__(self, name, age):

  3.        self.name = name

  4.        self.age = age

  5. class Student(Person):

  6.    def __init__(self, name, age, grade):

  7.        super(Student, self).__init__(name, age) # 這里也能寫出 Person.__init__(self, name, age)

  8.        self.grade = grade

  9. s = Student('Xiao Ming', 10, 90)

  10. print s.name # 'Xiao Ming'

  11. print s.grade # 90

可以看到子類在父類的基礎(chǔ)上又增加了 grade 屬性。我們可以再來看看 s 的類型。

  1. isinstance(s, Person)

  2. isinstance(s, Student)

可以看出,Python 中在一條繼承鏈上,一個(gè)實(shí)例可以看成它本身的類型,也可以看成它父類的類型。


題圖:pexels,CC0 授權(quán)。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多