Can global variable be passed into Python function?

D

Dennis Lee Bieber

Standard Pascal? Who uses standard Pascal? I'm talking about MacPascal :)

Actually, it's possible that I've forgotten the details, it's been over
twenty years since I last dereferences a Pascal pointer in anger, so you
might be right... a quick glance at some of my text books suggest that
you probably are. Thanks for the correction!

Alcor Pascal (TRS-80, in my case) had a library function Location(),
but the value it returned could not be used as a pointer dereference. It
was mainly meant providing arguments to the interface to the assembly level
call scheme (pass the address of a structure in a Z-80 register while
calling something in the OS)
 
G

Gregory Ewing

Steven said:
Standard Pascal? Who uses standard Pascal? I'm talking about MacPascal :)

Mac Pascal used @ for getting a pointer to
a variable, if I remember rightly.
 
M

Mark H. Harris

I need to pass a global variable into a python function. However, the global variable does not seem to be assigned after the function ends. Is it because parameters are not passed by reference? How can I get function parameters to be passed by reference in Python?

def func(x):
global ref_name
ref_name = '3.14159'
# rest of the code
# rest of the code

When you call this function the ref_name reference will be set to '3.14159' as a string and your main code will be able to 'see' it, and other funcs will be able to 'see' it too... play with it a bit... if other funcs need to write to it they will also have to use the global ref_name line. As long as other funcs only read the reference, then the global line is not needed to 'see' the reference.

As others have noted, python does not have a 'variable' concept (referencesto objects instead) and so your question is a little ambiguous.

Also, using global references within functions is not a good idea... generally speaking.

Cheers
 
N

Ned Batchelder

As others have noted, python does not have a 'variable' concept (references to objects instead) and so your question is a little ambiguous.

Mark, thanks for helping to answer the OP's question. We've covered (in
depth) in the rest of this thread, that Python *does* have the concept
of a variable, it just behaves differently than some other popular
programming languages (but exactly the same as some other popular
programming languages!)
 
M

Mark H. Harris

Mark, thanks for helping to answer the OP's question. We've covered (in
depth) in the rest of this thread, that Python *does* have the concept
of a variable, it just behaves differently than some other popular
programming languages (but exactly the same as some other popular
programming languages!)

I do not disagree. I've had the same discussion over the years since usingpython, and often its a rope soaking contest... some folks get so enamored with the 'way' it works under the covers that they forget how people think about it as they are trying (as normal people) to use the language (instead of BASIC).

So, yeah, thinking about variables is just not going away.

I finally decided (in my own head) that I would completely give up on the 'variable' concept (intellectually) and help folks try to understand references and reference counting. Knowing that A points to an int, and that B=A, now B points to the VERY SAME int... they are references pointing to the same piece of memory. And of course we want new folks to understand the issue of:
A==B
True
A is B
False
..... and WHY that is or isn't....

:)

it just helps to get the 'variable' idea out of here... it really is something completely different in python.

Thanks for the note,
kind regards,
marcus
 
S

Steven D'Aprano

Knowing that A points to an int, and
that B=A, now B points to the VERY SAME int... they are references
pointing to the same piece of memory. And of course we want new folks to
understand the issue of: A==B
True
A is B
False
..... and WHY that is or isn't....


If they point to the same piece of memory -- which, by the way, can be
moved around if the garbage collector supports it -- then A is B cannot
possibly return False.
 
M

Mark H. Harris

If they point to the same piece of memory -- which, by the way, can be
moved around if the garbage collector supports it -- then A is B cannot
possibly return False.

hi Steve, long time, yes, my whole point exactly. And we all know what python is doing under the covers for small ints like 0 - 256 ... in which case consider the following:

a=128
b=a
b=128
a is b
True

But...... consider this

a=1024
b=a
b=1024
a is b
False

For small ints below a certain value (257) A is B will always be True....but now for ints above that value, as I've shown,
A=257
B=A
B=257
A is B
False

But for the variable discussion (like in BASIC, or even C) A=128, B=A,A and B are two pieces of memory that both happen to be variables containing different pieces of memory. For python, the references to small ints (as above) will almost always point to the same int object for each reference; hence the need for reference counts.

Folks that think of assignment in python with a BASIC, or even C, mentalitywill have trouble understanding the difference between "==" and "is"and why... and they won't get reference counting.

Cheers
 
C

Chris Angelico

a=1024
b=a
b=1024
a is b
False

No no no no! They're not pointing to the same integer any more. Now,
if you change the "b=1024" from being a mostly-useless assignment (to
another int with the same value) into being a comparison, then it'll
be safe. But you're assigning "b=a" and then immediately reassigning
"b=1024".

