1. 程式人生 > >Python 模組解除安裝時__del__的行為

Python 模組解除安裝時__del__的行為

本節我們只討論一種情況:將某模組解除安裝時,如果某全域性變數含有__del__成員函式,其行為是怎樣的。

廢話少說,先上程式碼:

#-*- encoding: utf-8 -*-

import sys

class Test(object):
    testCount = 0
    def __init__(self):
        Test.testCount += 1
        print Test.testCount

    def __del__(self):
        print '[{}]'.format(id(self)), {k: None if v is None else id(v) for k, v in globals().iteritems()}
        #由於異常輸出的優先順序>標準輸出,此處強制輸出到控制檯,以防止下面執行出錯時,把錯誤資訊列印到print前面,從而影響到測試效果
        sys.stdout.flush()
        print Test.testCount
        Test.testCount -= 1

a = Test()
#在a, z之前移除
_k = Test()
z = Test()

#輸出全域性變數在字典中的順序(確保變量出現的順序為a < _k < Test < z)
print list(globals())
print '---[a = {}, _k = {}, z = {}]---'.format(id(a), id(_k), id(z))


#當前模組解除安裝時,按如下順序刪除globals中的變數:

#1. 優先將單下劃線開頭的變數刪除

#2. 按照globals中的順序去刪除全域性變數

#還要注意:此處說的刪除不是將變數從globals()del掉,而是將變數置為None

程式的輸出為:

1

2

3

['a', '__builtins__','__file__', '__package__', 'sys', '_k', 'Test', '__name__', 'z', '__doc__']

---[a = 41777640, _k = 41777696, z = 41778704]---

[41777696] {'a':41777640L, '__builtins__': 6004952L, '__package__': None, 'sys': 6006056L,'_k': None

, 'Test': 41880520L, '__name__': 6328752L, 'z':41778704L, '__doc__': None}

3

[41777640] {'a': None, '__builtins__': 6004952L, '__package__': None, 'sys': 6006056L, '_k':None, 'Test': 41880520L, '__name__': 6328752L, 'z': 41778704L, '__doc__': None}

2

[41778704] {'a': None,'__builtins__': 6004952L, '__package__': None, 'sys': None, '_k': None, 'Test':None, '__name__': None,'z': None

, '__doc__':None}

Exception AttributeError:"'NoneType' object has no attribute 'testCount'" in <bound methodTest.__del__ of <__main__.Test object at 0x00000000027D7E10>> ignored

我們使用紅色表示變數a, 綠色表示_k, 藍色表示z

可以看到刪除的順序是_k > a > Test >z

值得一提的有以下幾點:

1.      執行某變數的__del__時,如a, globals()中已將a置為了None,我們也可以理解為python是通過globals()['a'] = None動作在當前模組的globals中刪除a的。

2.     內建模組__builtins__永遠不會被解除安裝,它會貫穿於整個程式的生命週期。任何時候使用內建成員都是OK的。

3.      由於Test在globals()中位於z之前,在刪除z前,Test已經被刪除了。所以在刪除z時,丟擲了異常,因為None.testCount不存在。

4.      C++程式設計師應注意,Python的None不是nullptr(或NULL)。 None是python的一個物件,它有具體的地址。如果對None應用id函式,id(None)在筆者的Win7x64版上返回506033800L。

5.     請慎用__del__,根據Python官方文件,含有__del__函式的類,其例項不參與“迴圈垃圾”回收。python中有兩種垃圾回收(記憶體釋放)方式,一種是引用計數降為零時,釋放該變數;另一種是迴圈垃圾回收,這類似於Java的GC,主要用於回收由於“迴圈引用”而使得引用計數無法降為零的變數。而含用__del__成員函式的變數,無法被迴圈垃圾回收處理,從而造成記憶體隱患。

那麼如何保證__del__中呼叫Test.testCount不產生異常呢?

根據上面的分析,我們知道Test.testCount之所以失敗是因為globals()['Test'] is None了,那麼類級變數Test.testCount到底被回收了嗎? 顯然沒有,因為還有類的例項z的存在,在類的所有例項被銷燬前,類級變數是不會被回收的(這是Python語言本身的機制)。那如何訪問該變數呢,使用self.__class__替換Test,見程式碼:

    def __del__(self):
        print '[{}]'.format(id(self)), {k: None if v is None else id(v) for k, v in globals().iteritems()}
        #由於異常輸出的優先順序>標準輸出,此處強制輸出到控制檯,以防止下面執行出錯時,把錯誤資訊列印到print前面,從而影響到測試效果
        if sys is not None:
            sys.stdout.flush()
        print self.__class__.testCount
        self.__class__.testCount -= 1

__del__是一個比較特殊的函式,它發生在物件銷燬時,這個時間可能是由於引用計數降為0,也可能是模組解除安裝時,或者其它...,如果__del__需要使用self以外的變數的話要格外謹慎格外謹慎,一定要確保該變數有效。

所以要慎用__del__,能不用盡量不用


相關推薦

Python 模組解除安裝__del__行為

本節我們只討論一種情況:將某模組解除安裝時,如果某全域性變數含有__del__成員函式,其行為是怎樣的。 廢話少說,先上程式碼: #-*- encoding: utf-8 -*- import sys class Test(object): testCount

linux模組載入和模組解除安裝出現的問題

