Can global variable be passed into Python function?

C

Chris Angelico

Steven D'Aprano said:
The big difference is that in "fixed location" languages, it makes
sense to talk about the address of a *variable*.

The address could be a symbol, too.

The Python statement

xyz = 3

places a number in the address "xyz".

You can read the value from the address "xyz" with

locals()["xyz"]

No, you cannot. That's the exact line of thinking that leads to
problems. You are not placing a number at the address "xyz", you are
pointing the name "xyz" to the number 3. That number still exists
elsewhere.

xyz = 3
abc = xyz

Does this copy the 3 from xyz into abc? In C, it would. Those
variables might not "exist" anywhere, but they must, by definition, be
storing the integer 3. And that integer has been copied. But in
Python, no it does not. It doesn't *copy* anything. And if you fiddle
with the integer 3 in some way, making it different, it'll be
different whether you look at xyz or abc, because they're the same 3.
You can't see that with integers because Python's int is immutable,
but this is where the confusion about mutable vs immutable objects
comes from. Immutable objects behave *sufficiently similarly* to the
C/Pascal model that it's possible to think Python works the same way,
but it doesn't.

The nearest C equivalent to what I'm talking about is pointers.
(CPython objects are basically used with pointers anyway. When you get
back an object reference from a CPython API function, you get a
pointer, optionally with the responsibility for one of its
references.) This is broadly how Python objects work:

/* Python strings are immutable, so the equivalent would be a list. */
/* I'm using a string because C doesn't have a list type. */
char *xyz = strcpy(malloc(20),"Hello, world!");
char *abc = xyz;

xyz[1] = 'a';
printf("abc has: %s\n", abc);

That'll show that abc has "Hallo, world!", even though it was through
xyz that the change was made. The "thing" that is that string is the
puddle of bytes on the heap (allocated with the malloc(20) up above).
The name just has a reference to that. Creating another reference to
the same object doesn't change anything.

ChrisA
 
M

Marko Rauhamaa

Chris Angelico said:
That's the exact line of thinking that leads to problems. You are not
placing a number at the address "xyz", you are pointing the name "xyz"
to the number 3. That number still exists elsewhere.

And?

In C, I can say:

Number *o = malloc(sizeof *o);
o->value = 3;

Your statement is valid: the number 3 resides elsewhere than the
variable o.

As for Python, there's nothing in the Python specification that would
prevent you from having, say, 63-bit integers as representing
themselves. IOW, you could physically place such integers as themselves
as the reference and the number would not physically exist elsewhere.

Bottom line, there's no fundamental difference between C and Python
variables.


Marko
 
C

Chris Angelico

As for Python, there's nothing in the Python specification that would
prevent you from having, say, 63-bit integers as representing
themselves. IOW, you could physically place such integers as themselves
as the reference and the number would not physically exist elsewhere.

What would id(5) be? Some constant? What would id(id([])) be?

ChrisA
 
M

Marko Rauhamaa

Chris Angelico said:
As for Python, there's nothing in the Python specification that would
prevent you from having, say, 63-bit integers as representing
themselves. IOW, you could physically place such integers as
themselves as the reference and the number would not physically exist
elsewhere.

What would id(5) be? Some constant? What would id(id([])) be?

Any suitable scheme would do. For example, id(n) == n for 63-bit
integers; other objects are dynamically sequence-numbered starting from
a high base (here, 2 ** 64):
id(5) 5
id([]) 18446744073709551620
id(id([]))
18446744073709551624

Or id(n) == 2 * n for 63-bit integers; other objects are dynamically
sequence-numbered using only odd integers starting from 1:
18

Or id(n) == 2 ** 64 + n for 63-bit integers; other objects get the
RAM address of the internal ḿemory block:
id(5) 18446744073709551621
id([]) 3074657068
id(id([]))
18446744076784207372

The possibilities are endless.


Marko
 
C

Chris Angelico

Or id(n) == 2 ** 64 + n for 63-bit integers; other objects get the
RAM address of the internal ḿemory block:
id(5) 18446744073709551621
id([]) 3074657068
id(id([]))
18446744076784207372

Assuming you define "63-bit integers" either as 0<=n<2**63 or as
-2**62<=n<2**62, this could work, but it would depend on never using
memory with addresses with bit 63 set, as id() is (if I recall
correctly) supposed to return an integer in the native range. I'm not
sure you can depend on that sort of pattern of memory usage.

