2016-03-15 127 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__'方法',并在'语句中使用该类。 –