python基礎知識及應用(三)垃圾回收|迭代器與生成器| lambda表達式|多線程| zip | del

  • python的垃圾回收是什麼 ?
  • python的迭代器是什麼?
  • python 的return與yeild的區別?
  • python的全局變量調用順序?
  • python的lambda表達式是什麼?怎麼寫?
  • python的多線程與多進程是怎麼回事?

目錄

一、垃圾回收

1.1 垃圾回收

1.2 整數對象池及intern

1.3 引用計數

二、python迭代器與生成器

2.1 迭代器

2.2 生成器

三、lambda表達式

3.1 使用

3.2 編寫跳轉表(jump table)行爲的列表或者字典

四、python的多線程

4.1 進程與線程

4.2 創建線程

五、python的zip函數

六、__del__:

6.1 del作用

6.2 程序及結果

七、上面問題及答案


一、垃圾回收

1.1 垃圾回收

一些程序中,會出現內存泄露的問題。比如c++的malloc之後忘記了free。

內存泄漏沒有將相應的內存釋放給操作系統,導致無用內存越來越多。

所以一些語言引入了垃圾回收機制,例如ruby和java,python等

1.2 整數對象池及intern

https://www.cnblogs.com/alexzhang92/p/9416692.html

整數對象池

  • 小整數對象池,數值範圍是[-5, 257],在一個 Python 的程序中,所有位於這個範圍內的整數使用的都是同一個對象.
  • 大整數對象池:大整數均創建一個對象。

intern機制

幾個相同的變量,例如下面:

a1 = "HelloWorld"
a2 = "HelloWorld"
a3 = "HelloWorld"
a4 = "HelloWorld"
a5 = "HelloWorld"
a6 = "HelloWorld"
a7 = "HelloWorld"
a8 = "HelloWorld"
a9 = "HelloWorld"

只有9個,但是用下面

print(sys.getrefcount(a1))會輸出12,不知是什麼原因

intern機制

  • 讓他只佔用一個”HelloWorld”所佔的內存空間。靠引用計數去維護何時釋放。

1.3 引用計數

通過引用計數可以實現循環引用。

  • 每個對象有新的引用的時候,其引用計數會增加,刪除的時候,引用計數會減少。
  • 當引用計數爲0的時候,內存釋放。
  • 優點:簡單,實時性。實時性還帶來一個好處:處理回收內存的時間分攤到了平時。

導致引用計數+1的情況

  •     對象被創建,例如a=23
  •     對象被引用,例如b=a
  •     對象被作爲參數,傳入到一個函數中,例如func(a)
  •     對象作爲一個元素,存儲在容器中,例如list1=[a,a]

導致引用計數-1的情況

  •     對象的別名被顯式銷燬,例如del a
  •     對象的別名被賦予新的對象,例如a=24
  •     一個對象離開它的作用域,例如f函數執行完畢時,func函數中的局部變量(全局變量不會)
  • 對象所在的容器被銷燬,或從容器中刪除對象

查看一個對象的引用計數

import sys
a = "hello world"
sys.getrefcount(a)
#輸出是4

可以查看a對象的引用計數,但是比正常計數大1,因爲調用函數的時候傳入a,這會讓a的引用計數+1

循環引用會導致內存泄漏:

list1 = []
list2 = []
list1.append(list2)
list2.append(list1)

二、python迭代器與生成器

https://www.runoob.com/python3/python3-iterator-generator.html

2.1 迭代器

迭代是Python最強大的功能之一,是訪問集合元素的一種方式。

  • 迭代器是一個可以記住遍歷的位置的對象。
  • 迭代器對象從集合的第一個元素開始訪問,直到所有的元素被訪問完結束。迭代器只能往前不會後退。
  • 迭代器有兩個基本的方法:iter()next(),StopIteration
  • 字符串,列表或元組對象都可用於創建迭代器
#!/usr/bin/python3
list=[1,2,3,4]
it = iter(list)    # 創建迭代器對象
for x in it:
    print (x, end=" ")

運行結果:

1 2 3 4

2.2 生成器

在 Python 中,使用了 yield 的函數被稱爲生成器(generator)。

  • 跟普通函數不同的是,生成器是一個返回迭代器的函數,只能用於迭代操作,更簡單點理解生成器就是一個迭代器。
  • 在調用生成器運行的過程中,每次遇到 yield 時函數會暫停並保存當前所有的運行信息,返回 yield 的值, 並在下一次執行 next() 方法時從當前位置繼續運行。
  • 調用一個生成器函數,返回的是一個迭代器對象。
import sys
 
def fibonacci(n): # 生成器函數 - 斐波那契
    a, b, counter = 0, 1, 0
    while True:
        if (counter > n): 
            return
        yield a
        a, b = b, a + b
        counter += 1
f = fibonacci(10) # f 是一個迭代器,由生成器返回生成
 
while True:
    try:
        print (next(f), end=" ")
    except StopIteration:
        sys.exit()

輸出:

0 1 1 2 3 5 8 13 21 34 55

三、lambda表達式

https://www.cnblogs.com/mxh1099/p/5386529.html

