apramc
apramc

Reputation: 1386

Does python optimize unused variables out?

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

Answers (3)

Daniel Pryden
Daniel Pryden

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

wim
wim

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

hiro protagonist
hiro protagonist

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

Related Questions