When is del useful in Python? - python

I can't really think of any reason why Python needs the del keyword (and most languages seem to not have a similar keyword). For instance, rather than deleting a variable, one could just assign None to it. And when deleting from a dictionary, a del method could be added.
Is there a reason to keep del in Python, or is it a vestige of Python's pre-garbage collection days?

Firstly, you can del other things besides local variables
del list_item[4]
del dictionary["alpha"]
Both of which should be clearly useful. Secondly, using del on a local variable makes the intent clearer. Compare:
del foo
to
foo = None
I know in the case of del foo that the intent is to remove the variable from scope. It's not clear that foo = None is doing that. If somebody just assigned foo = None I might think it was dead code. But I instantly know what somebody who codes del foo was trying to do.

There's this part of what del does (from the Python Language Reference):
Deletion of a name removes the binding of that name from the local or global namespace
Assigning None to a name does not remove the binding of the name from the namespace.
(I suppose there could be some debate about whether removing a name binding is actually useful, but that's another question.)

One place I've found del useful is cleaning up extraneous variables in for loops:
for x in some_list:
do(x)
del x
Now you can be sure that x will be undefined if you use it outside the for loop.

Deleting a variable is different than setting it to None
Deleting variable names with del is probably something used rarely, but it is something that could not trivially be achieved without a keyword. If you can create a variable name by writing a=1, it is nice that you can theoretically undo this by deleting a.
It can make debugging easier in some cases as trying to access a deleted variable will raise an NameError.
You can delete class instance attributes
Python lets you write something like:
class A(object):
def set_a(self, a):
self.a=a
a=A()
a.set_a(3)
if hasattr(a, "a"):
print("Hallo")
If you choose to dynamically add attributes to a class instance, you certainly want to be able to undo it by writing
del a.a

There is a specific example of when you should use del (there may be others, but I know about this one off hand) when you are using sys.exc_info() to inspect an exception. This function returns a tuple, the type of exception that was raised, the message, and a traceback.
The first two values are usually sufficient to diagnose an error and act on it, but the third contains the entire call stack between where the exception was raised and where the the exception is caught. In particular, if you do something like
try:
do_evil()
except:
exc_type, exc_value, tb = sys.exc_info()
if something(exc_value):
raise
the traceback, tb ends up in the locals of the call stack, creating a circular reference that cannot be garbage collected. Thus, it is important to do:
try:
do_evil()
except:
exc_type, exc_value, tb = sys.exc_info()
del tb
if something(exc_value):
raise
to break the circular reference. In many cases where you would want to call sys.exc_info(), like with metaclass magic, the traceback is useful, so you have to make sure that you clean it up before you can possibly leave the exception handler. If you don't need the traceback, you should delete it immediately, or just do:
exc_type, exc_value = sys.exc_info()[:2]
To avoid it all together.

Just another thinking.
When debugging http applications in framework like Django, the call stack full of useless and messed up variables previously used, especially when it's a very long list, could be very painful for developers. so, at this point, namespace controlling could be useful.

Using "del" explicitly is also better practice than assigning a variable to None. If you attempt to del a variable that doesn't exist, you'll get a runtime error but if you attempt to set a variable that doesn't exist to None, Python will silently set a new variable to None, leaving the variable you wanted deleted where it was. So del will help you catch your mistakes earlier

del is often seen in __init__.py files. Any global variable that is defined in an __init__.py file is automatically "exported" (it will be included in a from module import *). One way to avoid this is to define __all__, but this can get messy and not everyone uses it.
For example, if you had code in __init__.py like
import sys
if sys.version_info < (3,):
print("Python 2 not supported")
Then your module would export the sys name. You should instead write
import sys
if sys.version_info < (3,):
print("Python 2 not supported")
del sys

To add a few points to above answers:
del x
Definition of x indicates r -> o (a reference r pointing to an object o) but del x changes r rather than o. It is an operation on the reference (pointer) to object rather than the object associated with x. Distinguishing between r and o is key here.
It removes it from locals().
Removes it from globals() if x belongs there.
Removes it from the stack frame (removes the reference physically from it, but the object itself resides in object pool and not in the stack frame).
Removes it from the current scope. It is very useful to limit the span of definition of a local variable, which otherwise can cause problems.
It is more about declaration of the name rather than definition of content.
It affects where x belongs to, not where x points to. The only physical change in memory is this. For example if x is in a dictionary or list, it (as a reference) is removed from there(and not necessarily from the object pool). In this example, the dictionary it belongs is the stack frame (locals()), which overlaps with globals().

I've found del to be useful for pseudo-manual memory management when handling large data with Numpy. For example:
for image_name in large_image_set:
large_image = io.imread(image_name)
height, width, depth = large_image.shape
large_mask = np.all(large_image == <some_condition>)
# Clear memory, make space
del large_image; gc.collect()
large_processed_image = np.zeros((height, width, depth))
large_processed_image[large_mask] = (new_value)
io.imsave("processed_image.png", large_processed_image)
# Clear memory, make space
del large_mask, large_processed_image; gc.collect()
This can be the difference between bringing a script to a grinding halt as the system swaps like mad when the Python GC can't keep up, and it running perfectly smooth below a loose memory threshold that leaves plenty of headroom to use the machine to browse and code while it's working.

Force closing a file after using numpy.load:
A niche usage perhaps but I found it useful when using numpy.load to read a file. Every once in a while I would update the file and need to copy a file with the same name to the directory.
I used del to release the file and allow me to copy in the new file.
Note I want to avoid the with context manager as I was playing around with plots on the command line and didn't want to be pressing tab a lot!
See this question.

I would like to elaborate on the accepted answer to highlight the nuance between setting a variable to None versus removing it with del:
Given the variable foo = 'bar', and the following function definition:
def test_var(var):
if var:
print('variable tested true')
else:
print('variable tested false')
Once initially declared, test_var(foo) yields variable tested true as expected.
Now try:
foo = None
test_var(foo)
which yields variable tested false.
Contrast this behavior with:
del foo
test_var(foo)
which now raises NameError: name 'foo' is not defined.

As an example of what del can be used for, I find it useful i situations like this:
def f(a, b, c=3):
return '{} {} {}'.format(a, b, c)
def g(**kwargs):
if 'c' in kwargs and kwargs['c'] is None:
del kwargs['c']
return f(**kwargs)
# g(a=1, b=2, c=None) === '1 2 3'
# g(a=1, b=2) === '1 2 3'
# g(a=1, b=2, c=4) === '1 2 4'
These two functions can be in different packages/modules and the programmer doesn't need to know what default value argument c in f actually have. So by using kwargs in combination with del you can say "I want the default value on c" by setting it to None (or in this case also leave it).
You could do the same thing with something like:
def g(a, b, c=None):
kwargs = {'a': a,
'b': b}
if c is not None:
kwargs['c'] = c
return f(**kwargs)
However I find the previous example more DRY and elegant.

When is del useful in python?
You can use it to remove a single element of an array instead of the slice syntax x[i:i+1]=[]. This may be useful if for example you are in os.walk and wish to delete an element in the directory. I would not consider a keyword useful for this though, since one could just make a [].remove(index) method (the .remove method is actually search-and-remove-first-instance-of-value).

I think one of the reasons that del has its own syntax is that replacing it with a function might be hard in certain cases given it operates on the binding or variable and not the value it references. Thus if a function version of del were to be created a context would need to be passed in. del foo would need to become globals().remove('foo') or locals().remove('foo') which gets messy and less readable. Still I say getting rid of del would be good given its seemingly rare use. But removing language features/flaws can be painful. Maybe python 4 will remove it :)