In any case, you'd need some way to pretend that every integer is
really an object, so you'd need to define id(), the 'is' operator, and
everything else that can work with objects, to ensure that they
correctly handle this. It would be a reasonable performance
improvement to use native integers for the small ones (where "small"
integers might still be fairly large by human standards), but unlike
in languages like Pike (which does something like what you're saying),
Python has a concept of "object identity" which can't be broken.
(Pike's integers simply _are_, they aren't considered separate
objects. You can't test them for identity. Its strings, also, simply
are, although since Pike strings are guaranteed to be interned, their
values and identities really are the same. To Pike, it's only more
complex types that need to distinguish value from identity.) So this
optimization, which certainly does make sense on the face of it, would
potentially make a mess of things elsewhere.

I'm sure PyPy optimizes small integers somewhat, though.

ChrisA
 
T

Terry Reedy

As for Python, there's nothing in the Python specification that would
prevent you from having, say, 63-bit integers as representing
themselves. IOW, you could physically place such integers as themselves
as the reference and the number would not physically exist elsewhere.

The Python spec requires that ints act as if they are independent
objects with about 20 attributes and methods. The language spec is based
on duck typing everything as an object with a class and attributes.

Revised code would have to either turn the reference int into a real
object on every access (which would be tremendously inefficient), or
code special case treatment of reference ints into *every* piece code
that might act on ints (which is all over the interpreter) so as to
simulate the int object behavior. id(someint) is the least of the problems.

Special-casing ints to store the value in the reference has been
proposed and rejected. I do not remember how far anyone went in trying
to code the idea, but I doubt that anyone got as far as getting the test
suite to pass.
Bottom line, there's no fundamental difference between C and Python
variables.

Hogwash. Int variables are not all variables. And as I explained above,
even if one stored Python ints much like C ints, one would have to add
code to hide the fact that one had done so.
 
M

Marko Rauhamaa

Chris Angelico said:
id() is (if I recall correctly) supposed to return an integer in the
native range

That restriction seems beyond the scope of the language definition.
Still, it can be trivially provided for.
In any case, you'd need some way to pretend that every integer is
really an object, so you'd need to define id(), the 'is' operator, and
everything else that can work with objects, to ensure that they
correctly handle this.

Trivial, I should say.
It would be a reasonable performance improvement to use native
integers for the small ones

Maybe. Point is, whether it's done this way or that is irrelevant from
the point of view of functional correctness. Whether an integer is an
object or not has absolutely nothing to do with the implementation of
the interpreter.

And thus, Python variables are barely distinguishable from C variables.


Marko
 
M

Marko Rauhamaa

Terry Reedy said:
Special-casing ints to store the value in the reference has been
proposed and rejected. I do not remember how far anyone went in trying
to code the idea, but I doubt that anyone got as far as getting the
test suite to pass.

FWIW, elisp essentially does that. Anyway, we are discussing this to
make it clear that the language definition is abstract. All compliant
implementations are equally correct. It doesn't make any difference
whatsoever for a Python programmer how this or that object type has been
implemented under the hood.
Hogwash. Int variables are not all variables. And as I explained
above, even if one stored Python ints much like C ints, one would have
to add code to hide the fact that one had done so.

<URL: http://www.brainyquote.com/quotes/quotes/s/salvadorda103580.html>

The only difference between me and a madman is that I'm not mad.


Marko
 
M

Mark Lawrence

And thus, Python variables are barely distinguishable from C variables.

To repeat what Terry Reedy said earlier, hogwash. Looks as if I've
another member of my dream team, who can proudly sit alongside our self
appointed resident unicode expert.
 
S

Steven D'Aprano

FWIW, elisp essentially does that. Anyway, we are discussing this to
make it clear that the language definition is abstract.

No. The language definition is concrete: it describes a concrete
interface. You are confusing the interface with the implementation: the
language definition is only abstract with regard to the implementation,
which is free to vary, so long as the interface remains the same.

Regardless of the implementation, Python code must behave in certain
ways, and the reference implementation CPython defines the semantics of
variable as name binding, not fixed locations. Can this by implemented
using fixed locations? Of course it can, and is: the proof is that
CPython's name binding variables are implemented in C, which uses fixed
location variables.

All compliant
implementations are equally correct. It doesn't make any difference
whatsoever for a Python programmer how this or that object type has been
implemented under the hood.

Performance can matter :)

But you are correct, as far as it goes. Where you are going wrong is by
confusing the semantics of Python code with the underlying implementation
of the Python virtual machine.
 
G

Gregory Ewing

