Objects in Python

C

Chris Angelico

Just to pick a nit, the compiler probably doesn't know that, but the
linker does (or maybe even the run-time loader). However, we can think
of all of those as just part of the compilation tool chain, and then
we're good.[/QUOTE]

Hrm. Back when I first started C programming, it was MS-DOS 16-bit
work - segmented addressing (one of the most fascinating insanities
ever to be perpetrated on unsuspecting consumers - why, oh why, if you
want 20-bit addressing, should you invent a system that uses 32 bits
of data in such a non-expandable way?). My program would be loaded
into whatever segment the loader chose, but offsets within that could
be compiled in.

With modern x86 systems there are several more layers of complication,
but in many cases, you can still hard-code offsets within a logical
segment of memory. Set CS to your one code segment and do your jumps
and calls at fixed locations. Set [DEFG]S to your single data segment
and all your data can be at fixed locations too. (Obviously your stack
is referenced relative to SP/BP.)

I'm not familiar with other architectures, but it seems likely that
there's something similar. The segment / base location may change, but
variable 'x' still corresponds to 12345678 within that.

Nits can be fun to pick :)

ChrisA
 
S

Steven D'Aprano

Does it? I thought the difference between function-scope and
module-scope was compiled in,

It is. But local and global scope are not the only two scopes. Python has
nested scopes. Try these:

x = y = -99
def test():
def inner():
x = 23
def even_more_inner():
print "x is", x
print "y is", y
even_more_inner()
x = 1000
y = 42
inner()

Also, built-ins require a name lookup too. As you point out, locals are
special, but Python will search an arbitrarily deep set of nested
nonlocal scopes, then globals, then builtins.

See the introduction of nested-scopes:

http://www.python.org/dev/peps/pep-0227/

and non-locals:

http://www.python.org/dev/peps/pep-3104/
 
C

Chris Angelico

Also, built-ins require a name lookup too. As you point out, locals are
special, but Python will search an arbitrarily deep set of nested
nonlocal scopes, then globals, then builtins.

Ah, builtins, forgot that. So yes, global scope involves potentially
two name lookups. But nonlocals aren't searched at run time.

ChrisA
 
D

Dennis Lee Bieber

(In some older versions of Python, wildcard imports are allowed, and the
function then falls back on a namespace instead of fixed locations. That
is no longer the case in Python 3.2 at least.)
Must be really old:

PythonWin 2.5.2 (r252:60911, Mar 27 2008, 17:57:18) [MSC v.1310 32 bit
(Intel)] on win32.
Portions Copyright 1994-2006 Mark Hammond - see 'Help/About PythonWin'
for further copyright information..... from math import *
<interactive input>:1: SyntaxWarning: import * only allowed at module
level
 
S

Steven D'Aprano

Ah, builtins, forgot that. So yes, global scope involves potentially two
name lookups. But nonlocals aren't searched at run time.

Well, whaddyaknow. You're right.

x = 'globals'
def test(switch):
def a():
if switch == 1:
x = 'a'
def b():
if switch == 2:
x = 'b'
def c():
print "x found in", x
c()
b()
a()


Tried that in Jython, IronPython and Python 2.7, and I get the same
result: only test(2) succeeds.

I even tried it in Python 2.2, which does the same thing.

(2.1 and older don't have nested scopes, so there's no point in going
back further.)
 
S

Steven D'Aprano

Must be really old:

Not really. You get a SyntaxWarning back to at least 2.2, but the
fallback namespace behaviour does work through to 2.7:

py> assert 'pi' not in globals()
py> def test():
.... from math import *
.... print pi
....
<stdin>:1: SyntaxWarning: import * only allowed at module level
py> test()
3.14159265359

What I didn't realise until just now is that it's a bit more complicated
than that. Using import * in a function you can end up with two distinct
sets of locals, those using numbered memory slots (effectively address-
based), and those using a dict namespace.

If you assign to a name in the function, it still gets turned into a
memory slot rather than being in a dict. Decompiling the function shows
that such local are still accessed using LOAD_FAST and STORE_FAST op-
codes. (That's the case all the way back to Python 1.5 at least.)

But if you *don't* assign to the name, Python uses LOAD_NAME instead,
which searches namespace. In this case pi is not found in the global or
built-in namespaces, so there must be a local, dict-based namespace in
addition to the usual LOAD_FAST slots. Hence, two distinct sets of locals.
 

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
473,774
Messages
2,569,598
Members
45,158
Latest member
Vinay_Kumar Nevatia
Top