The "del" command is very useful for controlling data in an array, for example:
elements = ["A", "B", "C", "D"]
# Remove first element.
del elements[:1]
print(elements)
Output:
['B', 'C', 'D']

del deletes the binding of the variable and its object that it points to.
>>> a = ['a', 'b', 'c']
>>> b = a
>>> del a
>>> b
['a', 'b', 'c']
>>> a
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'a' is not defined
A simple use case I can think of would be in case you have used a built-in function name as a variable, and you want to use that function after it has been already "overridden" by your variable name.
t = ('a', "letter")
value, type = t
print(value, type)
del type
print(type(value))
Output:
a letter
<class 'str'>

Yet another niche usage:
In pyroot with ROOT5 or ROOT6, "del" may be useful to remove a python object that referred to a no-longer existing C++ object. This allows the dynamic lookup of pyroot to find an identically-named C++ object and bind it to the python name. So you can have a scenario such as:
import ROOT as R
input_file = R.TFile('inputs/___my_file_name___.root')
tree = input_file.Get('r')
tree.Draw('hy>>hh(10,0,5)')
R.gPad.Close()
R.hy # shows that hy is still available. It can even be redrawn at this stage.
tree.Draw('hy>>hh(3,0,3)') # overwrites the C++ object in ROOT's namespace
R.hy # shows that R.hy is None, since the C++ object it pointed to is gone
del R.hy
R.hy # now finds the new C++ object
Hopefully, this niche will be closed with ROOT7's saner object management.