lambda的一般形式是關鍵字lambda後面跟一個或多個參數,緊跟一個冒號,以後是一個表達式。

  • lambda是一個表達式而不是一個語句。
  • 它能夠出現在Python語法不允許def出現的地方。
  • 作爲表達式,lambda返回一個值(即一個新的函數)。
  • lambda用來編寫簡單的函數,而def用來處理更強大的任務。

3.1 使用

f = lambda x, y, z :x+y+z
print(f(1,2,3)) #6

輸出:6

3.2 編寫跳轉表(jump table)行爲的列表或者字典

L = [lambda x: x+2, lambda x: x*2, lambda x: x**2]
print("L=", L[0](1), L[1](2), L[2](3))
# L= 3 4 9
D = {"d1": lambda x: x**1, "d2": lambda x: x**2, "d3": lambda x: x**3 }
print("D=", D["d1"](2), D["d2"](2), D["d3"](2))
# D= 2 4 8

四、python的多線程

4.1 進程與線程

線程在執行過程中與進程還是有區別的。

  • 每個獨立的進程有一個程序運行的入口、順序執行序列和程序的出口。
  • 線程不能夠獨立執行,必須依存在應用程序中,由應用程序提供多個線程執行控制。
  • 每個線程都有他自己的一組CPU寄存器,稱爲線程的上下文,該上下文反映了線程上次運行該線程的CPU寄存器的狀態。
  • 指令指針和堆棧指針寄存器是線程上下文中兩個最重要的寄存器,線程總是在進程得到上下文中運行的,這些地址都用於標誌擁有線程的進程地址空間中的內存。
  • 線程可以被搶佔(中斷)。
  • 在其他線程正在運行時,線程可以暫時擱置(也稱爲睡眠) -- 這就是線程的退讓。

4.2 創建線程

Python中使用線程有兩種方式:函數或者用類來包裝線程對象。

函數式:調用thread模塊中的start_new_thread()函數來產生新線程。語法如下:

thread.start_new_thread ( function, args[, kwargs] )

參數說明:

  •     function - 線程函數。
  •     args - 傳遞給線程函數的參數,他必須是個tuple類型。
  •     kwargs - 可選參數。
import thread
import time
# 爲線程定義一個函數
def print_time( threadName, delay):
   count = 0
   while count < 5:
      time.sleep(delay)
      count += 1
      print "%s: %s" % ( threadName, time.ctime(time.time()) )
 
# 創建兩個線程
try:
   thread.start_new_thread( print_time, ("Thread-1", 2, ) )
   thread.start_new_thread( print_time, ("Thread-2", 4, ) )
except:
   print "Error: unable to start thread"
 
while 1:
   pass

五、pythonzip函數

zip() 函數用於將可迭代的對象作爲參數,將對象中對應的元素打包成一個個元組,然後返回由這些元組組成的列表。

注意:

  • 一 一對應的返回
  • 只返回最小的list的個數
>>>a = [1,2,3]
>>> b = [4,5,6]
>>> c = [4,5,6,7,8]
>>> zipped = zip(a,b)     # 打包爲元組的列表
[(1, 4), (2, 5), (3, 6)]
>>> zip(a,c)              # 元素個數與最短的列表一致
[(1, 4), (2, 5), (3, 6)]
>>> zip(*zipped)          # 與 zip 相反,*zipped 可理解爲解壓,返回二維矩陣式。
# 注意,加一個星號表示元組格式
[(1, 2, 3), (4, 5, 6)]

思考程序:

A=[1,2,3]
B=[3,2,1,5,3,2]
zipped=zip(A,B)
for item in zipped:
    print(item)

輸出:

(1, 3)
(2, 2)
(3, 1)

六、__del__:

6.1 del作用

python的del函數,

  • 與 __init__() 方法對應的是 __del__() 方法
  • __init__() 方法用於初始化 Python 對象
  • 而 __del__() 則用於銷燬 Python 對象
  • 即在任何 Python 對象將要被系統回收之時,系統都會自動調用該對象的 __del__() 方法。

6.2 程序及結果

class Item:
    def __init__ (self, name, price):
        self.name = name
        self.price = price
    # 定義析構函數
    def __del__ (self):
        print('del刪除對象')
# 創建一個Item對象,將之賦給im變量
im = Item('鼠標', 29.8)
x = im   # ①
# 打印im所引用的Item對象
del im
print('end program')

運行結果:

end program
del刪除對象

因爲有x=im語句,因此只要X不被釋放,則不會調用del函數。

如果想要調用del函數,需要如下兩種方法:

  • 刪掉x=im語句
  • 加入代碼 del x

 

七、上面問題及答案

python的垃圾回收是什麼  ?

  • 見一、大整數池,小整數池,引用技術,循環引用的內存泄漏。

python的迭代器是什麼?

python 的return與yeild的區別?

  • 見二,迭代器是針對集合元素的一種遍歷。生成器是加了yeild的函數。可以看作迭代器,用next繼續調用

python的lambda表達式是什麼?怎麼寫?

  • 見三

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章