Reputation: 1386
my linter constantly bugs me with unused variable warning, for the following class that I have created:
class LockGuard(object):
def __init__(self, mutex):
self.mutex = mutex
self.mutex.acquire()
def __del__(self):
self.mutex.release()
in code, I get the warning everytime I use this
def do_something(self)
locker = LockGuard(self.mutex)
// do something on the data
return outcome
I know that c++ compilers optimize unused variables out, I was wondering if python ever does the same? Therefore remove the lock on data.
Upvotes: 4
Views: 1343
Reputation: 60947
You are misusing the __del__
method.
See the huge warning block in the documentation for object.__del__
:
Warning: Due to the precarious circumstances under which
__del__()
methods are invoked, [...]. In particular:
__del__()
can be invoked when arbitrary code is being executed, including from any arbitrary thread. If__del__()
needs to take a lock or invoke any other blocking resource, it may deadlock as the resource may already be taken by the code that gets interrupted to execute__del__()
. (emphasis mine)__del__()
can be executed during interpreter shutdown. [...]
The correct solution is to implement a context manager and use the with
statement to enter and exit it.
Upvotes: 5
Reputation: 362557
The linter should bug you about this. Because the correct way to manage context is with a context manager.
with LockGuard():
# do stuff
Put the implementation details of how to acquire and release a lock into LockGuard.__enter__
and LockGuard.__exit__
respectively.
You should not rely on __init__
and __del__
for this, because __del__
is not reliable.
I know that C++ compilers optimize unused variables out, I was wondering if Python ever does the same? Therefore remove the lock on data.
Python will not do the same. There are some peephole optimizations, but nothing so drastic as removing an object from scope entirely. Once the reference count of an instance falls to zero (i.e. once locker
name goes out of scope), it should be deleted, but there is no guarantee in the implementation about when this happens and there is not even a guarantee that a custom __del__
will be called at all.
Upvotes: 10
Reputation: 46849
for this simple function
def f():
a = 3
the answer is no: no optimization; disassembling with
from dis import dis
dis(f)
gives:
6 0 LOAD_CONST 1 (3)
3 STORE_FAST 0 (a)
6 LOAD_CONST 0 (None)
9 RETURN_VALUE
so a
is assigned (...and then not used in any way). you can check that for your code; i'm pretty sure it will be the same.
on how to fix your code: i agree with this answer.
Upvotes: 3