del is removing the variable from the current scope unless it is re-initialized. Setting it to None keeps it in the current scope.
a = "python string"
print(a)
del a
print(a)
a = "new python string"
print(a)
Output:
python string
Traceback (most recent call last):
File "testing.py", line 4, in <module>
print(a)
NameError: name 'a' is not defined

As I have not seen a interactive console answer, I'll be showing one.
When foo=None that reference and the object exist, it's not pointing to it.
While del foo destroys the object and reference too.
So if you do something like this if foo is None and it was deleted it will rise NameError as the the reference, it's object and everything in between was deleted with del
Deletion of a target list recursively deletes each target, from left to right.
Meanwhile foo=None is just a reference pointing to None so the reference is still kicking, same for the object.
[...]In Python, variables are references to objects and any variable can reference any object[...]
Link to quote 1
Link to quote 2

Another niche case, but useful.
from getpass import getpass
pass = getpass()
token = get_auth_token(pass)
del pass
# Assume more code here...
After the deletion of the pass variable, you don't run the risk of it being printed out later by mistake, or otherwise ending up in a log or stack trace.

Here goes my 2 cents contribution:
I have a optimization problem where I use a Nlopt library for it.
I initializing the class and some of its methods, I was using in several other parts of the code.
I was having ramdom results even if applying the same numerical problem.
I just realized that by doing it, some spurius data was contained in the object when it should have no issues at all. After using del, I guess the memory is being properly cleared and it might be an internal issue to that class where some variables might not be liking to be reused without proper constructor.

Once I had to use:
del serial
serial = None
because using only:
serial = None
didn't release the serial port fast enough to immediately open it again.
From that lesson I learned that del really meant: "GC this NOW! and wait until it's done" and that is really useful in a lot of situations. Of course, you may have a system.gc.del_this_and_wait_balbalbalba(obj).

del is the equivalent of "unset" in many languages
and as a cross reference point moving from another language to python..
people tend to look for commands that do the same thing that they used to do in their first language...
also
setting a var to "" or none doesn't really remove the var from scope..it just empties its value
the name of the var itself would still be stored in memory...why?!?
in a memory intensive script..keeping trash behind its just a no no
and anyways...every language out there has some form of an "unset/delete" var function..why not python?

Related

Type hints without value assignment in Python

I was under the impression that typing module in Python is mostly for increasing code readability and for code documentation purposes.
After playing around with it and reading about the module, I've managed to confuse myself with it.
Code below works even though those two variables are not initialized (as you would normally initialize them e.g. a = "test").
I've only put a type hint on it and everything seems ok. That is, I did not get a NameError as I would get if I just had a in my code NameError: name 'a' is not defined
Is declaring variables in this manner (with type hints) an OK practice? Why does this work?
from typing import Any
test_var: int
a: Any
print('hi')
I expected test_var: int to return an error saying that test_var is not initiated and that I would have to do something like test_var: int = 0 (or any value at all). Does this get set to a default value because I added type hint to it?
It is fairly straightforward, when you consider the namespaces involved. This is hinted at by the fact that you get a NameError, when you actually try and do anything with test_var, such as passing it to a function (like print). It tells you that the name you used is not known to the interpreter.
What does variable assignment do?
What happens, when you assign a value to a variable in the global namespace of a module for the first time, is it gets added to that modules globals dictionary with the key being the variable name and the value being, well, its value. You can see this dictionary by calling the built-in globals function in that module:
from pprint import pprint
a = 1
pprint(globals())
The output looks something like this:
{'__annotations__': {},
...
'__name__': '__main__',
...
'a': 1,
...}
What does annotation do?
When you look closer at that dictionary, you'll find another interesting key there, namely __annotations__. Right now, its value is an empty dictionary. But I bet you can already guess, what will happen, if we annotate our variable with a type:
from pprint import pprint
a: int = 1
pprint(globals())
The output:
{'__annotations__': {'a': <class 'int'>},
...
'a': 1,
...}
When we add a type hint to (i.e. annotate) a variable, the interpreter adds that name and type to the relevant __annotations__ dictionary (see docs); in this case that of our module. By the way, since the __annotations__ dictionary is in our global namespace we can access it directly:
a: int = 1
print("a" in globals()) # True
print("a" in __annotations__) # True
Can you annotate without assigning?
Finally, what happens, if we just annotate without assigning a value to a variable?
a: int
print("a" in globals()) # False
print("a" in __annotations__) # True
And that is the explanation of why we get an error, if we try and e.g. print out a in this example, but otherwise don't get any error. The code merely told the interpreter (and any static type checker) about the annotation, but it assigned no value, thus failing to create an entry in the global namespace dictionary.
It makes sense, if you think about it: What should be set as the value for a in that namespace? It has no value (not even None or NotImplemented or anything like that). To the interpreter the a: int line merely meant the creation of an entry in the __annotations__ of our module, which is perfectly valid.
Runtime meaning of annotations
I would also like to stress the fact that the annotation is not meaningless for the interpreter and thus runtime, as some people often claim. It is admittedly rarely used, but as we just saw in the example, you can absolutely work with annotations at runtime. Whether or not this is useful is obviously up to you. Some packages like Pydantic or the standard library's dataclasses actually rely heavily on annotations for their purposes.
The value set in the __annotations__ dictionary in our example is actually a reference to the int class. So we can absolutely work with it at runtime, if we want to:
a: int
a_type = __annotations__["a"]
print(a_type is int) # True
print(a_type("2")) # 2
You can play around with this concept in class namespaces as well (not just with module namespace), but I'll leave this as an exercise for the reader.
So to wrap up, for a name to be added to any namespace, it must have a value assigned to it. Not assigning a value and just providing an annotation is totally fine to create an entry in that namespace's __annotations__.
Python will not initialize a variable automatically, so that variable doesn't get set to anything. a: int doesn't actually define or initialize the variable. That happens when you assign a value to it. The typings really only act as hints to the IDE, and have no practical effect without assigning a value during compilation or runtime.

