private variables/methods

C

Christopher Koppler

Sean Ross wrote:
...

Just like any other import, it binds the name to a module object -- except
that it specifically binds said name to the module containing the function
that executes this import statement. The use case is: deprecating the
global statement. Setting a global variable would instead use:
import __current_module__
__current_module__.thevariable = 23

Hmmm, asking naively: why not make global (or some better name, I
don't have any good ideas however) the self of the current module -
i.e. instead of

def fun():
global x
x = somevalue

or your import, you'd use

def fun():
global.x = somevalue

And every module would set it's __global__ to itself by default...


Just a naive idea, of course...
 
B

Bengt Richter

Harri Pesonen wrote:
... [...]
One thing I have noticed that the keyword "global" is very confusing.

You are right. It would be better if the current module could be
imported -- by using some reserved special module name in a
perfectly ordinary 'import' instruction -- so that global variables
could then be re-bound as attributes of this module.

Just to give you an idea, in today's Python you could add this
feature as:

# part to be executed once, e.g. in site.py
import __builtin__, sys
_base_import = __builtin__.__import__
def __import__(name, *args):
if name == '__current_module__':
name = sys._getframe(1).f_globals['__name__']
return _base_import(name, *args)
__builtin__.__import__ = __import__
# end of part to be executed once

# example use
x = 23

def set_the_global():
import __current_module__
__current_module__.x = 45

print x
set_the_global()
print x


emits
23
45
For example, the following is syntactically valid Python:

a = 1
def b():
a = 2
def c():
return a

But it does not work as expected. Function b just creates a new local
variable "a" inside function b! The correct function is of course:

def b():
global a
a = 2

On the other hand, function c refers to the same global variable just
fine without any extra "global" keyword. Why on earth?? :) In every

Because reading is different from writing. Reading globals is (more or
less) all right; writing globals is a delicate decision that is well worth
emphasizing. So, anything that's written (any name that's re-bound,
to be precise) is deemed to be local -- unless explicitly mentioned in
a global statement.

The problem with global is that it's not clear enough. If there simply
was NO way at all to have any assignment to a bare name, such
as "a=2", EVER affect anything BUT a local, things would be much
clearer; the need to import __current_module__ would emphasize what
a serious, think-twice-about-it decision it is to choose to rebind
module-global names. It would also emphasize that 'global' means
'of this module', not in any way of ALL modules -- a misconception
that often affects newbies.

Hmmm -- maybe THIS is worth proposing for 2.4 (with a
pending deprecation warning for the global statement)...
other language I know you don't need "global". It is ugly.

Problem is, it's not quite ugly enough (nor quite clear enough).
Discouraging you from affecting globals is a swell idea, but I
think the 'global' statement may not be enough for that, whence
my newly conceived suggestion about importing...
Hm, since one way or another you have to tell the compiler you want to
rebind a global, I think maybe the situation could be normalized by
requiring the global name to pre-exist if it is to be rebound from within a function.
then we could change the 'global' keyword, and have a new one instead: 'external'

The idea is to generalize this to any names that are visible at compile time in eclosing scopes ;-)
I think requring pre-existence and visibility at compile time could make it work. Thus

g=123
def foo():
external: g
nested = 456
def bar():
external: nested
g = 'no effect on global 123, just local, only nested is external here'
nested = 789
bar() # nested becomes 789
g = nested # g becomes 789

I don't think it would be a good idea to waive the requirement for pre-existence and
visibility for where that currently works with 'global:' (i.e., defaulting to current
'global:' logic when the declared name is not visible) even though you could.
Best to avoid the kind of silent bugs that would come from misspelled names
in external declarations.

Only allowing 'external' inside a function would emphasize that it only reaches the
file global scope at most, not a universal global space. Requiring pre-existence would generate
errors if someone mistakenly thought they could rebind another module's global names
with an unqualified name by e.g. importing *, whose results wouldn't be visible at compile time.

My .02 ;-)

Regards,
Bengt Richter
 
D

Dennis Lee Bieber

Alex Martelli fed this fish to the penguins on Sunday 12 October 2003
15:01 pm:

i.e., they're there, but are not currently popular -- something
popular would be praised, not called names;-).
Depends on who's doing the coding <G> (I'll have to confess that I do
take advantage of the implicit integer range when coding do loops...
having to declare I,J,K, IX, JINX, or LYNX <G> at the top of a long
file just because they are used in a 10 line loop is a pain...

--
 
H

Harri Pesonen

