Inaccessible variables in Python

when you code in many languages, you usually need to dig a bit to find answers to questions that are not immediately obvious in a specific language. Mine was whether closures can simulate real private variables in python (i.e that really can’t be accessed as opposed to the __ mangling method).

I decided to test if this would work with closures, as shown below

def outer(a,b):
    class this:
        pass
    
    #--------------------------
    # real private variables and methods go here
    this.a = a
    this.b = b
    
    def sum_():
        return this.a + this.b
    
    def product_():
        return this.a * this.b
    
    def set_nums_(a, b):
        this.a, this.b = a, b
    
    #--------------------------
    # public variables and methods go here
    class inner:
        def get_nums(self):
            return this.a, this.b
        
        def set_nums(self, a, b):
            set_nums_(a,b)
        
        def sum(self):
            return sum_()
        
        def product(self):
            return product_()
    
    return inner()

and the result:

>>> x = outer(5,3)
>>> x.get_nums()
(5, 3)
>>> x.set_nums(5,4)
>>> x.get_nums()
(5, 4)
>>> x.product()
20
>>> x
<__main__.outer..inner object at 0x0000023C581E21C0>
>>>

Yay! seems like it works.

Of course, a bit of further digging showed that every python object has the __closure__ property through which you can access the closure for that object, and changing the values of the “private” variables above (bypassing the set_nums method) just becomes a matter of:

>>> loophole = x.sum.__closure__[0].cell_contents.__closure__[0].cell_contents
>>> loophole
<class '__main__.outer.<locals>.this'>
>>> loophole.a = 8
>>> loophole.b = 9
>>> x.get_nums()
(8, 9)
>>>

Leave a Reply

Your email address will not be published.