Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Python > what does 'a=b=c=[]' do

Reply
Thread Tools

what does 'a=b=c=[]' do

 
 
Steven D'Aprano
Guest
Posts: n/a
 
      12-24-2011
On Sat, 24 Dec 2011 09:50:04 +1100, Chris Angelico wrote:

> On Sat, Dec 24, 2011 at 9:32 AM, Steven D'Aprano
> <(E-Mail Removed)> wrote:
>> Yes. But having to manage it *by hand* is still unclean:

>
> Well, my point was that Python's current behaviour _is_ that.


Minus the managing it by hand part.


>> * you still have to assign the default value to the function assignment
>> outside the function, which is inelegant;

>
> C's static variables are initialized inside the function. But since
> Python doesn't have that, it doesn't really work that way. (You might be
> able to use a decorator to do some cool tricks though.)


If Python were C, then static variables would be the right solution, but
since it isn't, they aren't.



--
Steven
 
Reply With Quote
 
 
 
 
Steven D'Aprano
Guest
Posts: n/a
 
      12-24-2011
On Fri, 23 Dec 2011 17:03:11 +0000, Neil Cerutti wrote:

>> The disadvantage of late binding is that since the expression is live,
>> it needs to be calculated each time, even if it turns out to be the
>> same result. But there's no guarantee that it will return the same
>> result each time:

>
> That's its main *advantage*.


Ah yes, sorry, poor wording on my part. Whether calculating the default
value *once* or *each time* is an advantage or disadvantage depends on
what you're trying to do. Either way, it could be just what you want, or
an annoying source of bugs.


>> consider a default value like x=time.time(), which will return a
>> different value each time it is called; or one like x=a+b, which will
>> vary if either a or b are changed. Or will fail altogether if either a
>> or b are deleted. This will surprise some people some of the time and
>> lead to demands that Python "fix" the "obviously buggy" default
>> argument gotcha.

>
> It's hard to see anyone being confused by the resultant exception.


That's because you're coming at it from the perspective of somebody who
knows what to expect, in the middle of a discussion about the semantics
of late binding. Now imagine you're a newbie who has never thought about
the details of when the default value is created, but has a function like
"def foo(x, y=a+b)". He calls foo(x) seven times and it works, and on the
eighth time it blows up, perhaps with a NameError. It's surprising
behaviour, and newbies aren't good at diagnosing surprising bugs.

Or worse, it doesn't blow up at all, but gives some invalid value that
causes your calculations to be completely wrong. Exceptions are not the
worst bug to have -- they are the best.


> It's
> much harder to figure out what's going wrong with an early-bound
> mutable.


Only for those who don't understand, or aren't thinking about, Python's
object model. The behaviour of early-bound mutables is obvious and clear
once you think about it, but it does require you to think about what's
going on under the hood, so to speak.

[...]
>> To fake early binding when the language provides late binding, you
>> still use a sentinel value, but the initialization code creating the
>> default value is outside the body of the function, usually in a global
>> variable:

[...]

> I'd use a function attribute.
>
> def func(x, y=None):
> if y is None:
> y = func.default_y
> ...
> func.default_y = []
>
> That's awkward only if you believe function attributes are awkward.


I do. All you've done is move the default from *before* the function is
defined to *after* the function is defined, instead of keeping it in the
function definition. It's still separate, and if the function is renamed
your code stops working. In other words, it violates encapsulation of the
function.

That's not to say that you shouldn't do this. It's a perfectly reasonable
technique, and I've used it myself, but it's not as elegant as the
current Python default argument behaviour.


[...]
> The greater efficiency was probably what decided this question for
> Python, right? Since late-binding is so easy to fake, is hardly ever
> what you want, and would make all code slower, why do it?


Excellent point.


--
Steven
 
Reply With Quote
 
 
 
 
Steven D'Aprano
Guest
Posts: n/a
 
      12-24-2011
On Fri, 23 Dec 2011 19:24:44 -0500, Devin Jeanpierre wrote:

>> To fake early binding when the language provides late binding, you
>> still use a sentinel value, but the initialization code creating the
>> default value is outside the body of the function, usually in a global
>> variable:
>>
>> _DEFAULT_Y = [] # Private constant, don't touch.
>>
>> def func(x, y=None):
>> if y is None:
>> y = _DEFAULT_Y
>> ...
>>
>> This separates parts of the code that should be together, and relies on
>> a global, with all the disadvantages that implies.

>
> No, you can just do def func(x, y=_DEFAULT_Y): ...


Point taken. Nevertheless, the semantics are still not the same as actual
early binding: if the global name is deleted or changed, the function
stops working.



--
Steven
 
Reply With Quote
 
Lie Ryan
Guest
Posts: n/a
 
      12-24-2011
On 12/22/2011 10:20 AM, Dennis Lee Bieber wrote:

> which is to define the names "a", "b", and "c", and connects the three
> names to the single object (integer 7 or new empty list).


note that this "connects" and "disconnecting" business is more commonly
referred to in python parlance as "binding" a name to an object.

 
Reply With Quote
 
alex23
Guest
Posts: n/a
 
      12-24-2011