Differentiate Garbage collector and __del__ in Python [duplicate]

I can't really think of any reason why Python needs the del keyword (and most languages seem to not have a similar keyword). For instance, rather than deleting a variable, one could just assign None to it. And when deleting from a dictionary, a del method could be added.
Is there a reason to keep del in Python, or is it a vestige of Python's pre-garbage collection days?
Firstly, you can del other things besides local variables
del list_item[4]
del dictionary["alpha"]
Both of which should be clearly useful. Secondly, using del on a local variable makes the intent clearer. Compare:
del foo
to
foo = None
I know in the case of del foo that the intent is to remove the variable from scope. It's not clear that foo = None is doing that. If somebody just assigned foo = None I might think it was dead code. But I instantly know what somebody who codes del foo was trying to do.
There's this part of what del does (from the Python Language Reference):
Deletion of a name removes the binding of that name from the local or global namespace
Assigning None to a name does not remove the binding of the name from the namespace.
(I suppose there could be some debate about whether removing a name binding is actually useful, but that's another question.)
One place I've found del useful is cleaning up extraneous variables in for loops:
for x in some_list:
do(x)
del x
Now you can be sure that x will be undefined if you use it outside the for loop.
Deleting a variable is different than setting it to None
Deleting variable names with del is probably something used rarely, but it is something that could not trivially be achieved without a keyword. If you can create a variable name by writing a=1, it is nice that you can theoretically undo this by deleting a.
It can make debugging easier in some cases as trying to access a deleted variable will raise an NameError.
You can delete class instance attributes
Python lets you write something like:
class A(object):
def set_a(self, a):
self.a=a
a=A()
a.set_a(3)
if hasattr(a, "a"):
print("Hallo")
If you choose to dynamically add attributes to a class instance, you certainly want to be able to undo it by writing
del a.a
There is a specific example of when you should use del (there may be others, but I know about this one off hand) when you are using sys.exc_info() to inspect an exception. This function returns a tuple, the type of exception that was raised, the message, and a traceback.
The first two values are usually sufficient to diagnose an error and act on it, but the third contains the entire call stack between where the exception was raised and where the the exception is caught. In particular, if you do something like
try:
do_evil()
except:
exc_type, exc_value, tb = sys.exc_info()
if something(exc_value):
raise
the traceback, tb ends up in the locals of the call stack, creating a circular reference that cannot be garbage collected. Thus, it is important to do:
try:
do_evil()
except:
exc_type, exc_value, tb = sys.exc_info()
del tb
if something(exc_value):
raise
to break the circular reference. In many cases where you would want to call sys.exc_info(), like with metaclass magic, the traceback is useful, so you have to make sure that you clean it up before you can possibly leave the exception handler. If you don't need the traceback, you should delete it immediately, or just do:
exc_type, exc_value = sys.exc_info()[:2]
To avoid it all together.
Just another thinking.
When debugging http applications in framework like Django, the call stack full of useless and messed up variables previously used, especially when it's a very long list, could be very painful for developers. so, at this point, namespace controlling could be useful.
Using "del" explicitly is also better practice than assigning a variable to None. If you attempt to del a variable that doesn't exist, you'll get a runtime error but if you attempt to set a variable that doesn't exist to None, Python will silently set a new variable to None, leaving the variable you wanted deleted where it was. So del will help you catch your mistakes earlier
del is often seen in __init__.py files. Any global variable that is defined in an __init__.py file is automatically "exported" (it will be included in a from module import *). One way to avoid this is to define __all__, but this can get messy and not everyone uses it.
For example, if you had code in __init__.py like
import sys
if sys.version_info < (3,):
print("Python 2 not supported")
Then your module would export the sys name. You should instead write
import sys
if sys.version_info < (3,):
print("Python 2 not supported")
del sys
To add a few points to above answers:
del x
Definition of x indicates r -> o (a reference r pointing to an object o) but del x changes r rather than o. It is an operation on the reference (pointer) to object rather than the object associated with x. Distinguishing between r and o is key here.
It removes it from locals().
Removes it from globals() if x belongs there.
Removes it from the stack frame (removes the reference physically from it, but the object itself resides in object pool and not in the stack frame).
Removes it from the current scope. It is very useful to limit the span of definition of a local variable, which otherwise can cause problems.
It is more about declaration of the name rather than definition of content.
It affects where x belongs to, not where x points to. The only physical change in memory is this. For example if x is in a dictionary or list, it (as a reference) is removed from there(and not necessarily from the object pool). In this example, the dictionary it belongs is the stack frame (locals()), which overlaps with globals().
I've found del to be useful for pseudo-manual memory management when handling large data with Numpy. For example:
for image_name in large_image_set:
large_image = io.imread(image_name)
height, width, depth = large_image.shape
large_mask = np.all(large_image == <some_condition>)
# Clear memory, make space
del large_image; gc.collect()
large_processed_image = np.zeros((height, width, depth))
large_processed_image[large_mask] = (new_value)
io.imsave("processed_image.png", large_processed_image)
# Clear memory, make space
del large_mask, large_processed_image; gc.collect()
This can be the difference between bringing a script to a grinding halt as the system swaps like mad when the Python GC can't keep up, and it running perfectly smooth below a loose memory threshold that leaves plenty of headroom to use the machine to browse and code while it's working.
Force closing a file after using numpy.load:
A niche usage perhaps but I found it useful when using numpy.load to read a file. Every once in a while I would update the file and need to copy a file with the same name to the directory.
I used del to release the file and allow me to copy in the new file.
Note I want to avoid the with context manager as I was playing around with plots on the command line and didn't want to be pressing tab a lot!
See this question.
I would like to elaborate on the accepted answer to highlight the nuance between setting a variable to None versus removing it with del:
Given the variable foo = 'bar', and the following function definition:
def test_var(var):
if var:
print('variable tested true')
else:
print('variable tested false')
Once initially declared, test_var(foo) yields variable tested true as expected.
Now try:
foo = None
test_var(foo)
which yields variable tested false.
Contrast this behavior with:
del foo
test_var(foo)
which now raises NameError: name 'foo' is not defined.
As an example of what del can be used for, I find it useful i situations like this:
def f(a, b, c=3):
return '{} {} {}'.format(a, b, c)
def g(**kwargs):
if 'c' in kwargs and kwargs['c'] is None:
del kwargs['c']
return f(**kwargs)
# g(a=1, b=2, c=None) === '1 2 3'
# g(a=1, b=2) === '1 2 3'
# g(a=1, b=2, c=4) === '1 2 4'
These two functions can be in different packages/modules and the programmer doesn't need to know what default value argument c in f actually have. So by using kwargs in combination with del you can say "I want the default value on c" by setting it to None (or in this case also leave it).
You could do the same thing with something like:
def g(a, b, c=None):
kwargs = {'a': a,
'b': b}
if c is not None:
kwargs['c'] = c
return f(**kwargs)
However I find the previous example more DRY and elegant.
When is del useful in python?
You can use it to remove a single element of an array instead of the slice syntax x[i:i+1]=[]. This may be useful if for example you are in os.walk and wish to delete an element in the directory. I would not consider a keyword useful for this though, since one could just make a [].remove(index) method (the .remove method is actually search-and-remove-first-instance-of-value).
I think one of the reasons that del has its own syntax is that replacing it with a function might be hard in certain cases given it operates on the binding or variable and not the value it references. Thus if a function version of del were to be created a context would need to be passed in. del foo would need to become globals().remove('foo') or locals().remove('foo') which gets messy and less readable. Still I say getting rid of del would be good given its seemingly rare use. But removing language features/flaws can be painful. Maybe python 4 will remove it :)
The "del" command is very useful for controlling data in an array, for example:
elements = ["A", "B", "C", "D"]
# Remove first element.
del elements[:1]
print(elements)
Output:
['B', 'C', 'D']
del deletes the binding of the variable and its object that it points to.
>>> a = ['a', 'b', 'c']
>>> b = a
>>> del a
>>> b
['a', 'b', 'c']
>>> a
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'a' is not defined
A simple use case I can think of would be in case you have used a built-in function name as a variable, and you want to use that function after it has been already "overridden" by your variable name.
t = ('a', "letter")
value, type = t
print(value, type)
del type
print(type(value))
Output:
a letter
<class 'str'>
Yet another niche usage:
In pyroot with ROOT5 or ROOT6, "del" may be useful to remove a python object that referred to a no-longer existing C++ object. This allows the dynamic lookup of pyroot to find an identically-named C++ object and bind it to the python name. So you can have a scenario such as:
import ROOT as R
input_file = R.TFile('inputs/___my_file_name___.root')
tree = input_file.Get('r')
tree.Draw('hy>>hh(10,0,5)')
R.gPad.Close()
R.hy # shows that hy is still available. It can even be redrawn at this stage.
tree.Draw('hy>>hh(3,0,3)') # overwrites the C++ object in ROOT's namespace
R.hy # shows that R.hy is None, since the C++ object it pointed to is gone
del R.hy
R.hy # now finds the new C++ object
Hopefully, this niche will be closed with ROOT7's saner object management.
del is removing the variable from the current scope unless it is re-initialized. Setting it to None keeps it in the current scope.
a = "python string"
print(a)
del a
print(a)
a = "new python string"
print(a)
Output:
python string
Traceback (most recent call last):
File "testing.py", line 4, in <module>
print(a)
NameError: name 'a' is not defined
As I have not seen a interactive console answer, I'll be showing one.
When foo=None that reference and the object exist, it's not pointing to it.
While del foo destroys the object and reference too.
So if you do something like this if foo is None and it was deleted it will rise NameError as the the reference, it's object and everything in between was deleted with del
Deletion of a target list recursively deletes each target, from left to right.
Meanwhile foo=None is just a reference pointing to None so the reference is still kicking, same for the object.
[...]In Python, variables are references to objects and any variable can reference any object[...]
Link to quote 1
Link to quote 2
Another niche case, but useful.
from getpass import getpass
pass = getpass()
token = get_auth_token(pass)
del pass
# Assume more code here...
After the deletion of the pass variable, you don't run the risk of it being printed out later by mistake, or otherwise ending up in a log or stack trace.
Here goes my 2 cents contribution:
I have a optimization problem where I use a Nlopt library for it.
I initializing the class and some of its methods, I was using in several other parts of the code.
I was having ramdom results even if applying the same numerical problem.
I just realized that by doing it, some spurius data was contained in the object when it should have no issues at all. After using del, I guess the memory is being properly cleared and it might be an internal issue to that class where some variables might not be liking to be reused without proper constructor.
Once I had to use:
del serial
serial = None
because using only:
serial = None
didn't release the serial port fast enough to immediately open it again.
From that lesson I learned that del really meant: "GC this NOW! and wait until it's done" and that is really useful in a lot of situations. Of course, you may have a system.gc.del_this_and_wait_balbalbalba(obj).
del is the equivalent of "unset" in many languages
and as a cross reference point moving from another language to python..
people tend to look for commands that do the same thing that they used to do in their first language...
also
setting a var to "" or none doesn't really remove the var from scope..it just empties its value
the name of the var itself would still be stored in memory...why?!?
in a memory intensive script..keeping trash behind its just a no no
and anyways...every language out there has some form of an "unset/delete" var function..why not python?

