2016-03-15 116 views
8

試圖正確刪除一個Python對象。我創建了一個對象,然後用'with'語句刪除它。但是,當我做後打印出來的「用」的語句被關閉....對象仍然存在:Python'with'not'刪除對象

class Things(object): 
    def __init__(self, clothes, food, money): 
     self.clothes = clothes 
     self.food = food 
     self.money = money 

    def __enter__(self): 
     return self 

    def __exit__(self, exc_type, exc_val, exc_tb): 
     print('object deleted') 

with Things('socks','food',12) as stuff: 
    greg = stuff.clothes 
    print(greg) 


print(stuff.clothes) 

回報:

socks 
object deleted 
socks 
+3

亞歷克斯泰勒的答案是正確的錢。我想補充一點,因爲Python有自動內存管理(垃圾回收),所以你不必擔心刪除不再使用的對象。因此,您爲此目的使用上下文管理器毫無意義。同樣,名稱爲「stuff」的變量由'with'語句創建,但直到腳本結束時纔會繼續存在,如您所見。如果你有一行'del stuff',那麼名字「stuff」變得不確定。你必須這樣做很少見。 –

+1

[with with statement with available with-block?]定義的變量可能重複(http://stackoverflow.com/questions/6432355/variable-defined-with-with-statement-available-outside-of-with-塊) – 2016-03-15 04:47:45

回答

5

with調用對象的於__exit__方法退出該塊的範圍。你的__exit__方法只是打印object_deleted。你必須實際上將代碼銷燬在__exit__方法中(但請注意,這不是好的做法!)。

會發生什麼事是:

with Things('socks','food',12) as stuff: 
    # the __enter__() method is called and the returned object 
    # is assigned to the variable "stuff" 
    greg = stuff.clothes 
    print(greg) 
# when you've exited the block here, the __exit__() method is called. 

關於你的願望,明確刪除對象,你應該把它交給Python的垃圾收集器。閱讀這個question,這將有所幫助。您可以嘗試使用gc.collect()或重寫__del__方法。這裏是another good discussion

+0

嗯,它不是100%正確的。你不能刪除'__exit__'裏的'self'。 – viraptor

+0

是的,請...在這種情況下,請告訴我正確的__exit__方法來刪除一個Things對象 – rikkitikkitumbo

+0

我已經編輯了我的答案,建議OP將它留給Python的垃圾收集器。 –

17

Python的with聲明不是關於刪除對象 - 而是關於資源管理。 __enter____exit__方法是爲您提供資源初始化和銷燬​​代碼,即您可以選擇刪除那裏的某些內容,但不會隱式刪除對象。請閱讀此with article以更好地瞭解如何使用它。

該對象停留在with聲明後的範圍內。如果這是你想要的,你可以撥打del。由於它在範圍內,因此可以在底層資源關閉後進行查詢。考慮這個僞代碼:

class DatabaseConnection(object): 
    def __init__(self, connection): 
    self.connection = connection 
    self.error = None 

    def __enter__(self): 
    self.connection.connect() 

    def __exit__(self, exc_type, exc_val, exc_tb): 
    self.connection.disconnect() 

    def execute(self, query): 
    try 
     self.connection.execute(query) 
    except e: 
     self.error = e 

with DatabaseConnection(connection) as db: 
    db.execute('SELECT * FROM DB') 
if db.error: 
    print(db.error) 

del db 

我們不希望保持一個數據庫連接閒逛的時間比我們需要(另一個線程/客戶可能需要它),所以我們反而使資源被釋放(在含蓄with塊的結尾),但之後我們可以繼續查詢該對象。然後,我添加了一個明確的del來告訴運行時代碼已完成變量。

2

試圖妥善刪除一個Python對象

這是你的第一個錯誤,從不必擔心刪除對象以釋放內存解釋語言明確地釋放你。當沒有更多引用並且對象不在範圍內時,他們所做的是刪除它們。

其次:

with Things('socks','food',12) as stuff: 
    greg = stuff.clothes 
    print(greg) 

使用with,儘管縮進doesn't create a new scope

對比度與您的代碼:

class Things(object): 
    def __init__(self, clothes, food, money): 
     self.clothes = clothes 
     self.food = food 
     self.money = money 

    def __enter__(self): 
     return self 

    def __exit__(self, exc_type, exc_val, exc_tb): 
     print('object deleted') 

stuff = "no stuff" 
def do_it(): 
    with Things('socks','food',12) as stuff: 
     greg = stuff.clothes 
     print(greg) 
     print(stuff) 

do_it() 
print(stuff) 

其中給出:

socks 
<__main__.Things object at 0xb744370c> 
object deleted 
no stuff 

這裏內部stuffdo_it()不再存在,所以當第二print(stuff)運行有"no stuff"

最後,不要擔心刪除對象。它會發生,而不是你的工作來管理它。

1

所以,感謝大家的好鏈接。但我真的想要刪除一個對象,而不是等待花哨的垃圾收集器。這工作:

class Things(object): 
    def __init__(self,clothes, food, money): 
     self.clothes = clothes 
     self.food = food 
     self.money = money 

    def __enter__(self): 
     return self 

    def __exit__(self, exc_type, exc_val, exc_tb): 
     print('nothing happens') 



with Things('socks','food',12) as stuff: 
    print(stuff.clothes) 
    del stuff 


print(stuff) 

現在返回:

socks 
nothing happens 
Traceback (most recent call last): 
    File "/home/jeff/PycharmProjects/tensorflow_sandbox/main", line 36, in <module> 
    print(stuff) 
NameError: name 'stuff' is not defined 

萬歲!它被刪除

+1

你可能會考慮擁有一個'StuffManager',它有一個'__enter__'方法,創建並返回一個'Stuff'對象和一個'__exit__'方法',並在'語句中使用該類。 –