Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #101370 > unrolled thread

Unable to access module attribute with underscores in class method, Python 3

Started byJoseph Fox-Rabinovitz <jfoxrabinovitz@gmail.com>
First post2016-01-07 11:14 -0500
Last post2016-01-09 12:25 +1100
Articles 4 — 3 participants

Back to article view | Back to comp.lang.python


Contents

  Unable to access module attribute with underscores in class method, Python 3 Joseph Fox-Rabinovitz <jfoxrabinovitz@gmail.com> - 2016-01-07 11:14 -0500
    Re: Unable to access module attribute with underscores in class method, Python 3 Steven D'Aprano <steve@pearwood.info> - 2016-01-09 03:07 +1100
      Re: Unable to access module attribute with underscores in class method, Python 3 Chris Angelico <rosuav@gmail.com> - 2016-01-09 03:16 +1100
        Re: Unable to access module attribute with underscores in class method, Python 3 Steven D'Aprano <steve@pearwood.info> - 2016-01-09 12:25 +1100

#101370 — Unable to access module attribute with underscores in class method, Python 3

FromJoseph Fox-Rabinovitz <jfoxrabinovitz@gmail.com>
Date2016-01-07 11:14 -0500
SubjectUnable to access module attribute with underscores in class method, Python 3
Message-ID<mailman.62.1452258624.2305.python-list@python.org>
Hi,

I have a module attribute whose name starts with a pair of underscores. I
am apparently unable to access it directly in a class method (within the
same module, but that is not relevant as far as I can tell). The following
bit of code illustrates the situation:

__a = 3
class B:
    def __init__(self):
        global __a
        self.a = __a
b = B()

This results in a NameError because of name-mangling, despite the global
declaration:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 4, in __init__
NameError: name '_B__a' is not defined

Not using global does not make a difference. I posted a similar question on
Stack Overflow, where the only reasonable answer given was to wrap __a in a
container whose name is not mangled. For example, doing `self.a =
globals()['__a']` or manually creating a dictionary with a non-mangled name
and accessing that.

I feel that there should be some way of accessing __a within the class
directly in Python 3. Clearly my expectation that global would fix the
issue is incorrect. I would appreciate either a solution or an explanation
of what is going on that would convince me that accessing a module
attribute in such a way should be forbidden.

    -Joseph Fox-Rabinovitz

P.S. For reference, the Stack Overflow question is here:
http://stackoverflow.com/questions/34621484/how-to-access-private-variable-of-python-module-from-class

[toc] | [next] | [standalone]


#101381

FromSteven D'Aprano <steve@pearwood.info>
Date2016-01-09 03:07 +1100
Message-ID<568fded7$0$1608$c3e8da3$5496439d@news.astraweb.com>
In reply to#101370
On Fri, 8 Jan 2016 03:14 am, Joseph Fox-Rabinovitz wrote:

> Hi,
> 
> I have a module attribute whose name starts with a pair of underscores.

Don't do that.

The way to flag a module-level variable as private is with a single leading
underscore. Double-leading underscores are intended for use in classes, to
be name-mangled, and double-leading-and-trailing underscores are reserved
for use by Python.


> I am apparently unable to access it directly in a class method (within the
> same module, but that is not relevant as far as I can tell). The following
> bit of code illustrates the situation:
> 
> __a = 3
> class B:
>     def __init__(self):
>         global __a
>         self.a = __a
> b = B()
> 
> This results in a NameError because of name-mangling, despite the global
> declaration:

The global declaration is name-mangled as well, as can be seen from the
byte-code:


py> from dis import dis
py> class Test:
...     def method(self):
...             global __a
...             x = __a
...
py> dis(Test.method)
  4           0 LOAD_GLOBAL              0 (_Test__a)
              3 STORE_FAST               1 (x)
              6 LOAD_CONST               0 (None)
              9 RETURN_VALUE


That's exactly as described: within a class, ALL references to
double-leading underscore names are mangled.


> Not using global does not make a difference. I posted a similar question
> on Stack Overflow, where the only reasonable answer given was to wrap __a
> in a container whose name is not mangled. 

That's not a reasonable answer. That's adding unreasonable complication to
the code, just to support an unreasonable global name.


> For example, doing `self.a = 
> globals()['__a']` or manually creating a dictionary with a non-mangled
> name and accessing that.
> 
> I feel that there should be some way of accessing __a within the class
> directly in Python 3. Clearly my expectation that global would fix the
> issue is incorrect. I would appreciate either a solution or an explanation
> of what is going on that would convince me that accessing a module
> attribute in such a way should be forbidden.

You are trying to fight the language. __names are intended for a specific
use in Python, and you're ignoring that and trying to use them for
something else. That's fine so long as your use and the intended use don't
clash, but if they do clash (as they are here) then there's only one
reasonable answer: stop abusing name-mangled names.

If you absolutely insist that you must must must continue to use a double
underscore name, you could also try this:

py> __a = 1
py> class Test:
...     def method(self):
...             x = eval("__a")
...             print(x)
...
py> Test().method()
1


But don't do that.



-- 
Steven

[toc] | [prev] | [next] | [standalone]


#101382

FromChris Angelico <rosuav@gmail.com>
Date2016-01-09 03:16 +1100
Message-ID<mailman.74.1452269803.2305.python-list@python.org>
In reply to#101381
On Sat, Jan 9, 2016 at 3:07 AM, Steven D'Aprano <steve@pearwood.info> wrote:
> If you absolutely insist that you must must must continue to use a double
> underscore name, you could also try this:
>
> py> __a = 1
> py> class Test:
> ...     def method(self):
> ...             x = eval("__a")
> ...             print(x)
> ...
> py> Test().method()
> 1
>
>
> But don't do that.

Seriously? You consider that less bad than globals()["__a"]?

But all of this is craziness to support craziness. It's not asking
which inmate should run the asylum - it's asking which of my multiple
personalities should be elected fourteen-year-old queen.

ChrisA

[toc] | [prev] | [next] | [standalone]


#101399

FromSteven D'Aprano <steve@pearwood.info>
Date2016-01-09 12:25 +1100
Message-ID<5690617b$0$1583$c3e8da3$5496439d@news.astraweb.com>
In reply to#101382
On Sat, 9 Jan 2016 03:16 am, Chris Angelico wrote:

> On Sat, Jan 9, 2016 at 3:07 AM, Steven D'Aprano <steve@pearwood.info>
> wrote:
>> If you absolutely insist that you must must must continue to use a double
>> underscore name, you could also try this:
>>
>> py> __a = 1
>> py> class Test:
>> ...     def method(self):
>> ...             x = eval("__a")
>> ...             print(x)
>> ...
>> py> Test().method()
>> 1
>>
>>
>> But don't do that.
> 
> Seriously? You consider that less bad than globals()["__a"]?

No. That's why I said "don't do that" rather than "you should do this" :-)


> But all of this is craziness to support craziness. It's not asking
> which inmate should run the asylum - it's asking which of my multiple
> personalities should be elected fourteen-year-old queen.

Loretta, surely.




-- 
Steven

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.python


csiph-web