Steven said:
Yes, Pascal has pointers as a first-class data type. Syntax is similar to
C, ^x is a pointer to x, p^ dereferences the pointer p.

Actually, the prefix ^ is only used for declaring
pointer *types*. Standard Pascal has no way of getting
a pointer to an arbitrary variable; the only way to
get a pointer is new(p) (which is the equivalent of
p = malloc(sizeof(*p))).
 
W

wxjmfauth

Le lundi 24 février 2014 01:37:42 UTC+1, Steven D'Aprano a écrit :
Performance can matter :)

Two points to notice

- Even with utf-8, the worse performance case, such
a difference reaches [0.x - a few] percent.

- Indexing? Very well preserved for the "abc part"

jmf
 
S

Steven D'Aprano

Actually, the prefix ^ is only used for declaring pointer *types*.
Standard Pascal has no way of getting a pointer to an arbitrary
variable; the only way to get a pointer is new(p) (which is the
equivalent of p = malloc(sizeof(*p))).



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!
 
J

j.e.haque

And?



In C, I can say:



Number *o = malloc(sizeof *o);

o->value = 3;



Your statement is valid: the number 3 resides elsewhere than the

variable o.

typedef struct {
int value;
} Number;

Number *o;
o = malloc(sizeof(*o));
o->value=3;
printf("o<%p>, o->value<%p>\n", o, &o->value);

o<0x9fe5008>, o->value<0x9fe5008>

Is the compiler borked?
 
M

Michael Torrie

typedef struct {
int value;
} Number;

Number *o;
o = malloc(sizeof(*o));
o->value=3;
printf("o<%p>, o->value<%p>\n", o, &o->value);

o<0x9fe5008>, o->value<0x9fe5008>

Is the compiler borked?

Why would you think that? The address of the start of your malloc'ed
structure is the same as the address of the first element. Surely this
is logical? And of course all this is quite off topic.
 
R

random832

typedef struct {
int value;
} Number;

Number *o;
o = malloc(sizeof(*o));
o->value=3;
printf("o<%p>, o->value<%p>\n", o, &o->value);

o<0x9fe5008>, o->value<0x9fe5008>

Is the compiler borked?

That's cheating. Try printf("o<%p>", &o);
 
R

random832

Why would you think that? The address of the start of your malloc'ed
structure is the same as the address of the first element. Surely this
is logical? And of course all this is quite off topic.

That's not helpful - the problem, in context, is that he doesn't
understand that the fact that the structure exists at that address is
not the same thing as the variable "o" existing at that address.
 
C

Chris Angelico

typedef struct {
int value;
} Number;

Number *o;
o = malloc(sizeof(*o));
o->value=3;
printf("o<%p>, o->value<%p>\n", o, &o->value);

o<0x9fe5008>, o->value<0x9fe5008>

Is the compiler borked?

No, because a structure in C is simply a laying-out of its members. A
pointer to the structure is exactly the same as a pointer to its first
member, same as a pointer to an array is really just a pointer to its
first element (with other elements laid out sequentially, possibly
with padding for alignment). In Python, a complex object is a thing in
its own right; it has an identity and a set of members, each of which
has its own identity. In C, the structure is an invisible piece of
nothingness that surrounds an aggregation of other objects. For
instance:

typedef struct {
int val1;
int val2;
} NumberPair;

NumberPair five_pairs[5];
int *ten_ints = (int *)five_pairs;

This is considered naughty (pointer aliasing), and can make a mess of
optimization, but as far as I know, it's never going to be a problem
(I don't think it's possible for there to be any padding between two
ints; it's possible the struct will demand coarser alignment than the
ints would, which is why I've written them in that order). You can
access ten integers from the aliased pointer, and five pairs of
integers through the original structure array, and they're all exactly
the same. If you print out those two pointers, they will have the same
value in them, and &five_pairs[3]->val2 will be the same as
&ten_ints[7] (and the same as ten_ints+7).

For in C, neither the structure nor the non-structure is anything. The
only thing that counts is code expressing itself through love.
(Galatians 5:6, K&R translation. Or something like that.)

ChrisA
 
C

Chris Angelico

That's cheating. Try printf("o<%p>", &o);

It's not cheating, but it's showing something different. Comparing o
and &o->value shows that the structure itself and its first member are
at the same location in memory. Comparing o and &o shows that the
structure and the pointer to the structure are at different locations
in memory.

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

No members online now.

Forum statistics

Threads
474,079
Messages
2,570,574
Members
47,206
Latest member
Zenden

Latest Threads

Top