From: Grant Edwards on
On 2010-07-11, Thomas Jollans <thomas(a)jollans.com> wrote:
> On 07/11/2010 08:45 PM, wheres pythonmonks wrote:

>> On #3: Sorry this is confusing, but I was browsing some struct array
>> code from numpy, in which one of the columns contained strings, but
>> the type information, supplied in numpy.array's dtype argument,
>> specified the type as a an "object" not a string.

A string is an object.

>> Just wondering why one would do that.
>
> No expert on numpy, but maybe storing object references is cheaper than
> storing strings here ?

Strings are objects.

IIRC, numpy has special homogeneous array types to hold certain scalar
values: byte, int, float, complex. Those special array types allow
for very efficient storage and operations.

If you want an array of any other type, or a heterogeneous array, then
you use an array of objects and then you can put anything into the
array (including strings).

--
Grant Edwards grant.b.edwards Yow! The PINK SOCKS were
at ORIGINALLY from 1952!!
gmail.com But they went to MARS
around 1953!!
From: sturlamolden on
On 12 Jul, 07:51, "Alf P. Steinbach /Usenet" <alf.p.steinbach
+use...(a)gmail.com> wrote:

> We're talking about defining a 'swap' routine that works on variables.

I did not miss the point. One cannot make a swap function that rebinds
its arguments in the calling stack frame. But a swap function can swap
values, given that the type is not immutable:

def swap(a,b):
a[0],b[0] = b[0],a[0]

>>> a,b = [1],[2]
>>> swap(a,b)
>>> print a,b
[2] [1]

From: Alf P. Steinbach /Usenet on
* sturlamolden, on 12.07.2010 16:59:
> On 12 Jul, 07:51, "Alf P. Steinbach /Usenet"<alf.p.steinbach
> +use...(a)gmail.com> wrote:
>
>> We're talking about defining a 'swap' routine that works on variables.
>
> I did not miss the point. One cannot make a swap function that rebinds
> its arguments in the calling stack frame. But a swap function can swap
> values, given that the type is not immutable:
>
> def swap(a,b):
> a[0],b[0] = b[0],a[0]
>
>>>> a,b = [1],[2]
>>>> swap(a,b)
>>>> print a,b
> [2] [1]

OK, that's missing the point.

I thought you were joking.


Cheers & hth.,

- Alf

--
blog at <url: http://alfps.wordpress.com>
From: Alf P. Steinbach /Usenet on
* Steven D'Aprano, on 12.07.2010 04:39:
> On Mon, 12 Jul 2010 03:12:10 +0200, Alf P. Steinbach /Usenet wrote:
>
>> * MRAB, on 12.07.2010 00:37:
> [...]
>>> In Java a variable is declared and exists even before the first
>>> assignment to it. In Python a 'variable' isn't declared and won't exist
>>> until the first 'assignment' to it.
>>
>> That is a misconception.
>>
>> In Python a variable is declared by having an assignment to it, which
>> for a local variable may be anywhere within a routine.
>
> Oh, I'm going to regret being sucked into this...
>
> In *CPython*, but not necessarily other implementations, variables which
> are local to a function are not kept in a dictionary-based namespace, but
> in slots in the code object (not to be confused with __slots__ used for
> classes). Python has STORE_FAST and LOAD_FAST byte-codes for accessing
> locals.
>
> This is intended as a speed, and possibly memory, optimization. I don't
> believe this is a requirement though, so implementations may not do this.
>
> It is true that the slot is created at compile time, and in *that sense*,
> local variables exist before they are bound. I'm not entirely convinced
> that this is the only sense that matters, but never mind. The error
> message given exposes this to the user:
>
>>>> def f():
> ... print x
> ... x = 1
> ...
>>>> f()
> Traceback (most recent call last):
> File "<stdin>", line 1, in<module>
> File "<stdin>", line 2, in f
> UnboundLocalError: local variable 'x' referenced before assignment
>
>
> If you try this with a global, you get this:
>
>>>> def f():
> ... global x
> ... print x
> ...
>>>> f()
> Traceback (most recent call last):
> File "<stdin>", line 1, in<module>
> File "<stdin>", line 3, in f
> NameError: global name 'x' is not defined
>
> In this case, there's no doubt that global variable "x" doesn't exist at
> all -- there is no key "x" in the global namespace.

