Using explicit del in python on local variables - python

What are the best practices and recommendations for using explicit del statement in python? I understand that it is used to remove attributes or dictionary/list elements and so on, but sometimes I see it used on local variables in code like this:
def action(x):
result = None
something = produce_something(x)
if something:
qux = foo(something)
result = bar(qux, something)
del qux
del something
return result
Are there any serious reasons for writing code like this?
Edit: consider qux and something to be something "simple" without a __del__ method.

I don't remember when I last used del -- the need for it is rare indeed, and typically limited to such tasks as cleaning up a module's namespace after a needed import or the like.
In particular, it's not true, as another (now-deleted) answer claimed, that
Using del is the only way to make sure
a object's __del__ method is called
and it's very important to understand this. To help, let's make a class with a __del__ and check when it is called:
>>> class visdel(object):
... def __del__(self): print 'del', id(self)
...
>>> d = visdel()
>>> a = list()
>>> a.append(d)
>>> del d
>>>
See? del doesn't "make sure" that __del__ gets called: del removes one reference, and only the removal of the last reference causes __del__ to be called. So, also:
>>> a.append(visdel())
>>> a[:]=[1, 2, 3]
del 550864
del 551184
when the last reference does go away (including in ways that don't involve del, such as a slice assignment as in this case, or other rebindings of names and other slots), then __del__ gets called -- whether del was ever involved in reducing the object's references, or not, makes absolutely no difference whatsoever.
So, unless you specifically need to clean up a namespace (typically a module's namespace, but conceivably that of a class or instance) for some specific reason, don't bother with del (it can be occasionally handy for removing an item from a container, but I've found that I'm often using the container's pop method or item or slice assignment even for that!-).

No.
I'm sure someone will come up with some silly reason to do this, e.g. to make sure someone doesn't accidentally use the variable after it's no longer valid. But probably whoever wrote this code was just confused. You can remove them.

When you are running programs handling really large amounts of data ( to my experience when the totals memory consumption of the program approaches something like 1GB) deleting some objects:
del largeObject1
del largeObject2
…
can give your program the necessary breathing room to function without running out of memory. This can be the easiest way to modify a given program, in case of a “MemoryError” runtime error.

Actually, I just came across a use for this. If you use locals() to return a dictionary of local variables (useful when parsing things) then del is useful to get rid of a temporary that you don't want to return.

Related

In python, is it possible to get an object without name from another module?

I want to get all object generated from another module, even the object do not have a name or reference, is it possible? For example:
in module1.py, there's only one line code:
MyClass()
in module2.py:
module1 = __import__("module1")
# print sth of MyClass from module1
What you're trying to do is generally impossible.
An object that has no name or other reference is garbage. That's the technical meaning of the term "garbage". In CPython (the Python implementation you're probably using if you don't know which one you're using), garbage is collected immediately—as soon as that MyClass() statement ends, the instance gets destroyed.
So, you can't access the object, because it doesn't exist.
In some other Python implementations, the object may not be destroyed until the next garbage collection cycle, but that's going to be pretty soon, and it's not deterministic exactly when—and you still have no way to get at it before it's destroyed. So it might as well not exist, even if it hasn't actually been finalized yet.
Now, "generally" means there are some exceptions. They're not common, but they do exist.
For example, imagine a class like this:
class MyClass:
_instances = []
def __init__(self):
MyClass._instances.append(self)
Now, when you do MyClass(), there actually is a reference to that instance, so it's not garbage. And, if you know where it is (which you'd presumably find in the documentation, or in the source code), you can access it as MyClass._instances[-1]. But it's unlikely that an arbitrary class MyClass does anything like this.
OK, I lied. There is sort of a way to do this, but (a) it’s cheating, and (b) it’s almost certainly a terrible idea that has no valid use cases you’ll ever think of. But just for fun, here’s how you could do this.
You need to write an import hook, and make sure it gets installed before the first time you import the module. Then you can do almost anything you want. The simplest idea I can think of is transforming the AST to turn every expression statement (or maybe just every expression statement at the top level) into an assignment statement that assigns to a hidden variable. You can even make the variable name an invalid identifier, so it'll be safe to run on any legal module no matter what's in the global namespace. Then you can access the first object created and abandoned by the module as something like module.globals()['.0'].

Python: Understanding object __del__ method

Can anyone describe me why this code will print '2 1 0 done' instead of expected output '0 1 2 done'?
As i can understand, we have some anonymous variables creating during list comprehensions, and they are garbage-collected, using filo principle, on list comprehension uncoverage end.
But, they still are referenced in list aa, aren't they?
Why the second 'del a' is not calling del magic method in that case?
class A:
def __init__(self, name):
self.name = name
def __del__(self):
print self.name,
aa = [A(str(i)) for i in range(3)]
for a in aa:
del a
print 'done'
Also, advanced questions. Please look at http://codepad.org/niaUzGEy
Why there are 5 copies, 3 copies? Musn't this be 1 copy? Why 5 or 3? Dont know, thats why asking it ;)
Thanks for your time!
You are confusing the del statement and the __del__ method.
del a simply unbinds the name a from whatever object it referenced. The list referenced by aa is unchanged so the objects all continue to exist.
The __del__ method is only called after the last reference to an object has been destroyed. That could be after a call to __del__ but usually isn't.
You rarely need to use del. It would be much more common just to rebind aa and then all the objects it contains will be released, and if not otherwise referenced their __del__ methods will be called automatically.
Also, you rarely need to use __del__. For most purposes Python's management of objects will handle cleanup automatically. Adding a __del__ method to a class is generally a bad idea as it can interfere with the garbage collector, so rather paradoxically __del__ makes it more likely that your program will leak memory. Also Python won't guarantee whether __del__ is actually called on program exit, and if it does you may find global variables you cant to use no longer exist, nor will it guarantee to only call it once (though you have to jump through hoops to make it call it more than once).
In short, avoid using __del__ if you possibly can.
It prints done 2 1 0(CPython).
You don't delete list elements in a for loop. They are deleted on exit. As far as I know call order of __del__ is implementation-specific, so it can be different in another implementations(IronPython, Jython etc.)

Delete Function

I'm trying to create a function to delete another function.
def delete_function(func):
del func
is what I have so far, but for some reason it doesn't work.
def foo():
print("foo")
delete_function(foo)
doesn't seem to do the trick. I know one can do it easily, just
del(foo)
but I'm trying to do it a different way. How?
Deleting a function isn't really something you do to the function itself; it's something you do to the namespace it lives in. (Just as removing the number 3 from a list isn't something you do to the number 3, it's something you do to the list.)
Suppose you say
def foo(x): return 1
bar = foo
Then (more or less) you have two names, foo and bar, for the exact same function. Now suppose you call delete_function(foo) or delete_function(bar). The exact same thing, namely a function object, is being passed to delete_function. But what you actually want to remove is the association between the name foo or bar and that object -- and there's no possible way delete_function (however you define it) can know whether it's foo or bar or something else you're wanting to get rid of.
(Well ... Actually, there is. There are nasty hacky things you can do that would let the code in delete_function know more about how it was called. But don't even think about thinking about them.)
So. Your options are as follows. (1) Nasty hacky things, as just mentioned. Don't. (2) Pass delete_function not the function object but information about the name of the function and the thing you're trying to delete it from. This is ugly and ungainly. (3) Don't bother.
I strongly recommend #3, unless the only reason you're doing this is to learn more about how Python works. In the latter case, a good place to begin might be http://docs.python.org/reference/executionmodel.html.
Since foo is a global, you can delete it from the global definitions:
def delete_func(func):
del globals()[func.func_name]
It just won't work.
What you are trying to do is, essentially, the name space of the caller.
Try this:
print "0", locals()
def foo(): pass
print "1", locals()
del foo
print "2", locals()
Note that
the locals dict at 0 and 2 are identical, and at 1 nearly - except it has the additional assignment of foo.
del is a statement and not a function
If you do the del in a function delete_function(), essentially the assignment within your function gets removed (which is effectless because the function is terminated immediately), while the caller keeps the assignment.
Strictly spoken, del does not delete objects, but merely assignments from names to objects. Objects get deleted "automatically" (garbage collected) as soon as they are not referenced any longer.
It COULD work what you try to do by inspection of the stack frame and passing of the name to be deleted as a string, but it would be a PITA.
Maybe you try
del locals()['foo']
or
locals()['foo'] = 42
? But I think it is not guarantteed that it really modifies the real locals dictionary, it might as well operate on a copy and thus stay effectless...
If you're using python 3, this should work:
def foo():
return 'foo'
del foo

In Python, is use of `del` statement a code smell?

I tend to use it whenever I am working on a prototype script, and:
Use a somewhat common variable (such as fileCount), and
Have a large method (20+ lines), and
Do not use classes or namespaces yet.
In this situation, in order to avoid potential variable clash, I delete the bugger as soon as I am done with it. I know, in a production code I should avoid 1., 2., and 3., but going from a prototype that works to a completely polished class is time consuming. Sometimes I might want to settle for a sub-optimal, quick refactoring job. In that case I find keeping the del statements handy. Am I developing an unnecessary, bad habit? Is del totally avoidable? When would it be a good thing?
I don't think that del by itself is a code smell.
Reusing a variable name in the same namespace is definitely a code smell as is not using classes and other namespaces where appropriate. So using del to facilitate that sort of thing is a code smell.
The only really appropriate use of del that I can think of off the top of my head is breaking cyclic references which are often a code smell as well (and often times, this isn't even necessary). Remember, all del does is delete the reference to the object and not the object itself. That will be taken care of by either reference counting or garbage collecting.
>>> a = [1, 2]
>>> b = a
>>> del a
>>> a
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'a' is not defined
>>> b
[1, 2]
You can see that the list is kept alive after the del statement because b still holds a reference to it.
So, while del isn't really a code smell, it can be associated with things that are.
Any code that's well organized in functions, classes and methods doesn't need del except in exceptional circumstances. Aim to build your apps well factored from the start by using more functions and methods, avoid reusing variable names, etc.
The use of a del statement is OK - it doesn't lead to any trouble, I use it often when I use Python as a replacement for shell scripts on my system, and when I'm making script experiments. However, if it appears often in a real application or library, it is an indication that something isn't all right, probably badly structured code. I never had to use it in an application, and you'd rarely see it used anywhere on code that's been released.

Deleting attributes when deleting instance

class A:
def __get(self):
return self._x
def __set(self, y):
self._x = y
def __delete_x(self):
print('DELETING')
del self._x
x = property(__get,__set,__delete_x)
b = A()
# Here, when b is deleted, i'd like b.x to be deleted, i.e __delete_x()
# called (and for immediate consequence, "DELETING" printed)
del b
The semantics of the del statement don't really lend themselves to what you want here. del b simple removes the reference to the A object you just instantiated from the local scope frame / dictionary; this does not directly cause any operation to be performed on the object itself. If that was the last reference to the object, then the reference count dropping to zero, or the garbage collector collecting a cycle, may cause the object to be deallocated. You could observe this by adding a __del__ method to the object, or by adding a weakref callback that performs the desired actions.
Neither of the latter two solutions seems like a great idea, though; __del__ methods prevent the garbage collector from collecting any cycles involving the object; and while weakrefs do not suffer from this problem, in either case you may be running in a strange environment (such as during program shutdown), which may make it difficult to get done what you want to accomplish.
If you can expand on your exact use case, it may be that there is an entirely different approach to accomplishing your desired end goal, but it is difficult to speculate based on such a general and limited example.
To control what happens when an instance of class A goes away (whether by being deleted or garbage collected), you can implement special method __del__(self) in A. If you want to have your code involved when a specific attribute of that instance goes away, you can either wrap that attribute with a wrapper class which has __del__, or, probably better in most cases, use the weakref module (however, not all types are subject to being target of weak references, so you may also need some wrapping for this case).
Avoiding __del__ is generally preferable, if you possibly can, because it can interfere with garbage collection and thereby cause "memory leaks" if and when you have circular references.
An ugly way to do it would be :
def __del__(self):
for x in dir(self.__class__):
if type(getattr(self.__class__, x)) == property:
getattr(self.__class__, x).fdel(self)

Categories

Resources