Simple rule of thumb: Never use 'is' with strings or ints. They're
immutable, their identities should be their values. Playing with 'is'
will only confuse you, unless you're specifically going for
introspection and such.

ChrisA
 
M

Mark H. Harris

Simple rule of thumb: Never use 'is' with strings or ints. They're
immutable, their identities should be their values. Playing with 'is'
will only confuse you, unless you're specifically going for
introspection and such.

Right. The only time I use "is" is when I'm trying to explain to someonenew to python assignment what is happening inside... what Mark Summerfieldcalls "python's beautiful heart," in his his recent book, "Programming in Python 3" ... a great resource, by the way.
 
C

Chris Angelico

Right. The only time I use "is" is when I'm trying to explain to someone new to python assignment what is happening inside... what Mark Summerfield calls "python's beautiful heart," in his his recent book, "Programming in Python 3" ... a great resource, by the way.

'is' can and should be used with mutables, to distinguish between
identical values with different identities. It's also appropriate to
use 'is' with special singletons like None. Just be careful of ints
and strings.

ChrisA
 
M

Marko Rauhamaa

Chris Angelico said:
Simple rule of thumb: Never use 'is' with strings or ints. They're
immutable, their identities should be their values. Playing with 'is'
will only confuse you, unless you're specifically going for
introspection and such.

Here's a use case for "is" with strings (or ints):

class Connection:
IDLE = "IDLE"
CONNECTING = "CONNECTING"
CONNECTED = "CONNECTED"
DISCONNECTING = "DISCONNECTING"
DISCONNECTED = "DISCONNECTED"

def __init__(self):
self.state = IDLE

def connect(self, address):
...
self.state = CONNECTING
...

def disconnect(self):
...
if self.state is CONNECTED:
...

The state objects could have been defined like this:

IDLE = object()
CONNECTING = object()
CONNECTED = object()
DISCONNECTING = object()
DISCONNECTED = object()

However, strings have the advantage in troubleshooting:

sys.stderr.write("state = {}\n".format(self.state))


Marko
 
S

Steven D'Aprano

Here's a use case for "is" with strings (or ints):

I don't think this is a use-case for "is". See below.
class Connection:
IDLE = "IDLE" [...]
CONNECTED = "CONNECTED" [...]
def disconnect(self):
...
if self.state is CONNECTED:
...

Why do you care that the state is *that specific* string, rather than any
old string with the value "CONNECTED"?

Unless you can explain a good reason why, say, *this* instance
"CONNECTED" should fail the test, while *that* instance with the same
value passes, it's not a good use-case for "is".
 
C

Chris Angelico

Here's a use case for "is" with strings (or ints):

class Connection:
IDLE = "IDLE"
CONNECTING = "CONNECTING"
CONNECTED = "CONNECTED"
DISCONNECTING = "DISCONNECTING"
DISCONNECTED = "DISCONNECTED"

The state objects could have been defined like this:

IDLE = object()
CONNECTING = object()
CONNECTED = object()
DISCONNECTING = object()
DISCONNECTED = object()

However, strings have the advantage in troubleshooting:

sys.stderr.write("state = {}\n".format(self.state))

As Ben said, strong use-case for enums (either migrate to 3.4, or
check PyPI). But here's an alternative that uses object identity
safely. (Remember, all it takes is a bit of string interning and two
equal strings could become identical.)

class enum:
def __init__(self, desc):
self.desc = desc
def __repr__(self):
return self.desc

IDLE = enum("IDLE")
CONNECTING = enum("CONNECTING")
CONNECTED = enum("CONNECTED")
DISCONNECTING = enum("DISCONNECTING")
DISCONNECTED = enum("DISCONNECTED")

Now object identity is the right way to do things, and you can still
do the formatting just like you say; plus there's no way to
accidentally get something that seems to work.

Of course, the real enum type is far more sophisticated than that, but
the concept is the same. It's an object.

ChrisA
 
M

Marko Rauhamaa

Ben Finney said:
There are two reasons why I think this is *still* not a justification
for using ‘is’ with string values:

First reason: This is better done by making it clear the value is an
arbitrary object that won't be compared for equality. Just use
‘object()’ to creeate each value and be done with it. That's a hack,
but it's better than pretending you'll use the string as a string of
text and then breaking that expectation.

Second reason: This use case is a primary motivation for the Enum
pattern. The Enum pattern is implemented in the standard-library
‘enum’ module, now in Python 3.4
<URL:http://python.org/dev/peps/pep-0435/>.