On Dec 24, 2:15*am, Roy Smith <(E-Mail Removed)> wrote:
> I know this is not quite the same thing, but it's interesting to look at
> what django (and mongoengine) do in their model definitions, prompted by
> your time.time() example. *You can do declare a model field something
> like:
>
> class Foo(models.Model):
> * *timestamp = DateTimeField(default=datetime.utcnow)
>
> Now, when you create a Foo, if you don't supply a timestamp, it
> generates one by calling utcnow() for you. *Very handy.
>
> I'm not arguing that Python should do that, just pointing out an example
> of where late binding is nice.


There is absolutely nothing stopping you from writing functions now
with that behaviour. All Python functions are "early binding, late
calling" with their arguments, if you treat the arguments as callables
within the function body.



 
Reply With Quote
 
alex23
Guest
Posts: n/a
 
      12-24-2011
On Dec 24, 2:27*am, Mel Wilson <(E-Mail Removed)> wrote:
> In a tool that's meant for other people to use to accomplish work of their
> own, breaking workflow is a cardinal sin.
>
> In a research language that's meant always to be up-to-date with the concept
> of the week, not so much.


What on earth gave you the impression Python was bleeding edge? As
there's more to the language than its syntax, "breaking workflow"
disrupts the core library as much as it does the code of everyone
else.

More importantly, you're talking pap. Research is as much about
communication as programming; if you expect every single researcher in
a discipline (or even in the same _building_) to remain in perfect
lockstep with the version releases of a domain-relevant language,
you're either not a researcher or not a very good one. You should get
out to a conference occasionally and see what people think about your
"concept of the week" idea.
 
Reply With Quote
 
alex23
Guest
Posts: n/a
 
      12-24-2011
On Dec 24, 6:25*pm, Steven D'Aprano <steve
(E-Mail Removed)> wrote:
> > It's
> > much harder to figure out what's going wrong with an early-bound
> > mutable.

>
> Only for those who don't understand, or aren't thinking about, Python's
> object model. The behaviour of early-bound mutables is obvious and clear
> once you think about it, but it does require you to think about what's
> going on under the hood, so to speak.


And here we've come full circle to the point of this thread.

If Python was ever 'fixed' to prevent this issue, I'm pretty sure we'd
see an increase in the number of questions like the OP's.
 
Reply With Quote
 
Thomas Rachel
Guest
Posts: n/a
 
      12-24-2011
Am 22.12.2011 00:48 schrieb Steven D'Aprano:
> On Wed, 21 Dec 2011 18:20:16 -0500, Dennis Lee Bieber wrote:
>
>> For the amount of typing, it's easier to just do a straight line
>> tuple unpack
>>
>>>>> a,b,c = ([],[],[])

>
> Note that tuples are created by the comma, not the round brackets (or
> parentheses for any Americans reading). So the round brackets there are
> strictly redundant:
>
> a, b, c = [], [], []
>
> The only times you need the brackets around a tuple is to control the
> precedence of operations, or for an empty tuple.


IBTD:

a=((a, b) for a, b, c in some_iter)
b=[(1, c) for <whatever>]

Without the round brackets, it is a syntax error.


Thomas
 
Reply With Quote
 
Thomas Rachel
Guest
Posts: n/a
 
      12-24-2011
Am 22.12.2011 00:20 schrieb Dennis Lee Bieber:

> The key one is that lists ([] defines a list, not an array) are
> "mutable". Your "7" is not mutable.


Strictly spoken, that's only a "side show" where the effect is visible.

The real key concept is that [] creates *one* object which is then
assigned to the three names. That's the same for mutable and immutable
objects.

But only the modification which happens on mutable objects turns it into
a problem.

The rest o your explanation is 100% correct.


Thomas
 
Reply With Quote
 
Thomas Rachel
Guest
Posts: n/a
 
      12-24-2011
Am 21.12.2011 23:25 schrieb Eric:

> Is it true that if I want to create an array or arbitrary size such
> as:
> for a in range(n):
> x.append(<some function...>)
>
> I must do this instead?
> x=[]
> for a in range(n):
> x.append(<some function...>)


Of course - your x must exist before using it.

> Now to my actual question. I need to do the above for multiple arrays
> (all the same, arbitrary size). So I do this:
> x=y=z=[]
> for a in range(n):
> x.append(<some function...>)
> y.append(<some other function...>)
> z.append(<yet another function...>)
> Also, is there a more pythonic way to do "x=[], y=[], z=[]"?


You could do:

def create_xyz(n):
for a in range(n):
yield <some function...>, <some other function...>, \
<yet another function...>)

x, y, z = zip(*create_xyz(11))

or, if you want x, y, z to be lists,

x, y, z =[list(i) for i in zip(*create_xyz(11))]

..


Thomas
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
.NET 2.0 ASPx Page does not load, but HTM does prabhupr@hotmail.com ASP .Net 1 02-08-2006 12:57 PM
Button OnClick does not fire on first postback, but does on second Janet Collins ASP .Net 0 01-13-2006 10:08 PM
Does the 2.0 Framework come out when Visual Studio .NET 2005 does? needin4mation@gmail.com ASP .Net 3 10-07-2005 12:55 AM
CS0234 Global does not exist ... but it genuinely does Bill Johnson ASP .Net 0 07-08-2005 06:34 PM
Does no one else think microsoft does a poor job? =?Utf-8?B?SmVyZW15IEx1bmRncmVu?= Wireless Networking 2 11-20-2004 12:17 AM



Advertisments