国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

腳本之家,腳本語言編程技術及教程分享平臺!
分類導航

Python|VBS|Ruby|Lua|perl|VBA|Golang|PowerShell|Erlang|autoit|Dos|bat|

服務器之家 - 腳本之家 - Python - python黑魔法之參數傳遞

python黑魔法之參數傳遞

2020-08-12 09:15icedoom Python

這篇文章主要介紹了python黑魔法之參數傳遞,分析了python參數傳遞的方法,感興趣的小伙伴們可以參考一下

我們都聽說,python世界里面,萬物皆對象。
怎么說萬物皆對象呢?最常見的:

?
1
2
> class A: pass
> a = A()

我們說a是一個對象。
那么既然是萬物了,其實A也是對象。3 也是對象。True 也是對象。"hello" 也是對象。
> def Func(): pass
o~yee, Func 也是對象。
那么對象之間的傳遞是如何呢?我們看看下面兩個簡單的例子:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
> a = 3
> b = a
> b = 3 + 1
> print b
4
> print a
3
 
> a = []
> b = a
> b.append(1)
 
> print a
[1]
> print b
[1]

不是都說python所有對象都是引用傳遞嗎?為毛第一個b不是3?
好吧。事實是,在python的實現上,對象分為mutable 和 immutable。
這里說的對象分類,是說在實現上具備這樣的特性。而非對象本身的屬性。
什么是immutable?表示對象本身不可改變。這里先記住一點,是對象 本身 不可改變。
什么叫做對象本身不可改變呢?
一個簡單的例子:

?
1
2
> a = (1,2,3)
> a[0] = 10

TypeError: 'tuple' object does not support item assignment
元組的元素在初始化后就不能再被改變。也就是說,元組對象具備immutable的特性。
那么很簡單,相對的,mutable 就是可變的。比如:

?
1
2
> a = {}
> a[0] = 10

有了上面的兩個例子,相信大家已經有了基本的認識。
那么,在python世界中,哪些是具備immutable特性,哪些又是mutable的呢?
簡單講,基本類型都是immutable, 而object都是mutable的。
比如說:int, float, bool, tuple 都是immutable。
再比如:dict, set, list, classinstance 都是mutable的。
那么問題來了。既然說基本類型是 immutable ,那么最上面的 b = 3 + 1 為什么不會像tuple一樣,拋異常呢?
原因在于,int 對+操作會執行自己的__add__方法。而__add__方法會返回一個新的對象。
事實是,當基本類型被改變時,并不是改變其自身,而是創建了一個新的對象。最終返回的是新的對象的引用。
怎么證明?
我們可以使用一個叫做id()的函數。該函數會返回對象的一個唯一id(目前的實現可以間接理解為對象的內存地址)。
那么我們看下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
> a = 3
> id(a)
140248135804168
 
> id(3)
140248135804168
 
> id(4)
140248135804144
 
> a = a + 1
> id(a)
140248135804144

you see ? 當我們執行a=a+1 后,id(a) 已經改變了。
深究一點,為什么會這樣呢?
其實,a = a + 1 經歷了兩個過程:

  • 1、a + 1
  • 2、a 賦值

第2步只是一個引用的改變。重點在第1步。a + 1,那么python實際上會調用a.__add__(1)。
對于int類型__add__函數的實現邏輯,是創建了一個新的int對象,并返回。
不知道細心的你有沒有發現一個特別的地方?
id(4)的值等于id(3+1) 。這個只是python對int,和bool做的特殊優化。不要以為其他基本類型只要值一樣都會指向相同的對象。
有個特殊的例子,str。做個簡單的實驗:

?
1
2
3
4
5
6
7
8
9
10
11
> a = "hello"
> id(a)
4365413232
> b = "hell"
> id(b)
4365386208
 
> id(a[:-1])
4365410928
> id(a[:-1])
4365413760

看到了嗎?雖然值相同,但是還是指向(創建)了不同的對象,尤其是最后兩句,哪怕執行相同的操作,依然創建了不同的對象。
python這么傻,每次都創建新的對象?
no no no 他只是緩存了“一些”結果。我們可以再試試看:

?
1
2
3
4
5
6
> a = "hello"
> ret = set()
> for i in range(1000):
  ret.add(id(a[:-1]))
> print ret
{4388133312, 4388204640}

看到了嗎?python還是挺聰明的。不過具體的緩存機制我沒有深究過,期望有同學能分享下。
再次回到我們的主題,python中參數是如何傳遞的?
答案是,引用傳遞。
平時使用靜態語言的同學(比如我),可能會用下面的例子挑戰我了:

?
1
2
3
4
5
6
7
def fun(data):
  data = 3
 
a = 100
func(a)
 
print a # 100

不是尼瑪引用傳遞嗎?為毛在執行func(a)后,a 的值沒有改變呢?這里犯了一個動態語言基本的錯誤。
data=3,語義上是動態語言的賦值語句。千萬不要和C++之類的語言一個理解。
看看我們傳入一個mutable 的對象:

?
1
2
3
4
5
6
7
8
9
> def func(m):
  m[3] = 100
 
