Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.python > #17049 > unrolled thread
| Started by | Terry Reedy <tjreedy@udel.edu> |
|---|---|
| First post | 2011-12-12 10:52 -0500 |
| Last post | 2011-12-13 12:14 -0800 |
| Articles | 14 — 6 participants |
Back to article view | Back to comp.lang.python
This discussion starts older than the indexed window; earlier articles aren't shown. The article labeled Started by
below is the oldest one visible, not the original post.
Re: Verbose and flexible args and kwargs syntax Terry Reedy <tjreedy@udel.edu> - 2011-12-12 10:52 -0500
Re: Verbose and flexible args and kwargs syntax Eelco <hoogendoorn.eelco@gmail.com> - 2011-12-12 09:12 -0800
Re: Verbose and flexible args and kwargs syntax Terry Reedy <tjreedy@udel.edu> - 2011-12-12 16:58 -0500
Re: Verbose and flexible args and kwargs syntax Eelco <hoogendoorn.eelco@gmail.com> - 2011-12-12 15:40 -0800
Re: Verbose and flexible args and kwargs syntax Ian Kelly <ian.g.kelly@gmail.com> - 2011-12-12 18:41 -0700
Re: Verbose and flexible args and kwargs syntax Eelco <hoogendoorn.eelco@gmail.com> - 2011-12-13 00:44 -0800
Re: Verbose and flexible args and kwargs syntax Eelco <hoogendoorn.eelco@gmail.com> - 2011-12-13 01:26 -0800
Re: Verbose and flexible args and kwargs syntax Ian Kelly <ian.g.kelly@gmail.com> - 2011-12-13 11:15 -0700
Re: Verbose and flexible args and kwargs syntax Eelco <hoogendoorn.eelco@gmail.com> - 2011-12-13 12:32 -0800
Re: Verbose and flexible args and kwargs syntax Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2011-12-13 01:34 +0000
Re: Verbose and flexible args and kwargs syntax alex23 <wuwei23@gmail.com> - 2011-12-12 16:27 -0800
Re: Verbose and flexible args and kwargs syntax Eelco <hoogendoorn.eelco@gmail.com> - 2011-12-13 00:30 -0800
Re: Verbose and flexible args and kwargs syntax Cameron Simpson <cs@zip.com.au> - 2011-12-14 06:11 +1100
Re: Verbose and flexible args and kwargs syntax Eelco <hoogendoorn.eelco@gmail.com> - 2011-12-13 12:14 -0800
| From | Terry Reedy <tjreedy@udel.edu> |
|---|---|
| Date | 2011-12-12 10:52 -0500 |
| Subject | Re: Verbose and flexible args and kwargs syntax |
| Message-ID | <mailman.3550.1323705162.27778.python-list@python.org> |
On 12/12/2011 4:12 AM, Eelco Hoogendoorn wrote: >> The above examples are seldom needed in Python because we have one >> general method to repeatedly split a sequence into head and tail. > >> it = iter(iterable) # 'it' now represents the sequenced iterable >> head = next(it) # 'it' now represents the tail after removing the head > >> In other words, next(it) encompasses all of your examples and many more. >> Because 'it' is mutated to represent the tail, it does not need to be >> rebound and therefore is not. > > > The question in language design is never 'could we do these things > before'. The answer is obvious: yes our CPUs are turing complete; we can > do anything. The question is; how would we like to do them? > > So do you think the new head/tail unpacking features in python 3 are > entirely uncalled for? No, *target unpacking (singular) is quite useful in specialized cases. But it is not specifically head/tail unpacking. >>> a,*b,c = 1,2,3,4,5,6 >>> a,b,c (1, [2, 3, 4, 5], 6) >>> *a,b,c = 1,2,3,4,5 >>> a,b,c ([1, 2, 3], 4, 5) > I personally quite like them, but I would like them to be more general. It already is. The *target can be anywhere in the sequence. -- Terry Jan Reedy
[toc] | [next] | [standalone]
| From | Eelco <hoogendoorn.eelco@gmail.com> |
|---|---|
| Date | 2011-12-12 09:12 -0800 |
| Message-ID | <e31c5737-5514-4031-acdd-4882fe11b867@y7g2000vbe.googlegroups.com> |
| In reply to | #17049 |
> > I personally quite like them, but I would like them to be more general. > > It already is. The *target can be anywhere in the sequence. Im not sure if this is a genuine understanding, or trollish obtuseness. Yes, the target can be anywhere in the sequence. And yes, the resulting list can contain objects of any type, so its very flexible in that regard too. But to relate it to the topic of this thread: no, the syntax does not allow one to select the type of the resulting sequence. It always constructs a list. Yes, we can cast the list to be whatever we want on the next line, but the question is whether this language design can be improved upon. The choice of a list feels arbitrary, adding another line to cast it to something else would be even more verbose, and whats more, there would be serious performance implications if one should seek to apply this pattern to a deque/linkedlist; it would make taking off the head/tail of the list from a constant to a linear operation. That is: >>> head, deque(tail) = somedeque Is better in every way I can think of (readability, consistence, performance) than: >>> head, *tail = somedeque >>> tail = deque(tail)
[toc] | [prev] | [next] | [standalone]
| From | Terry Reedy <tjreedy@udel.edu> |
|---|---|
| Date | 2011-12-12 16:58 -0500 |
| Message-ID | <mailman.3571.1323727128.27778.python-list@python.org> |
| In reply to | #17065 |
On 12/12/2011 12:12 PM, Eelco wrote: > Im not sure if this is a genuine understanding, or trollish > obtuseness. If you are referring to what I write, it is based on genuine understanding of Python. > Yes, the target can be anywhere in the sequence. And yes, the > resulting list can contain objects of any type, so its very flexible > in that regard too. > > But to relate it to the topic of this thread: no, the syntax does not > allow one to select the type of the resulting sequence. It always > constructs a list. One use case of *target is to ignore the stuff collected in the target because one only wants a few end values from the iterable. Another is to pull stuff out because one wants to iterate through the rest. For both uses, a list is as good as anything. > Yes, we can cast the list to be whatever we want on the next line, Convert. For the very few cases one wants to do this, it is quite adequate. > but the question is whether this language design can be improved upon. Not easily. > The choice of a list feels arbitrary, On the contrary, a list is precisely what is needed to collect an indefinite number of leftovers. > adding another line to cast it to > something else would be even more verbose, and whats more, there would > be serious performance implications if one should seek to apply this > pattern to a deque/linkedlist; it would make taking off the head/tail > of the list from a constant to a linear operation. For a linked list, no *target and no copying is needed: head, tail = llist >>>> head, deque(tail) = somedeque > > Is better in every way I can think of (readability, consistence, > performance) than: >>>> head, *tail = somedeque >>>> tail = deque(tail) But your suggestion is much worse in each way than head = somedeque.popleft() To repeat, there is no reason to copy even once. If one does not want to mutate the deque, then one mutates an iterator view of the deque. -- Terry Jan Reedy
[toc] | [prev] | [next] | [standalone]
| From | Eelco <hoogendoorn.eelco@gmail.com> |
|---|---|
| Date | 2011-12-12 15:40 -0800 |
| Message-ID | <bdd08297-8fdd-47a2-a435-b12627bd6482@i6g2000vbh.googlegroups.com> |
| In reply to | #17085 |
> > Im not sure if this is a genuine understanding, or trollish > > obtuseness. > > If you are referring to what I write, it is based on genuine > understanding of Python. This is getting 'interesting'. In a way. I meant to write 'misunderstanding', as I think the context made quite clear. So again this adds another layer of doubt as to whether you are being obtuse for its own sake, or if there is yet another layer of misunderstanding stacked on top of the others. Either way, lets continue with the benefit of the doubt. > One use case of *target is to ignore the stuff collected in the target > because one only wants a few end values from the iterable. Another is to > pull stuff out because one wants to iterate through the rest. For both > uses, a list is as good as anything. So what is the point of having different sequence types, if a list can do anything? I would argue that the different performance characteristics and differences in semantics give each sequence type ample reason for existence. > Convert. For the very few cases one wants to do this, it is quite adequate. Or so you opine. As you may recall, the original idea was motivated by args/kwargs syntactic clarity and flexibility; I merely shifted focus to this use case of collection unpacking since it is somewhat simpler and easier to discuss. Keep that in mind, should you seek to build a case for that assertion in the future. > > but the question is whether this language design can be improved upon. > > Not easily. Again, so you opine. Care to give a refutation of my proposed double colon syntax? Ignoring for a moment whether or not it is useful; does it clash with anything? I havnt been able to think of anything in the past few hours, but im not taking that to mean much; there are probably some subtleties I am overlooking. I think it dos not clash with slicing syntax for instance, but im not sure. > For a linked list, no *target and no copying is needed: > > head, tail = llist I have no idea what this means. > >>>> head, deque(tail) = somedeque > > > Is better in every way I can think of (readability, consistence, > > performance) than: > >>>> head, *tail = somedeque > >>>> tail = deque(tail) > > But your suggestion is much worse in each way than > > head = somedeque.popleft() No its not. First of all, its not semantically equivalent; popleft mutates a collection type, and collection unpacking does not; it creates a set of disjoint views of the collection's data. Whether its worse in terms of readability is debatable, but in terms of the other two stated metrics, your claim of it being any kind of worse is objectively false. Furthermore, this brings us back again to the point I raised several times before. Yes, obviously you can already DO these things, but NOT within the same uniform collection unpacking syntactic construct. Again, you have failed to point out what is wrong with supplying a type constrain to python and let it do the right thing based on that; to reiterate: head, tail::deque = deque No need to mutate anything; python can create the view of the linkedlist internally. A single unambigious syntax, and single unambigious semantics, for all sequence types. Whats not to like? If you dont like the extra characters you have to type; there is of course such a thing as defaults. You can choose: head, tail:: = deque; if the type constraint is omitted, we could make tail a list by default, or my preferred solution, infer it from the right hand side type. In case of the former, all you had to do was type :: instead of *, and your python universe would otherwise be completely unchanged. If thats 'not easily', I dont know what is. > To repeat, there is no reason to copy even once. If one does not want to > mutate the deque, then one mutates an iterator view of the deque. And arrive at yet another construction to do the same thing.
[toc] | [prev] | [next] | [standalone]
| From | Ian Kelly <ian.g.kelly@gmail.com> |
|---|---|
| Date | 2011-12-12 18:41 -0700 |
| Message-ID | <mailman.3574.1323740526.27778.python-list@python.org> |
| In reply to | #17090 |
On Mon, Dec 12, 2011 at 4:40 PM, Eelco <hoogendoorn.eelco@gmail.com> wrote:
>> For a linked list, no *target and no copying is needed:
>>
>> head, tail = llist
>
> I have no idea what this means.
Each node of a linked list consists of a data member and a "next"
member, that holds the next node in the list. The natural container
for this and the way it is usually implemented in Python is a
2-element tuple. For example:
llist = ('one', ('two', ('three', ('four', None))))
would be a linked list as typically constructed in Python, and it can
be used in pretty much the same way that lists are used in Lisp. The
result of the operation:
head, tail = llist
is:
head = 'one'
tail = ('two', ('three', ('four', None)))
and as Terry pointed out, no copying is required to do this. I
believe deque is also implemented as a doubly-linked list, which is
probably why you keep referring to it as such, but that is an
implementation detail. When you say "linked list" in relation to
Python, the preceding is what comes to mind.
>> >>>> head, deque(tail) = somedeque
>>
>> > Is better in every way I can think of (readability, consistence,
>> > performance) than:
>> >>>> head, *tail = somedeque
>> >>>> tail = deque(tail)
>>
>> But your suggestion is much worse in each way than
>>
>> head = somedeque.popleft()
>
> No its not. First of all, its not semantically equivalent; popleft
> mutates a collection type, and collection unpacking does not; it
> creates a set of disjoint views of the collection's data. Whether its
> worse in terms of readability is debatable, but in terms of the other
> two stated metrics, your claim of it being any kind of worse is
> objectively false.
I definitely disagree on readability. Skimming this thread as I have
been, it took me a while to get that your proposed syntax would create
a second deque sharing internal state with the original, rather than
creating a simple copy of the deque, which is what it looks like it
should do.
Incidentally, while that change is not really central to your syntax
proposal, I think it would be very messy. For example, how do you
propose keeping the length elements in sync? Inserting an item in one
may or may not affect the length of the other. If I append an item to
the end of one deque, should the other automatically be extended as
well? What if the tail node of the second deque occurs after the tail
node of the deque being appended? Does the appended element then get
inserted into the middle of the second deque (I think it would have to
be)? If I insert an element into the longer (second) deque that just
happens to be immediately after the tail of the shorter deque, does
*that* cause the shorter deque to be automatically extended? And
likewise for operations at the head of the deque.
None of these questions have obvious answers as to the "right" way to
it, and for that reason I think this is probably best left to the user
to implement a custom deque view class with whatever semantics they
prefer.
> Furthermore, this brings us back again to the point I raised several
> times before. Yes, obviously you can already DO these things, but NOT
> within the same uniform collection unpacking syntactic construct.
> Again, you have failed to point out what is wrong with supplying a
> type constrain to python and let it do the right thing based on that;
> to reiterate:
>
> head, tail::deque = deque
Python users generally follow the rule "explicit is better than
implicit". Setting a general constraint and letting the language "do
the right thing" is a kind of black magic that feels off because it
tends to break that rule. But that's not to say that black magic
never wins -- just look at super() and the MRO.
> If you dont like the extra characters you have to type; there is of
> course such a thing as defaults. You can choose:
> head, tail:: = deque; if the type constraint is omitted, we could make
> tail a list by default, or my preferred solution, infer it from the
> right hand side type.
I prefer the former. If it always creates a list by default, then the
programmer reading this code three years later knows exactly what the
type of tail is. If it instead infers it from the sequence being
unpacked, then the programmer is forced to infer it as well, and it
won't necessarily be obvious or even consistent.
Cheers,
Ian
[toc] | [prev] | [next] | [standalone]
| From | Eelco <hoogendoorn.eelco@gmail.com> |
|---|---|
| Date | 2011-12-13 00:44 -0800 |
| Message-ID | <2ff41b2e-90e3-4fae-9951-67bb257ed6ed@m10g2000vbc.googlegroups.com> |
| In reply to | #17099 |
On Dec 13, 2:41 am, Ian Kelly <ian.g.ke...@gmail.com> wrote:
> On Mon, Dec 12, 2011 at 4:40 PM, Eelco <hoogendoorn.ee...@gmail.com> wrote:
> >> For a linked list, no *target and no copying is needed:
>
> >> head, tail = llist
>
> > I have no idea what this means.
>
> Each node of a linked list consists of a data member and a "next"
> member, that holds the next node in the list. The natural container
> for this and the way it is usually implemented in Python is a
> 2-element tuple. For example:
>
> llist = ('one', ('two', ('three', ('four', None))))
>
> would be a linked list as typically constructed in Python, and it can
> be used in pretty much the same way that lists are used in Lisp. The
> result of the operation:
>
> head, tail = llist
>
> is:
>
> head = 'one'
> tail = ('two', ('three', ('four', None)))
>
> and as Terry pointed out, no copying is required to do this. I
> believe deque is also implemented as a doubly-linked list, which is
> probably why you keep referring to it as such, but that is an
> implementation detail. When you say "linked list" in relation to
> Python, the preceding is what comes to mind.
'for i in llist' is not quite going to fly is it? Thats probably the
reason noone ever uses that construct; its not a proper sequence type.
> >> >>>> head, deque(tail) = somedeque
>
> >> > Is better in every way I can think of (readability, consistence,
> >> > performance) than:
> >> >>>> head, *tail = somedeque
> >> >>>> tail = deque(tail)
>
> >> But your suggestion is much worse in each way than
>
> >> head = somedeque.popleft()
>
> > No its not. First of all, its not semantically equivalent; popleft
> > mutates a collection type, and collection unpacking does not; it
> > creates a set of disjoint views of the collection's data. Whether its
> > worse in terms of readability is debatable, but in terms of the other
> > two stated metrics, your claim of it being any kind of worse is
> > objectively false.
>
> I definitely disagree on readability. Skimming this thread as I have
> been, it took me a while to get that your proposed syntax would create
> a second deque sharing internal state with the original, rather than
> creating a simple copy of the deque, which is what it looks like it
> should do.
Thats a matter of reading up on the semantics of collection unpacking.
To be honest I dont even know what they are for lists, since I dont
use python 3. But whatever is the case, the important thing is that
the semantics should be uniform regardless of the type to be unpacked.
> Incidentally, while that change is not really central to your syntax
> proposal, I think it would be very messy. For example, how do you
> propose keeping the length elements in sync? Inserting an item in one
> may or may not affect the length of the other. If I append an item to
> the end of one deque, should the other automatically be extended as
> well? What if the tail node of the second deque occurs after the tail
> node of the deque being appended? Does the appended element then get
> inserted into the middle of the second deque (I think it would have to
> be)? If I insert an element into the longer (second) deque that just
> happens to be immediately after the tail of the shorter deque, does
> *that* cause the shorter deque to be automatically extended? And
> likewise for operations at the head of the deque.
>
> None of these questions have obvious answers as to the "right" way to
> it, and for that reason I think this is probably best left to the user
> to implement a custom deque view class with whatever semantics they
> prefer.
Good point. Copy-on-write semantics could be used, but really one
should have several linked list types reflecting the underlying
implementations. I would like to have an immutable singly linked list
builtin of the standard functional type, which you can only unpack
from one end and renders these issues moot, plus a builtin doubly
linked list with copy-on-write or copy-on-unpacking semantics.
> > Furthermore, this brings us back again to the point I raised several
> > times before. Yes, obviously you can already DO these things, but NOT
> > within the same uniform collection unpacking syntactic construct.
> > Again, you have failed to point out what is wrong with supplying a
> > type constrain to python and let it do the right thing based on that;
> > to reiterate:
>
> > head, tail::deque = deque
>
> Python users generally follow the rule "explicit is better than
> implicit". Setting a general constraint and letting the language "do
> the right thing" is a kind of black magic that feels off because it
> tends to break that rule. But that's not to say that black magic
> never wins -- just look at super() and the MRO.
We are not talking black magic here; we are talking about an EXPLICIT
type constraint provided on the very same line.
> > If you dont like the extra characters you have to type; there is of
> > course such a thing as defaults. You can choose:
> > head, tail:: = deque; if the type constraint is omitted, we could make
> > tail a list by default, or my preferred solution, infer it from the
> > right hand side type.
>
> I prefer the former. If it always creates a list by default, then the
> programmer reading this code three years later knows exactly what the
> type of tail is. If it instead infers it from the sequence being
> unpacked, then the programmer is forced to infer it as well, and it
> won't necessarily be obvious or even consistent.
Well perhaps, but not always knowing the type of your objects at write-
time is inherent to weakly typed languages; this happens all the time.
Not knowing the type of the sequence to be unpacked is in a sense an
asset; I can use this construct in a function, and unpack any sequence
type in a manner appropriate for it. About the result of the unpacking
I will know just as much as about the input to it; that they are the
same type.
[toc] | [prev] | [next] | [standalone]
| From | Eelco <hoogendoorn.eelco@gmail.com> |
|---|---|
| Date | 2011-12-13 01:26 -0800 |
| Message-ID | <824d74b4-5495-447a-a9cb-addc22092a44@da3g2000vbb.googlegroups.com> |
| In reply to | #17109 |
> > Python users generally follow the rule "explicit is better than > > implicit". Setting a general constraint and letting the language "do > > the right thing" is a kind of black magic that feels off because it > > tends to break that rule. But that's not to say that black magic > > never wins -- just look at super() and the MRO. > > We are not talking black magic here; we are talking about an EXPLICIT > type constraint provided on the very same line. To hammer that point home: would you say the following C# code performs 'black magic'? float x = 3; After all, exactly the same thing is going on; C# will 'do the right thing'; convert the integer literal 3 to a floating point value, based on the type constraint placed on x.
[toc] | [prev] | [next] | [standalone]
| From | Ian Kelly <ian.g.kelly@gmail.com> |
|---|---|
| Date | 2011-12-13 11:15 -0700 |
| Message-ID | <mailman.3610.1323800154.27778.python-list@python.org> |
| In reply to | #17109 |
On Tue, Dec 13, 2011 at 1:44 AM, Eelco <hoogendoorn.eelco@gmail.com> wrote:
> 'for i in llist' is not quite going to fly is it? Thats probably the
> reason noone ever uses that construct; its not a proper sequence type.
Not really a problem, because fortunately Python makes it super-easy
to create custom iterators.
def listiter(llist):
while llist:
head, llist = llist
yield head
And you're done. If you like, you could also wrap this up in a class
with all the sequence-related magic methods you want, although you
lose the simplicity of the literal syntax by doing so. If this is
rarely used, it is more likely because custom containers are going to
be less efficient than built-ins, but if you want to do functional
programming and are not overly concerned with the speed of iteration,
this is not a bad way to do it.
> Good point. Copy-on-write semantics could be used, but really one
> should have several linked list types reflecting the underlying
> implementations. I would like to have an immutable singly linked list
> builtin of the standard functional type, which you can only unpack
> from one end and renders these issues moot, plus a builtin doubly
> linked list with copy-on-write or copy-on-unpacking semantics.
Copy-on-write could be implemented with any type. You don't need a
doubly linked list for that.
> We are not talking black magic here; we are talking about an EXPLICIT
> type constraint provided on the very same line.
An explicit type constraint with very different semantics depending on
what particular type you specify and what particular type you're
unpacking from, as I had understood it before. Now you seem to be
saying that it would always be a copy, but sharing state with
copy-on-write possible, which is a different situation.
> Well perhaps, but not always knowing the type of your objects at write-
> time is inherent to weakly typed languages; this happens all the time.
> Not knowing the type of the sequence to be unpacked is in a sense an
> asset; I can use this construct in a function, and unpack any sequence
> type in a manner appropriate for it. About the result of the unpacking
> I will know just as much as about the input to it; that they are the
> same type.
Just because the issue is inherent doesn't mean we should contribute
to it. Knowing that an object is an arbitrary sequence is fine if all
you want to do is iterate and index it. If you want to do anything
else, then it's important to know the type. The copy-on-write
suggestion does make the type-matching approach a bit more attractive.
On the other hand, it's also more fragile (what if the type being
unpacked can't be constructed from an iterable? For example, a
database cursor), so that approach potentially needs additional
error-handling.
Anyway, the more I think about it, that concern is really more of an
issue for straight copying. One of my pet peeves is that I prefer
list(x) for copying sequences rather than the more common x[::]. The
latter is fine if all I need is an immutable sequence of uncertain
type to iterate and index over -- but then why did I need to make a
copy? Unpacking implies different use cases, though, and maybe a good
argument can be made for it to match type.
[toc] | [prev] | [next] | [standalone]
| From | Eelco <hoogendoorn.eelco@gmail.com> |
|---|---|
| Date | 2011-12-13 12:32 -0800 |
| Message-ID | <26b97534-1624-4afb-8869-f04afc800e22@4g2000yqu.googlegroups.com> |
| In reply to | #17159 |
On Dec 13, 7:15 pm, Ian Kelly <ian.g.ke...@gmail.com> wrote: > On Tue, Dec 13, 2011 at 1:44 AM, Eelco <hoogendoorn.ee...@gmail.com> wrote: > > 'for i in llist' is not quite going to fly is it? Thats probably the > > reason noone ever uses that construct; its not a proper sequence type. > > Not really a problem, because fortunately Python makes it super-easy > to create custom iterators. > > def listiter(llist): > while llist: > head, llist = llist > yield head > > And you're done. If you like, you could also wrap this up in a class > with all the sequence-related magic methods you want, although you > lose the simplicity of the literal syntax by doing so. If this is > rarely used, it is more likely because custom containers are going to > be less efficient than built-ins, but if you want to do functional > programming and are not overly concerned with the speed of iteration, > this is not a bad way to do it. Fair enough. Still, I dont readily see myself using the construct, and I do feel myself longing for something like that to be included as a builtin collection type. Im not sure why python is so stingy with the collections it provides. > > Good point. Copy-on-write semantics could be used, but really one > > should have several linked list types reflecting the underlying > > implementations. I would like to have an immutable singly linked list > > builtin of the standard functional type, which you can only unpack > > from one end and renders these issues moot, plus a builtin doubly > > linked list with copy-on-write or copy-on-unpacking semantics. > > Copy-on-write could be implemented with any type. You don't need a > doubly linked list for that. True > > We are not talking black magic here; we are talking about an EXPLICIT > > type constraint provided on the very same line. > > An explicit type constraint with very different semantics depending on > what particular type you specify and what particular type you're > unpacking from, as I had understood it before. Now you seem to be > saying that it would always be a copy, but sharing state with > copy-on-write possible, which is a different situation. Yes, I think consistent semantics over all sequence types is very important. Although, returning a view for immutable collections like tuples and 'functional lists' (for lack of a better term), and always returning a copy for mutable container types (lists and doubly-linked- lists / deques) is not so bad either, imo. Just one extra simple rule that is clear and obvious enough. > > Well perhaps, but not always knowing the type of your objects at write- > > time is inherent to weakly typed languages; this happens all the time. > > Not knowing the type of the sequence to be unpacked is in a sense an > > asset; I can use this construct in a function, and unpack any sequence > > type in a manner appropriate for it. About the result of the unpacking > > I will know just as much as about the input to it; that they are the > > same type. > > Just because the issue is inherent doesn't mean we should contribute > to it. How are we contributing to it? If we dont know the type of the RHS, we dont know the type of the LHS either, but its not like we lost any information. If we do know the type of the RHS, then we do know the type of the LHS as well; its conserved. > Anyway, the more I think about it, that concern is really more of an > issue for straight copying. One of my pet peeves is that I prefer > list(x) for copying sequences rather than the more common x[::]. The > latter is fine if all I need is an immutable sequence of uncertain > type to iterate and index over -- but then why did I need to make a > copy? Unpacking implies different use cases, though, and maybe a good > argument can be made for it to match type. Thanks for the constructive feedback; something to think about.
[toc] | [prev] | [next] | [standalone]
| From | Steven D'Aprano <steve+comp.lang.python@pearwood.info> |
|---|---|
| Date | 2011-12-13 01:34 +0000 |
| Message-ID | <4ee6abac$0$11091$c3e8da3@news.astraweb.com> |
| In reply to | #17085 |
On Mon, 12 Dec 2011 16:58:33 -0500, Terry Reedy wrote: > On 12/12/2011 12:12 PM, Eelco wrote: >> Yes, we can cast the list to be whatever we want on the next line, > > Convert. For the very few cases one wants to do this, it is quite > adequate. +1 with the small proviso that there's not much you can usefully do with a dict. If you convert to an ordered dict, the initial order is lost by the time you see it; if you want to allow duplicates, duplicates are likewise lost (or in a function call, an exception is raised). In Python 4000, I'd like to see some way to pass arbitrary parameters to functions, including duplicates. That is, emulating the richness of command line argument handling in functions. In Python 3.x, I'd like to see OrderedDict become a built-in, and then **kwargs can collect named arguments in an ordered dict without losing the order. -- Steven
[toc] | [prev] | [next] | [standalone]
| From | alex23 <wuwei23@gmail.com> |
|---|---|
| Date | 2011-12-12 16:27 -0800 |
| Message-ID | <e8c21dc4-e971-410c-a9ec-55f4fb3d1db6@e8g2000prb.googlegroups.com> |
| In reply to | #17065 |
On Dec 13, 3:12 am, Eelco <hoogendoorn.ee...@gmail.com> wrote: > But to relate it to the topic of this thread: no, the syntax does not > allow one to select the type of the resulting sequence. It always > constructs a list. So by this argument, _every_ function that returns a list should take an optional argument to specify an alternative form of sequence. What, exactly, is so onerous about coercing your list to _whatever_ type you want? You know, like everybody else has been. What does this _gain_ you other than one less line of code?
[toc] | [prev] | [next] | [standalone]
| From | Eelco <hoogendoorn.eelco@gmail.com> |
|---|---|
| Date | 2011-12-13 00:30 -0800 |
| Message-ID | <d6a73ede-4ad9-4380-b9c1-5da30850e764@o1g2000vbe.googlegroups.com> |
| In reply to | #17091 |
On Dec 13, 1:27 am, alex23 <wuwe...@gmail.com> wrote: > On Dec 13, 3:12 am, Eelco <hoogendoorn.ee...@gmail.com> wrote: > > > But to relate it to the topic of this thread: no, the syntax does not > > allow one to select the type of the resulting sequence. It always > > constructs a list. > > So by this argument, _every_ function that returns a list should take > an optional argument to specify an alternative form of sequence. > > What, exactly, is so onerous about coercing your list to _whatever_ > type you want? You know, like everybody else has been. > > What does this _gain_ you other than one less line of code? 1) Turning two lines of code into a single more readable one is nothing to scoff at 2) After-the-fact conversion is O(n), getting the view you want right away is O(1) Not every function needs this flexibility; many specialized functions could not care less. But collection unpacking is quite a general thing, and for the record; slicing a tuple returns a tuple. Would you rather have that return a list too?
[toc] | [prev] | [next] | [standalone]
| From | Cameron Simpson <cs@zip.com.au> |
|---|---|
| Date | 2011-12-14 06:11 +1100 |
| Message-ID | <mailman.3614.1323803498.27778.python-list@python.org> |
| In reply to | #17106 |
On 13Dec2011 00:30, Eelco <hoogendoorn.eelco@gmail.com> wrote:
| On Dec 13, 1:27 am, alex23 <wuwe...@gmail.com> wrote:
| > On Dec 13, 3:12 am, Eelco <hoogendoorn.ee...@gmail.com> wrote:
| > > But to relate it to the topic of this thread: no, the syntax does not
| > > allow one to select the type of the resulting sequence. It always
| > > constructs a list.
| >
| > So by this argument, _every_ function that returns a list should take
| > an optional argument to specify an alternative form of sequence.
| >
| > What, exactly, is so onerous about coercing your list to _whatever_
| > type you want? You know, like everybody else has been.
| >
| > What does this _gain_ you other than one less line of code?
|
| 1) Turning two lines of code into a single more readable one is
| nothing to scoff at
| 2) After-the-fact conversion is O(n), getting the view you want right
| away is O(1)
Regarding (2), it has already cost you O(n) to get there. So your O(1)
is a little ingenuous.
--
Cameron Simpson <cs@zip.com.au> DoD#743
http://www.cskk.ezoshosting.com/cs/
I'm a volunteer EMT-I on our local ambulance service; one of our Paramedics
calls squid style motorcycle accidents "ZoomSplats", as in "we had a good
ZoomSplat the other night". ;-)
- Scott <traurig@rapnet.sanders.lockheed.com>
[toc] | [prev] | [next] | [standalone]
| From | Eelco <hoogendoorn.eelco@gmail.com> |
|---|---|
| Date | 2011-12-13 12:14 -0800 |
| Message-ID | <0c87865e-d8a2-41b6-91b4-09278ee2ffcf@cs7g2000vbb.googlegroups.com> |
| In reply to | #17162 |
On Dec 13, 8:11 pm, Cameron Simpson <c...@zip.com.au> wrote: > On 13Dec2011 00:30, Eelco <hoogendoorn.ee...@gmail.com> wrote: > | On Dec 13, 1:27 am, alex23 <wuwe...@gmail.com> wrote: > | > On Dec 13, 3:12 am, Eelco <hoogendoorn.ee...@gmail.com> wrote: > | > > But to relate it to the topic of this thread: no, the syntax does not > | > > allow one to select the type of the resulting sequence. It always > | > > constructs a list. > | > > | > So by this argument, _every_ function that returns a list should take > | > an optional argument to specify an alternative form of sequence. > | > > | > What, exactly, is so onerous about coercing your list to _whatever_ > | > type you want? You know, like everybody else has been. > | > > | > What does this _gain_ you other than one less line of code? > | > | 1) Turning two lines of code into a single more readable one is > | nothing to scoff at > | 2) After-the-fact conversion is O(n), getting the view you want right > | away is O(1) > > Regarding (2), it has already cost you O(n) to get there. So your O(1) > is a little ingenuous. Well, yes, but if one takes a given sequence as input (at least O(n) complexity to obtain it in the first place, indeed), and then wants to, say, recursively unwind it, the cost of the total operation is O(n) versus O(n^2) And besides, O(n) < 2*O(n); perhaps of lesser concern than different orders, but still.
[toc] | [prev] | [standalone]
Back to top | Article view | comp.lang.python
csiph-web