So, I think Marko's use case is not a justification for comparing
string values with ‘is’.

Yes, enums are long overdue. However, since any distinct objects will
do, there is nothing preventing you from using string objects.


Marko

PS On the topic of enums, when are we getting support for a switch
statement?
 
C

Chris Angelico

Yes, enums are long overdue. However, since any distinct objects will
do, there is nothing preventing you from using string objects.

String literals will often be interned if they look like (especially,
if they *are*) identifiers, so if you want to prevent other strings
from happening to match, you can't trust 'is'.
INIT = "INIT"
def __init__(self):
self.state = self.INIT
def initializing(self):
return self.state is self.INITTrue


So you should use some string value that doesn't look like an identifier:
INIT = "<<INIT>>"
def __init__(self):
self.state = self.INIT
def initializing(self):
return self.state is self.INITFalse

But even then, chances are you can force the matter by interning explicitly.
INIT = ">>INIT<<"
def __init__(self):
self.state = self.INIT
def initializing(self):
return self.state is self.INITTrue

Note that in no case did I at all tamper with the class definition,
either to change its idea of the INIT string or to fetch that
particular object. Two equal strings, in Python, might and might not
be identical, and you simply cannot rely on interning either way.

The third example, incidentally, depends on sys.intern reusing a.state
as the "one interned string". This will normally be what happens if
it's the first string of that value to be used. So you might be able
to first force the strings to be in the interning table, and then
force your sentinels to be different objects. But at that point, you
really should be using object(), or a proper enum module.

If you're using strings as state values, you should be using == to
compare them. Nothing else is safe.

ChrisA
 
C

Chris Angelico

PS On the topic of enums, when are we getting support for a switch
statement?

I don't see that they're particularly connected. In my C code, I've
used enums frequently as quick constants, often never switching on
them. Conversely, I often use switch in C code with either integer or
character constants. (ASCII character, of course, as that's all you
get.) Take this, for example, from my C++ MUD client:

enum {IS=0x00,ECHO=0x01,SEND=0x01,SUPPRESSGA=0x03,TERMTYPE=0x18,NAWS=0x1F,SE=0xF0,GA=0xF9,SB,WILL,WONT,DO=0xFD,DONT,IAC=0xFF};

That one happens to be used in a switch at one point, but it's also
used in other ways, like this:

static char naws[]={IAC,SB,NAWS,0,0,0,0,IAC,SE};

(The actual window size gets patched in separately, in case you're
curious... but I suspect most people here won't be aware that IAC SB
NAWS means Interpret-As-Command, Subnegotiation Begin, Negotiate About
Window Size, and that this is a TELNET command sequence.)

With bit flags, they'll never be used in switch:

enum //Bitflags in hackity
{
HACK_ATAT=1, //Perform @@ -> fill-in translation
HACK_AUTOEDIT=2, //Respond to the autoedit markers [now active by default]
};

....

if (hackity&HACK_ATAT) ...

Sometimes, they're just states, and they're assigned and/or compared
for equality:

enum {ic, court, citizen, trivia, sports, chancount} lastlinetype;

Some things check if (lastlinetype == ic), but nothing ever switches on it.

Meanwhile, here's a switch block from Gypsum that will never use enumerations:

switch (max(delay,base))
{
case 0..59: ... handling for <1 minute ...
case 60..3599: ... handling for <1 hour ...
default: ... handling for >= 1 hour ...
}

No, the features are quite independent. Python currently has dispatch
tables and if/elif chains, and a strong cultural aversion to switch.
You could change that by coming up with some *really* awesome
proposal, but you'll be fighting against the tide a bit.

ChrisA
 
M

Marko Rauhamaa

Chris Angelico said:
Python currently has dispatch tables and if/elif chains, and a strong
cultural aversion to switch. You could change that by coming up with
some *really* awesome proposal, but you'll be fighting against the
tide a bit.

It's easy have a "cultural aversion" when the language doesn't provide
the facility.

Switch statements provide for excellent readability in parsers and state
machines, for example. They also allow the Python compiler to optimize
the statement internally unlike long if-else chains.


Marko
 
C

Chris Angelico

Chris Angelico said:
String literals will often be interned if they look like (especially,
if they *are*) identifiers, so if you want to prevent other strings
from happening to match, you can't trust 'is'.

[...]

If you're using strings as state values, you should be using == to
compare them. Nothing else is safe.

You didn't quite understand the use case. You would never ever do things
like:

You'd only refer to the state names symbolically:

a.state = a.INIT