Restoring variables from outer scope to previous values if an exception occur

Is it possible to call a function in a kind of protected environment with the following feature: if calling function f raises an exception, then make sure all (outer) variables are restored to their previous values.
For instance, the following code:
a = 42
def f():
global a
a += 1
error
f()
will obviously set a to 43 before raising the exception. I would like to build some try/except structure for calling f() where the exception would restore local variables to their previous state.
Of course I thought to something related to sys._getframe(1).f_locals. Is it possible? Would it be portable accross different versions of Python? etc.
No major goal right now; just curious about that idea.
Short answer is no, there's no snapshot feature to these executions and thus no way of reverting the variables.
However there are some things you can do. One of them being:
(And I'm writing this as I go so this will be resource exhausting way to solve your problem if you use it on large variables.)
from pickle import load, dump
def snapshot(v):
with open('snapshot.bin', 'wb') as fh:
dump(v, fh)
def restore():
with open('snapshot.bin', 'rb') as fh:
v = load(fh)
return v
a = 42
snapshot(a)
def f():
global a
a += 1
error
try:
f()
except:
a = restore()
If this were a class with initated values, you could also snapshot the entire class or peak inside it and pull out certain variables. But there's no way to automatically do these things for you.
Of course this requires you to know a head of time what variables will be affected, I'm not sure there is a way to "peak inside" a function and see what variable names will be used, and even then you'd have to use a traceback call to see on which row your got the error and restored based on that.
One way I would solve it, is to store all my critical variables in a dictionary and snapshot branches of that dictionary or the entire dictionary itself.

How to get gobject.idle_add() to pass a parameter by reference?

I have two threads in my PyGTK app:
the main thread which runs the GTK loop and does all the GUI stuff
another thread which handles network requests, etc.
I need to have the second thread get some information from the first thread, so I call:
variable = None
gobject.idle_add( function_in_main_thread, variable )
In the main thread I have:
def function_in_main_thread( variable ):
variable = 1
The problem is that the variable in the second thread never gets set. It's value remains at None. So how can I get the main thread to actually modify the variable in the other thread?
Note: I have some thread synchronization code in the script in case anyone is concerned about modifying variables in other threads. I omitted it from this example because I felt it really didn't apply to the real issue.
In Python, assignment always creates the name in the current scope. The name you pass is indeed a reference to the variable you've created, but the assignment operator will try to find it in the current scope and, if it's not there, create it.
>>> def assign_to(name, value):
... name = value
...
>>> name = "nothing"
>>> assign_to(name, 5)
>>> name
'nothing'
You can instead pass a reference to some kind of instance, a type or maybe even a list, and then use some method of that instance.
>>> def append_to_list(my_list, value):
... my_list.append(value)
...
>>> my_list = []
>>> append_to_list(my_list, 5)
>>> my_list
[5]
The list could of course equally be just an empty object with a "value" member.
In short, if you want to do something akin to call by reference, avoid the assignment operator. Use some kind of method of the object instead.
There's a neat, and surprisingly terse guide to Python Namespaces by Shrutarshi Basu, in case you want to dig deeper. In order to understand what the assignment operator is doing, check out wp: Name Binding. It also explains why the assignment operator can't be overloaded in Python.
Also, as you pointed out, you need to call gobject.threads_init()

How can one create new scopes in python

In many languages (and places) there is a nice practice of creating local scopes by creating a block like this.
void foo()
{
... Do some stuff ...
if(TRUE)
{
char a;
int b;
... Do some more stuff ...
}
... Do even more stuff ...
}
How can I implement this in python without getting the unexpected indent error and without using some sort of if True: tricks
Why do you want to create new scopes in python anyway?
The normal reason for doing it in other languages is variable scoping, but that doesn't happen in python.
if True:
a = 10
print a
In Python, scoping is of three types : global, local and class. You can create specialized 'scope' dictionaries to pass to exec / eval(). In addition you can use nested scopes
(defining a function within another). I found these to be sufficient in all my code.
As Douglas Leeder said already, the main reason to use it in other languages is variable scoping and that doesn't really happen in Python. In addition, Python is the most readable language I have ever used. It would go against the grain of readability to do something like if-true tricks (Which you say you want to avoid). In that case, I think the best bet is to refactor your code into multiple functions, or use a single scope. I think that the available scopes in Python are sufficient to cover every eventuality, so local scoping shouldn't really be necessary.
If you just want to create temp variables and let them be garbage collected right after using them, you can use
del varname
when you don't want them anymore.
If its just for aesthetics, you could use comments or extra newlines, no extra indentation, though.
Python has exactly two scopes, local and global. Variables that are used in a function are in local scope no matter what indentation level they were created at. Calling a nested function will have the effect that you're looking for.
def foo():
a = 1
def bar():
b = 2
print a, b #will print "1 2"
bar()
Still like everyone else, I have to ask you why you want to create a limited scope inside a function.
variables in list comprehension (Python 3+) and generators are local:
>>> i = 0
>>> [i+1 for i in range(10)]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> i
0
but why exactly do you need this?
A scope is a textual region of a
Python program where a namespace is
directly accessible. “Directly
accessible” here means that an
unqualified reference to a name
attempts to find the name in the
namespace...
Please, read the documentation and clarify your question.
btw, you don't need if(TRUE){} in C, a simple {} is sufficient.
As mentioned in the other answers, there is no analogous functionality in Python to creating a new scope with a block, but when writing a script or a Jupyter Notebook, I often (ab)use classes to introduce new namespaces for similar effect. For example, in a notebook where you might have a model "Foo", "Bar" etc. and related variables you might want to create a new scope to avoid having to reuse names like
model = FooModel()
optimizer = FooOptimizer()
...
model = BarModel()
optimizer = BarOptimizer()
or suffix names like
model_foo = ...
optimizer_foo = ...
model_bar = ...
optimizer_bar= ...
Instead you can introduce new namespaces with
class Foo:
model = ...
optimizer = ...
loss = ....
class Bar:
model = ...
optimizer = ...
loss = ...
and then access the variables as
Foo.model
Bar.optimizer
...
I find that using namespaces this way to create new scopes makes code more readable and less error-prone.
While the leaking scope is indeed a feature that is often useful,
I have created a package to simulate block scoping (with selective leaking of your choice, typically to get the results out) anyway.
from scoping import scoping
a = 2
with scoping():
assert(2 == a)
a = 3
b = 4
scoping.keep('b')
assert(3 == a)
assert(2 == a)
assert(4 == b)
https://pypi.org/project/scoping/
I would see this as a clear sign that it's time to create a new function and refactor the code. I can see no reason to create a new scope like that. Any reason in mind?
def a():
def b():
pass
b()
If I just want some extra indentation or am debugging, I'll use if True:
Like so, for arbitrary name t:
### at top of function / script / outer scope (maybe just big jupyter cell)
try: t
except NameError:
class t
pass
else:
raise NameError('please `del t` first')
#### Cut here -- you only need 1x of the above -- example usage below ###
t.tempone = 5 # make new temporary variable that definitely doesn't bother anything else.
# block of calls here...
t.temptwo = 'bar' # another one...
del t.tempone # you can have overlapping scopes this way
# more calls
t.tempthree = t.temptwo; del t.temptwo # done with that now too
print(t.tempthree)
# etc, etc -- any number of variables will fit into t.
### At end of outer scope, to return `t` to being 'unused'
del t
All the above could be in a function def, or just anyplace outside defs along a script.
You can add or del new elements to an arbitrary-named class like that at any point. You really only need one of these -- then manage your 'temporary' namespace as you like.
The del t statement isn't necessary if this is in a function body, but if you include it, then you can copy/paste chunks of code far apart from each other and have them work how you expect (with different uses of 't' being entirely separate, each use starting with the that try: t... block, and ending with del t).
This way if t had been used as a variable already, you'll find out, and it doesn't clobber t so you can find out what it was.
This is less error prone then using a series of random=named functions just to call them once -- since it avoids having to deal with their names, or remembering to call them after their definition, especially if you have to reorder long code.
This basically does exactly what you want: Make a temporary place to put things you know for sure won't collide with anything else, and which you are responsible for cleaning up inside as you go.
Yes, it's ugly, and probably discouraged -- you will be directed to decompose your work into a set of smaller, more reusable functions.
As others have suggested, the python way to execute code without polluting the enclosing namespace is to put it in a class or function. This presents a slight and usually harmless problem: defining the function puts its name in the enclosing namespace. If this causes harm to you, you can name your function using Python's conventional temporary variable "_":
def _():
polluting_variable = foo()
...
_() # Run the code before something overwrites the variable.
This can be done recursively as each local definition masks the definition from the enclosing scope.
This sort of thing should only be needed in very specific circumstances. An example where it is useful is when using Databricks' %run magic, which executes the contents of another notebook in the current notebook's global scope. Wrapping the child notebook's commands in temporary functions prevents them from polluting the global namespace.

Categories