在編寫驅動程式的時候有時候會出現這種情況,模組載入之後不能解除安裝或解除安裝之後不能在載入,cat /proc/devices 後發現裝置還佔用著裝置號,這種情況下,再次載入驅動模組肯定不會成功,必須重新啟動才可以解決。最近仔細看書後發現自己在驅動程式的解除安裝函式中少寫了兩個函式呼叫,以至於在載入模組的時候

Python模組安裝解除安裝

安裝:        無pip環境變數時:           安裝whl包:python -mpip install wheel    ->    python -m pip install  **.whl           安裝tar.gz包:cd到解壓後路

解除安裝彈出啟動c program出現問題 找不到制定的模組

可以按照如下方法進行解決:點選“開始”----“所有程式”----“附件”----“執行”,鍵入cmd。回車。執行命令:sfc /scannow。  windows會自動對系統檔案進行全面掃描,然後修復受損檔案,完成後重新啟動系統即可,或者也可以自行查詢在c"\progra

用apt-get remove python命令解除安裝後出現的坑,你填得上麼?

用apt-get remove python命令解除安裝python後出現的坑,你填得上麼? 本文記錄了博主在企圖解除安裝python3.5的過程中遇到的坑和自救的過程。更新於2018.10.23。 首先,上重點!!!! 不要用下面的命令!!!坑都是因為這個命令出來的。 su

python無法解除安裝安裝

there is a problem with this windows installer package................. 使用微軟提供的工具執行監測,刪除之前有問題的版本;然後重新安裝 https://support.microsoft.com/en-us/help/1

vs2013在解除安裝,出現安裝錯誤devenv.exe

  [3DCC:0CD4][2018-10-10T19:23:13]i001: Burn v3.7.2002.0, Windows v6.3 (Build 9600: Service Pack 0), path: C:\ProgramData\Package Cache\{4d78

VS2010解除安裝vs_setup.msi could not be opened

在電腦已有VS2010的情況下安裝VS2015又解除安裝2015,導致VS2010無法開啟,報錯Exception has been thrown by the target of an invocat

在Ubuntu系統上停止使用Anaconda及自帶的Python解除安裝Anaconda

一、停止使用Anaconda(包括Anaconda帶有的Python環境) 由於Anaconda在安裝過程中也會安上自帶的Python,而Ubuntu系統自帶有Python2.7環境,如果Anaconda安裝的是Python3,會將Python2.7版本覆蓋掉。

window下python模組nmap安裝使用

我是直接用pip安裝的,需要安裝nmap,和python-nmap模組。 使用 nmap.PortScanner(),報錯“‘nmap’ has no ‘PortScanner’ attribute”,進入原始檔中檢視,檔案中沒有PortScanner類。   解決方法 下

linux 核心編譯驅動模組ko的配置以及載入模組解除安裝模組例項測試

linux 核心編譯驅動模組ko的配置以及載入模組、解除安裝模組例項測試一、要讓linux系統支援動態載入驅動模組必須先對linux 核心進行相關的配置,不然編譯不過,載入模組也會載入失敗甚至導致裝置重啟。1、勾選核心Enable loadable module suppor

解決Python使用pip安裝遇到的解碼錯誤問題

我的OS是Windows,在使用python 3.6.2嘗試安裝pylint時,使用自動工具pip安裝遇到了一個錯誤: 命令列: >pip install pylint 執行錯誤(省略了其他正常輸出): Exception: Tra

pythonpython徹底解除安裝的方法【windows安裝解除安裝的示例】

要想徹底乾淨的解除安裝python,如果是使用的安裝版的話,其實很簡單。【windows安裝版】   就是點選安裝包。   例如,當前你安裝的版本是3.6.5,你想要把它解除安裝掉。 檢視python版本的命令:   只需要點選對應版本的安裝包: 點選解除

Windows下Python模組安裝

兩種方式 方法一:python setup.py install 1.此種方法安裝首先需要下載相關的模組(可以到此網站下載 ctrl+f搜尋:https://www.lfd.uci.edu/~gohlke/pythonlibs/)。 2.解壓,在cmd視窗cd進入到解壓目錄

檢查python模組是否安裝

主要是通過python -c來執行import 語句下面是指令碼,修改第一個變數,就可以隨意的檢查模組是否已經安裝#!/bin/bash

npm全域性模組解除安裝及預設安裝目錄修改

解除安裝全域性安裝模組  npm uninstall -g <package> 解除安裝後,你可以到 /node_modules/ 目錄下檢視包是否還存在,或者使用以下命令檢視:npm l

Inno Setup安裝解除安裝判斷是否程式正在執行

var ErrorCode: Integer; IsRunning: Integer; // 安裝時判斷客戶端是否正在執行 function InitializeSetup(): Boolean; begin Result :=true; //安裝程式

Mac下Python的MySQL-python模組安裝

用Python連線MySQL(版本5.7)資料庫時需要用到MySQL模組,但是Python並沒有自帶MySQL模組,需要自行安裝,也就是MySQL for Python(MySQL-python)pyt

Python第三方庫安裝編碼問題utf-8變gbk

第三方庫安裝時編碼錯誤 Exception: Traceback (most recent call last):   File "d:\tools\pyhthon\lib\site-packages\pip\compat\__init__.py", line 73, i

Python安裝解除安裝第三方模組

pip command ModuleName command:用於指定要執行的命令(install:安裝,uninstall:解除安裝) ModuleName:需要安裝的模組名稱 示例: 安裝第三方模組numpy模組(用於科學計算): C:\Users&