Yes.

What I disproved was the statement that every Python variable is created by the
execution of an assignment.

Some (the global ones) are. :-)


> It seems to me that "a slot to hold the variable is created for local
> variables" is an implementation detail, not a language feature.

Yes.

However, any Python implementation has to implement the same user level
semantics in some way (note: use level semantics do not include "space reserved"
for an unassigned variable, or even for all assigned variables since with single
assignment a sufficiently smart compiler can optimize away the space, but user
level semantics do include existence and resultant effect).

As I see it it doesn't matter whether the implementation is CPython call frame
slots or that mechanism called something else or a different mechanism called
the same or a different mechanism called something different; what IMO matters
is same semantics, that any assignment to a variable within a routine serves as
a compile time declaration, creating that local variable in advance, unless,
with Python 3.x., that name has been declared as a 'global' or 'nonlocal'.

So, this is a possible point of disagreement.

I say the semantics of local variable creation are part of the language
definition, but I get the /impression/ that maybe you think it's
CPython-specific, that e.g.

def foo():
x
x = 0

might not raise an unassigned variable exception with some conforming Python
implementation, i.e. different effect for same code with different
implementations, that this is at least /unspecified behavior/ in Python?


> CPython
> could easily hide the difference by changing the exception from
> UnboundLocalError to:
>
> NameError: local name 'x' does not exist
>
> and nobody would be any wiser. (Well, perhaps people who catch
> UnboundLocalError, but why would you do that?)
>
> I also note that UnboundLocalError is a subclass of NameError, so
> "variable exists but is not bound" is considered to be a special case of
> "variable doesn't exist" rather than a completely independent case. In
> that sense, I think I'm on solid ground to say that in Python variables
> don't exist until they are bound to a value, and leave it to pedants like
> you and I to mention that for CPython local variables have space reserved
> for them by the compiler before they are bound.

He he. I wouldn't say "space reserved". That is an implementation detail.


Cheers,

- Alf

--
blog at <url: http://alfps.wordpress.com>
From: Rhodri James on
On Mon, 12 Jul 2010 13:56:38 +0100, bart.c <bartc(a)freeuk.com> wrote:

> "Steven D'Aprano" <steve(a)REMOVE-THIS-cybersource.com.au> wrote in
> message news:4c3aedd5$0$28647$c3e8da3(a)news.astraweb.com...
>> On Mon, 12 Jul 2010 09:48:04 +0100, bart.c wrote:
>>
>>> That's interesting. So in Python, you can't tell what local variables a
>>> function has just by looking at it's code:
>
>>> def foo(day):
>>> if day=="Tuesday":
>>> x=0
>>> print ("Locals:",locals())
>>>
>>> #foo("Monday")
>>>
>>> Does foo() have 1 or 2 locals?
>>
>> That's easy for CPython: it prepares two slots for variables, but only
>> creates one:
>>
>>>>> foo("Monday")
>> ('Locals:', {'day': 'Monday'})
>>>>> foo.func_code.co_varnames
>> ('day', 'x')
>>>>> foo.func_code.co_nlocals
>> 2
>>
>> So, the question is, is x a local variable or not? It's not in locals,
>> but the function clearly knows that it could be.
>
> So Alf P.S. could be right; x exists, but Python pretends it doesn't
> until it's assigned to.

CPython, not Python. And as Steven said, x *doesn't* exist. Allowance is
made by that specific implementation of the interpreter because x *might*
exist, but in this particular case it doesn't and a more dynamic
implementation might choose not to reserve a slot just in case. x is
created until it's actually used.

--
Rhodri James *-* Wildebeeste Herder to the Masses