Christopher said:
Hmmm, asking naively: why not make global (or some better name, I
don't have any good ideas however) the self of the current module -
i.e. instead of

def fun():
global x
x = somevalue

or your import, you'd use

def fun():
global.x = somevalue

And every module would set it's __global__ to itself by default...

Just a naive idea, of course...

Sounds good to me. So if you have now

a = 1
def b():
a = 2

This would cause a compiler warning that a global "a" already exists. So
the programmer should write either

def b():
global.a = 2

or

def b():
local.a = 2

The latter of course creates a new local variable with the same name.
After this it is OK to use just "a" without "local" prefix?

def b():
local.a = 2
a = 3

How about the following:

def b():
global.a = 2
a = 3

Is the second "a" still global?

The idea with "Option Explicit" gets around this differently. The
following creates a new local variable:

def b():
var a = 2

While the following refers to the global variable, if there is no local
variable with the same name:

def b():
a = 2

This would be more beautiful.

Harri
 
S

Sean Ross

Christopher:

Hi.
You couldn't use "global" that way for backwards compatability reasons.
Still, I like the overall idea.

[snip]
Sounds good to me. So if you have now

a = 1
def b():
a = 2

This would cause a compiler warning that a global "a" already exists.


Harri:

Hi.
Actually, I don't think that is what's intended. Rather, if you want to use
the global variable a, you will need to access it through the current module
object, which can be referenced using global, i.e.,

a = 1
def b():
global.a = 2 # rebinds the global variable a
a = 3 # binds a new local variable a, the global variable a is
unaffected.
print "a values: global = %s; local = %s"%(global.a, a)

#output
a values: global = 2; local = 3

the local and global variables a will not be confused, because the global
variable a can only ever be referenced in the local scope via the current
module reference ("global"). Meaning, if you want to use a global variable
in a scope other than at the module level , you'll have to preface it with
"global.".
So
the programmer should write either

def b():
global.a = 2

or

def b():
local.a = 2

The latter of course creates a new local variable with the same name.
After this it is OK to use just "a" without "local" prefix?

def b():
local.a = 2
a = 3

So, continuing from the explanation above, you will not have to say "local.a
= 2" to bind a local variable. All variables will be local by default.
Variables from other namespaces (such as globals) will have to be explicitly
resolved (e.g. "global.a = 2")
How about the following:

def b():
global.a = 2
a = 3

Is the second "a" still global?

No.

The idea with "Option Explicit" gets around this differently. The
following creates a new local variable:

def b():
var a = 2

While the following refers to the global variable, if there is no local
variable with the same name:

def b():
a = 2

This would be more beautiful.

Making a variable local by default, and requiring that globals be accessed
explicitly seems like a better path to me. As far as I know, the use of
globals is generally discouraged. So a lot of people try to avoid using them
in code, when they can. But local variables occur all the time. Using
"Option Explicit" would seem to be making you write more code for something
that happens more often (local variable binding), and less code for
something that is discouraged and should be happening less often (global
variable rebinding). But maybe thats just me...

Sean
 
H

Harri Pesonen

Sean said:
Christopher:

Hi.
You couldn't use "global" that way for backwards compatability reasons.
Still, I like the overall idea.

[snip]
Sounds good to me. So if you have now

a = 1
def b():
a = 2

This would cause a compiler warning that a global "a" already exists.

Harri:

Hi.
Actually, I don't think that is what's intended. Rather, if you want to use
the global variable a, you will need to access it through the current module
object, which can be referenced using global, i.e.,

a = 1
def b():
global.a = 2 # rebinds the global variable a
a = 3 # binds a new local variable a, the global variable a is
unaffected.
print "a values: global = %s; local = %s"%(global.a, a)

#output
a values: global = 2; local = 3

the local and global variables a will not be confused, because the global
variable a can only ever be referenced in the local scope via the current
module reference ("global"). Meaning, if you want to use a global variable
in a scope other than at the module level , you'll have to preface it with
"global.".
So
the programmer should write either

def b():
global.a = 2

or

def b():
local.a = 2

The latter of course creates a new local variable with the same name.
After this it is OK to use just "a" without "local" prefix?

def b():
local.a = 2
a = 3

So, continuing from the explanation above, you will not have to say "local.a
= 2" to bind a local variable. All variables will be local by default.
Variables from other namespaces (such as globals) will have to be explicitly
resolved (e.g. "global.a = 2")
How about the following:

def b():
global.a = 2
a = 3

Is the second "a" still global?
No.

The idea with "Option Explicit" gets around this differently. The
following creates a new local variable:

def b():
var a = 2

While the following refers to the global variable, if there is no local
variable with the same name:

def b():
a = 2

This would be more beautiful.

Making a variable local by default, and requiring that globals be accessed
explicitly seems like a better path to me. As far as I know, the use of
globals is generally discouraged. So a lot of people try to avoid using them
in code, when they can. But local variables occur all the time. Using
"Option Explicit" would seem to be making you write more code for something
that happens more often (local variable binding), and less code for
something that is discouraged and should be happening less often (global
variable rebinding). But maybe thats just me...

I agree with you. But the original problem (at least mine) was that the
following code has a bug that the compiler could easily detect and warn.

a = 1
def b():
a = 2

Perhaps the above bug happens with novice Python developers only. But my
idea of compiler warning and "global.a = 2" and "local.a = 2" (or "var a
= 2") would solve it. I wonder how many unnecessary warnings this would
cause in the current code base, and how many bugs it would detect.

It is a bit difficult for novice Python developers to understand why
accessing global variables is OK but modifying them is not, especially
if you just write a short script like the above. There is no such
restriction in any other language I know. I agree that modifying global
variables is usually bad, though. But it would be more beautiful if
accessing and modifying would happen with the same syntax ("global."
prefix or not). Every other language checks first the locals and then
globals and modifies what it finds first, and gives error if it can't
find it. So the above code should work as it is, without any extra
"global" keywords. But this is impossible because of the current code
base... it seems that there is no easy solution here.

Harri
 
S

Sean Ross

Harri Pesonen said:
I agree with you. But the original problem (at least mine) was that the
following code has a bug that the compiler could easily detect and warn.

a = 1
def b():
a = 2

Hi.
I see what your saying, though I wouldn't consider that so much a "bug"
as much as I would consider it a misunderstanding of how binding
works in Python. But, yeah, if you wrote that expecting to bind the
global variable 'a' to 2, I guess you'd have a bug :)

[snip]
It is a bit difficult for novice Python developers to understand why
accessing global variables is OK but modifying them is not, especially
if you just write a short script like the above.

I suppose it might be. I didn't find that, but I can see how it could be
true.
There is no such restriction in any other language I know.

I'm thinking that the languages you're speaking of require you to declare
your variables before (or as) you bind them. Python doesn't. And most
people who use Python _really_appreciate_ that. So, unfortunately, there
likely will not be much head-way gained in trying to get variable
declarations of any form added to the language (i.e., var a = 3, or even
local.a = 3). Just so you know.

Also, just to give you an example of another language that _does_ have
the same "problem" we're discussing, here's some Ruby code:

a = 1
def b()
a = 2
end
b()
print a
# outputs: 1

The first 'a' is bound as a local variable in the module scope, while the
second is bound as a local variable in the method (yep, that's a method,
not a function) scope of 'b'. Pretty much the same thing as what happens
in Python. But, then, that first 'a' really isn't global, in the Ruby sense.
To make it global we need to use '$a'.

$a = 1
def b()
$a = 2
end
b()
print $a
# outputs: 2

That works the way you were hoping. And there's no confusion between
what's global and what's local. But, then, you've also got to use that sigil
all the time (and Python folk don't take kindly to sigils ;). Which would be
pretty much comparable to the "global.a" idea. It's different from the
current "global a" method, since you can't have a local variable 'a'
once you've used the global statement. With "global.a" or "$a", you could.
But it would be more beautiful if
accessing and modifying would happen with the same syntax ("global."
prefix or not). Every other language checks first the locals and then
globals and modifies what it finds first, and gives error if it can't
find it. So the above code should work as it is, without any extra
"global" keywords. But this is impossible because of the current code
base... it seems that there is no easy solution here.

For accessing, Python, essentially, first checks locals and then globals.
For modifying...no. Essentially, "a = 2" works _something_like_
locals()['a'] = 2. I don't think Python tries to look up 'a' during a
binding
operation (but I could be wrong :). To do what you're advocating, it'd have
to, and that would probably slow things down.

So, yeah, there's no easy solution. The "global.a" idea seems okay. You
don't have to declare your variables, and you can't confuse local and
global variables, because you have to use the global namespace directly
to access global variables. But, then, you have to use the global
namespace directly to access global variables, heh. So, you're code
becomes more verbose. You could go the Ruby route and introduce a
sigil to denote global, but I don't see that happening in this language. And
the look-up before binding approach probably won't be happening any
time soon either. Oh well.

C'est la vie.
Sean
 
A

Alex Martelli

Mel said:
To me, the existence of a qualified

__current_module__.xyz = 3

implies that another local variable can also be called xyz.
So we're forced to code things like

__current_module__.xyz = 1 - __current_module__.xyz

even with all the beautification brackets '__', this starts
to look cumbersome to me. I would also prefer (while we're

you can of course use all normal possibilities of import, e.g:

import __current_module__ as g
g.xyz = 1 - g.xyz

Maybe Python 3 could re-cast the 'global' keyword to take
the place of '__current_module__'. 'module' might be more
meaningful, if it doesn't ultimately take one too many
useful names away from the programmers.

You can use any identifier you please after the 'as'.


Alex
 
C

Carlo v. Dango

do you want private or protected? private can be acomplished with the ugly
__ hack, but you can't create protected properties---this really suxx...


-carlo
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,482
Members
44,901
Latest member
Noble71S45

Latest Threads

Top