-3

Difficulty in understanding mangling mechanism in Python

bank.__balance = "abcdefg"

works but using

bank._Atm__balance = "wgwwg"

is throwing an error

  • the error was that I was adding int with str

  • but what I'm not able to understand is it got passed on for bank.__balance but throw an error for bank._Atm__balance

  • 2
    It’s nothing to do with the variable being “private”. Look at the exception (it’s not a “crash” like in a C program, you have an actual error message that tells you what went wrong). You set the `__balance` attribute to a string and your code expects it to be an int. – Samwise Jul 09 '23 at 07:06
  • Notice that it didn’t throw the error while trying to *set* those values, but on a subsequent operation. And you have pretty much explained the name mangling mechanism already, so it should be clear why the two are different and even what they do‽ – deceze Jul 09 '23 at 07:23
  • If the mangling function made those changes, I wouldnt be using it. – Rohit Gupta Jul 12 '23 at 03:30
  • 1
    I was reviewing your question from the "reopen queue", but now you edited too much. Your MCVE cannot be run and does not show the error. If you want your question reopened, make a small Python script that actually displays the error when it is run. – giusti Jul 27 '23 at 01:19

1 Answers1

2

First, note that Python's lack of private methods is deliberate. The language has a "we're all consenting adults here" attitude, so encapsulation is not enforced by the compiler. That's why internal methods and attributes are usually marked only with a single underscore.

Second, when you do

sbi.__balance = "abcdefg"

You're not setting the balance, but creating a new attribute. That's why the code doesn't crash. When you use the mangled name, then you're actually changing the value.

But you're changing it to a string, so it crashes when it tries to perform a numeric operation.


Here's an example showing how new attributes can be added to an existing object, and how mangled names can be changed only by referring to the mangled version.

class MyClass:
    public = 'this is public'
    _internal = 'this is internal'
    __mangled = 'this is mangled'

def print_attributes(obj):
    """ Prints all declared attributes in the given object. """
    print([att for att in reversed(dir(obj)) if not att.endswith('__')])

instance = MyClass()
print_attributes(instance)
# ['_MyClass__mangled', '_internal', 'public']
# The class starts with those three attributes.

instance.public = 'new value'
print_attributes(instance)
# ['_MyClass__mangled', '_internal', 'public']
# We change the value of `public`.

instance._MyClass__mangled = 'new value'
print_attributes(instance)
# ['public', '_internal', '_MyClass__mangled']
# We change the value of the mangled attribute. Note the name used.

instance.__mangled = 'new value'
print_attributes(instance)
# ['public', '_internal', '__mangled', '_MyClass__mangled']
# If you try to change the mangled value by using `__mangled`, a new attribute is created instead.
BoppreH
  • 8,014
  • 4
  • 34
  • 71