In theory, yes. If that's all people will ever do, then you can safely
use == to check. Why are you using is? To prevent the case where some
other random string will happen to compare equal. So I stuffed some
other random string in, and it was equal, and I proved that I could
make it identical as well.

ChrisA
 
C

Chris Angelico

It's easy have a "cultural aversion" when the language doesn't provide
the facility.

I'm talking about the strong resistance that gets put up any time the
suggestion comes up on python-ideas or somesuch. The core devs and
Guido especially are against the idea.
Switch statements provide for excellent readability in parsers and state
machines, for example. They also allow the Python compiler to optimize
the statement internally unlike long if-else chains.

It's usually possible to turn any concrete example of a switch
statement into an equally-readable dispatch table. All you need is for
your search terms to be hashable (which is a much less stringent
requirement than is usually put on switch blocks, like "must be
machine word signed integer"), and you can do something like this:

compare_key = {
# Same target(s).
ast.Assign: lambda node: ' '.join(dump(t) for t in node.targets),
# Same target and same operator.
ast.AugAssign: lambda node: dump(node.target) + dump(node.op) + "=",
# A return statement is always compatible with another.
ast.Return: lambda node: "(easy)",
# Calling these never compatible is wrong. Calling them
# always compatible will give lots of false positives.
ast.Expr: lambda node: "(maybe)",
# These ones are never compatible, so return some
# object that's never equal to anything.
ast.Import: lambda node: float("nan"),
ast.ImportFrom: lambda node: float("nan"),
ast.Pass: lambda node: float("nan"),
ast.Raise: lambda node: float("nan"),
ast.If: lambda node: float("nan"),
}

I then effectively do a big switch block like this:

if try_type not in compare_key:
print("Unrecognized type",try_type.__name__,file=sys.stderr)
compare_key[try_type] = lambda node: float("nan")
func = compare_key[try_type]
try_node = func(node.body[0])
for handler in node.handlers:
if try_node != func(handler.body[0]): return

The first check (the "not in" bit) is kinda like a default clause, but
it makes the output only once for any given type. For a more 'true'
default clause, I could do this:

try:
func = compare_key[try_type]
except KeyError:
func = compare_key["default"]

but I take advantage of the fact that the dispatch table is a dict and
mutate it. Also, if this were done in a switch block, there'd be some
redundancy. I call the same function on node.body[0] and on
handler.body[0] for each handler in handlers, so there's structure
that's common to all the branches there. I'm not sure how, with a
classic C-style switch block, I could implement that cleanly. Probably
I'd end up using function pointers and basically doing it exactly the
same way :)

The only major thing C's switch does that a dispatch table doesn't is
fall-through. And let's face it, if your big argument in favour of a
switch statement is "I need fall-through", you're not just going to
have Python devs against you, you're also going to fight against the
roughly 50% of C programmers who detest that feature :)

(FWIW, I'm in the other 50%. I quite like fall-through, and there are
times when it's a very clean way to express something. But even those
cases can usually be expressed one way or another with only a little
more redundancy - for instance, have one case that sets the key to be
the next one, and then have stand-alone if blocks rather than if/elif.
Considering that that use of fall-through usually requires an
explanatory comment anyway, you're not really losing much.)

So, going back to your statement:
Switch statements provide for excellent readability in parsers and state
machines, for example.

The best way to start trying to build support for this would be to
mock up a syntax for a switch statement, and find a currently-existing
parser or state machine to translate. Show us the "before and after"
shots. That's what I'm currently doing to justify an exception
expression syntax - examples like this:

pwd = (os.getcwd() except OSError: None)

# Lib/tkinter/filedialog.py:210:
try:
pwd = os.getcwd()
except OSError:
pwd = None


g = (grp.getgrnam(tarinfo.gname)[2] except KeyError: tarinfo.gid)
u = (pwd.getpwnam(tarinfo.uname)[2] except KeyError: tarinfo.uid)

# Lib/tarfile.py:2198:
try:
g = grp.getgrnam(tarinfo.gname)[2]
except KeyError:
g = tarinfo.gid
try:
u = pwd.getpwnam(tarinfo.uname)[2]
except KeyError:
u = tarinfo.uid


This is real Python code, straight out of the standard library. I
don't know if you could find many examples in the stdlib that beg for
a switch statement, but pick up some real-world code of your own, or
from some open source project, or something. Even if, in practice, it
wouldn't be changed for many years (because that project needs to be
compatible with previous versions of Python), it'd be worth showing
"here's what could be".

And then be prepared for a few hundred posts' worth of bikeshedding
about the details :)

ChrisA
 

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,777
Messages
2,569,604
Members
45,223
Latest member
Jurgen2087

Latest Threads

Top