> a = {}
> print a
{}
> func(a)
> print a
{3:100}

現在同學們知道該如何進行參數傳遞了吧?好嘞,進階!
像很多語言如C++,js,swift... 一樣,python 的函數聲明支持默認參數:
def func(a=[]): pass
不知道什么意思?自己看書去!
我這里要說的是,如果我們的默認參數是mutable類型的對象,會有什么黑魔法產產生?
我們看看下面的函數:

?
1
2
3
def func(a=[]):
  a.append(3)
  return a

可能有同學會說了:我去!這么簡單?來騙代碼的吧?
但是,真的這么簡單嗎?我們看下下面的調用結果:

?
1
2
3
4
5
6
> print func()
[3]
> print func()
[3,3]
> print func()
[3,3,3]

這真的是你想要的結果嗎?
No,我要的是[3],[3],[3]!
原因?好吧,我們再用下id()神奇看看:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
def func(a=[]):
  print id(a)
  a.append(3)
  return a
 
> print func()
4365426272
[3]
> print func()
4365426272
[3, 3]
> print func()
4365426272
[3, 3, 3]

明白沒?原來在python中,*默認參數不是每次執行時都創建的!*
這下你再想想,曾經嘲笑過的代碼(至少我)為什么要 多此一舉:

?
1
2
3
def func(a=None):
  if a is None:
    a = []

這里在順帶提一下==, is:
== : 值比較
is : 比較左右兩邊是否是同一個對象。 a is b ==> id(a) == id(b)
ok, let's move on!
我們都知道,在python中,不定參數我們可以這樣定義:
def func(*args, **kv): pass
什么你不知道?看書去!
那args和kv到底是什么情況呢?到底是mutable 還是 immutable 呢?
再一次請出id()神器:

?
1
2
3
4
5
6
7
8
9
10
11
def func(*args):
  print id(args)
 
 
> a = [1,2]
> print id(a)
4364874816
> func(*a)
4364698832
> func(*a)
4364701496

看到了吧?實際上args也會產生一個新的對象。但是值是填入的傳入參數。那么每一個item也會復制嗎?
我們再看看:

?
1
2
3
4
5
6
7
8
def func(*args):
  print id(args[0])
 
> a = [1,2]
> print id(a[0])
140248135804216
> func(*a)
140248135804216

答案是,No。值會像普通list賦值一樣,指向原先list(a)所引用的對象。
那么為什么會這樣呢?
python的源碼就是這么寫的.......
最最后,還記得我說過的一句話嗎?
immutable 限制的是對象本身不可變
意思就是說,對象的immtable 只是限制自身的屬性能否被改變,而不會影響到其引用的對象。
看下下面的例子:

?
1
2
3
4
5
6
7
8
9
10
> a = [1,2]
> b = (a,3)
> b[1] = 100
TypeError: 'tuple' object does not support item assignment
 
> print b
([1, 2], 3)
> b[0][0] = 10
> print b
([10, 2], 3)

最最最后,我有個對象,它本身應該是 mutable 的,但是我想讓他具備類似immutable的特性,可以嗎?
答案是,可以模擬!
還是之前說的,immutable 限制的是其自身屬性不能改變。
那么,我們的可以通過重定義(重載)屬性改變函數,來模擬immutable特性。
python可以嗎?O~Yee
在python的類函數中,有這樣的兩個函數: __setattr__ 和 __delattr__。分別會在對象屬性賦值和刪除時執行。
那么我們可以進行簡單重載來模擬immutable:

?
1
2
3
class A:
  def __setattr__(self, name, val):
    raise TypeError("immutable object could not set attr")

以上就是為大家介紹的python黑魔法,希望對大家的學習有所幫助。

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 欧美精品一二三区 | 可以免费看黄色的网站 | 精品亚洲永久免费精品 | 国产色区| 一区二区三区成人 | 欧美国产精品一区 | 在线观看成人av | 日本在线免费 | 在线观看亚洲a | 国产精品久久久久久久久久久久久 | 天天操天天干天天爽 | 99久久精品国产一区二区三区 | 国产福利电影一区 | 黄色美女视频网站 | 中文字幕啪啪 | 国产精品久久久久久久久软件 | 91精品国产综合久久婷婷香蕉 | 国产成人精品久久二区二区 | 国产剧情一区二区 | 亚洲精品专区 | 精品久久久久久久久久 | 在线观看av网站 | 日韩精品在线一区二区 | 精品国产凹凸成av人导航 | 国产中文字幕在线观看 | av在线播放网站 | 亚洲欧美激情视频 | 精品国产乱码久久久久久牛牛 | 久久久精品一区二区 | 香港黄色录像片 | 欧美在线免费观看 | 国产欧美日韩综合精品一区二区 | 久久精品在线 | 亚洲午夜成激人情在线影院 | 欧美久久久 | 国产精选一区二区三区不卡催乳 | 成人小视频在线观看 | 欧美日韩一区二区在线 | 亚洲欧美视频播放 | 国产精品久久久久一区二区三区 | 一区二区三区四区在线 |