Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Re: Double sided double underscored variable names

21 views
Skip to first unread message

Chris Angelico

unread,
Sep 11, 2012, 6:22:17 PM9/11/12
to pytho...@python.org
On Wed, Sep 12, 2012 at 8:09 AM, Joshua Landau
<joshua.l...@gmail.com> wrote:
> If I were to use internal double-underscored names of the form
> __BS_internalname__, would the compiled code be able to assume that no-one
> had overwritten these variables and never will, even through modification
> of, say, locals(). I ask because Python's docs seem to specify that double
> sided double underscored names are strictly for Python and its special
> names.

Interesting. If you're compiling your code to Python, you may be able
to, if necessary, adorn a user's variable name(s). I'd be inclined to
use a single underscore notation like _BS_internalname_ and then, in
the event of a collision (which would be incredibly unlikely unless
someone's fiddling), rename the offending variable to
_BS_BS_something_ - which of course you'd never yourself use. Would
that serve?

ChrisA

Chris Angelico

unread,
Sep 11, 2012, 6:52:10 PM9/11/12
to pytho...@python.org
On Wed, Sep 12, 2012 at 8:48 AM, Joshua Landau
<joshua.l...@gmail.com> wrote:
> Well, the problem is that a lot of collisions aren't predictable.
> "locals()['foo'] = 2", for example. If it weren't for Python's annoying
> flexibility* I would definitely do something very close to what you suggest.
> Remember that "locals()" isn't Python's only introspection tool. How about
> "from foo import *"?

You're not supposed to mutate locals(), but I suppose globals() works
the same way.

Inline functions? I like this idea. I tend to want them in pretty much
any language I write in.

ChrisA

Steven D'Aprano

unread,
Sep 11, 2012, 8:51:49 PM9/11/12
to
Sorry for breaking threading, but Joshua's post does not show up on my
usenet provider.

On Wed, 12 Sep 2012 08:22:17 +1000, Chris Angelico wrote:

> On Wed, Sep 12, 2012 at 8:09 AM, Joshua Landau
> <joshua.l...@gmail.com> wrote:
>>
>> If I were to use internal double-underscored names of the form
>> __BS_internalname__, would the compiled code be able to assume that
>> no-one had overwritten these variables and never will,

Certainly not. It is virtually never possible to make that assumption in
Python. Nearly everything can be shadowed at runtime.

(One exception is local variables of a function, which can only be seen
from inside that function. But you don't need to wrap local variable
names in underscores to treat them as local.)

Dunder ("Double leading and trailing UNDERscore") names are normal names
subject to the same rules as anything else in Python (with one
exception), which means you can modify them in all sorts of ways at
runtime:

py> _int = int
py> class MyInt(_int):
... def __add__(self, other):
... return 42
...
py> int = MyInt
py> a = int("10000")
py> a + 1
42
py> type(a).__add__ = lambda self, other: 23
py> a + 1
23


The one exception how dunder names are treated specially is that Python
uses a short-cut for name-lookup which means you cannot override them on
a per-instance basis like normal other attribute names.



>> even through modification of, say, locals().

Modifying locals() is an implementation detail which may not be supported.



>> I ask because Python's docs seem to
>> specify that double sided double underscored names are strictly for
>> Python and its special names.

Dunder names are reserved for use by Python's built-ins and syntax, that
is all.


> Interesting. If you're compiling your code to Python, you may be able
> to, if necessary, adorn a user's variable name(s). I'd be inclined to
> use a single underscore notation like _BS_internalname_ and then, in the
> event of a collision (which would be incredibly unlikely unless
> someone's fiddling), rename the offending variable to _BS_BS_something_
> - which of course you'd never yourself use. Would that serve?

This seems to be a mere extension of the name-mangling that occurs with
leading-only double-underscore attributes like self.__spam. This can be a
right PITA at times, and offers so little protection that it isn't
worthwhile. __names only protect against *accidental* name collisions,
and not all of those.


--
Steven

Steven D'Aprano

unread,
Sep 11, 2012, 9:14:16 PM9/11/12
to
And again, Joshua's original post is not available from my provider.
Joshua, I suspect that something about your post is being seen as spam
and dropped by at least some providers.


On Wed, 12 Sep 2012 08:52:10 +1000, Chris Angelico wrote:

> On Wed, Sep 12, 2012 at 8:48 AM, Joshua Landau
> <joshua.l...@gmail.com> wrote:
>>
>> Well, the problem is that a lot of collisions aren't predictable.
>> "locals()['foo'] = 2", for example. If it weren't for Python's annoying
>> flexibility*

I can't see your footnote there, so you may have already covered this,
but for the record, what you call Python's "annoying flexibility" is
fundamental to Python's programming model and done so for good reasons.
The ability to shadow built-ins is, at times, incredibly useful rather
than annoying.

The world is full of bondage and domination languages that strongly
restrict what you can do. Python doesn't need to be another one of them.
Python's optimizing compiler, PyPy, is able to optimize code very well
without such restrictions.


>> I would definitely do something very close to what you
>> suggest. Remember that "locals()" isn't Python's only introspection
>> tool. How about "from foo import *"?

I wouldn't call "import *" an introspection tool. At least, no more so
than print.


> You're not supposed to mutate locals(),

It's not so much you're not allowed to do it, but that the result of
making changes to locals() inside a function is implementation dependent:

CPython 2: writing to the dict returned by locals() will work, but the
changes will not be reflected in the actual local variables, except under
very restricted circumstances;

CPython 3: those restricted circumstances that allowed writes to locals()
to modify local variables are now SyntaxErrors;

Stackless: presumably the exact same behaviour as CPython (since
Stackless is a fork, not a re-implementation);

Jython: the same as CPython;

IronPython: writes to locals() will modify the corresponding local
variable.


Outside of a function, locals() returns globals() and writes will always
modify the global variable (this is a language guarantee).

> but I suppose globals() works the same way.
>
> Inline functions? I like this idea. I tend to want them in pretty much
> any language I write in.

What do you mean by in-line functions? If you mean what you literally
say, I would answer that Python has that with lambda.

But I guess you probably mean something more like macros.


--
Steven

Chris Angelico

unread,
Sep 12, 2012, 12:12:20 AM9/12/12
to pytho...@python.org
On Wed, Sep 12, 2012 at 11:38 AM, Joshua Landau
<joshua.l...@gmail.com> wrote:
> On 12 September 2012 02:14, Steven D'Aprano
> <steve+comp....@pearwood.info> wrote:
>>
>> And again, Joshua's original post is not available from my provider.
>> Joshua, I suspect that something about your post is being seen as spam
>> and dropped by at least some providers.
>
> I am sorry to ask this, but in the meantime can someone who isn't
> spam-filtered repost my messages? I'll give them a cookie!
> To repeat my previous post, I'm using GMail and posting to
> pytho...@python.org. If that is what I'm meant to be doing, I'll try
> another email address.

Mailing to python-list@python from Gmail is exactly what I do, and far
as I know, none of my posts are getting lost. But then, I'm seeing all
your posts, too, so maybe I just don't know when my posts don't go
through.
> No, just multi-line lambda. Macros, if my knowledge of lower-level languages
> is valid, would be sorta' silly in Python.

Ah, okay. I was thinking more along the lines of what you call macros,
but in the C++ sense of inline functions. In C, macros are handled at
precompilation stage, and are dangerous. Classic example:

#define squared(x) x*x

x_squared = squared(6+7)

So your macros end up littered with parentheses, and it still doesn't
solve anything, as the argument still gets evaluated twice. (A problem
if it has side effects - eg if it's a function call.)

What I'm thinking of, though, is like C++ functions. You can put the
'inline' keyword onto any function, and the compiler will do its best
to inline it (in fact, a good optimizing compiler will inline things
regardless, but that's a separate point). I can write:

inline int squared(int x) {return x*x;}

and C++ will add no function overhead, but will still do all the
proper evaluation order etc.

Of course, C++ doesn't allow monkeypatching, so you'll never have
semantic differences from inlining. It's just a performance question.
But I use inline functions like constants - for instance, I could
create a function that converts a database ID into an internal
reference number, and I can change the definition of that function in
one place and have it apply everywhere, just like if I wanted to
change the definition of math.PI to 3.142857 for fun one day. Of
course I can use a normal (out-of-line) function for this, but that
has overhead in most languages. Hence, wanting inline functions.

ChrisA

Joshua Landau

unread,
Sep 12, 2012, 5:55:58 AM9/12/12
to Chris Angelico, pytho...@python.org
On 12/09/2012, Chris Angelico <ros...@gmail.com> wrote:
> On Wed, Sep 12, 2012 at 11:38 AM, Joshua Landau
> <joshua.l...@gmail.com> wrote:
>> On 12 September 2012 02:14, Steven D'Aprano
>> <steve+comp....@pearwood.info> wrote:
>>>
Interesting. I'd overestimated macros and underestimated inline functions.

I am not sure how to make a version of that with scope-compatibility. Inlining
inline_def f(y): x = y +1
would hopefully not change the outside scope*, but I'm not sure how to
make that.

I could make it work by banning "=", but then it's almost a macro but with
internal_a = input_a
internal_b = input_b
...
at the start...

* If I understand rightly
0 new messages