Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #46422 > unrolled thread

Re: How clean/elegant is Python's syntax?

Started byMa Xiaojun <damage3025@gmail.com>
First post2013-05-30 09:14 +0800
Last post2013-06-01 04:52 +1000
Articles 11 — 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.


Contents

  Re: How clean/elegant is Python's syntax? Ma Xiaojun <damage3025@gmail.com> - 2013-05-30 09:14 +0800
    Re: How clean/elegant is Python's syntax? rusi <rustompmody@gmail.com> - 2013-05-29 19:49 -0700
      Re: How clean/elegant is Python's syntax? Ian Kelly <ian.g.kelly@gmail.com> - 2013-05-30 12:36 -0600
        Re: How clean/elegant is Python's syntax? rusi <rustompmody@gmail.com> - 2013-05-30 11:47 -0700
        Re: How clean/elegant is Python's syntax? John Ladasky <john_ladasky@sbcglobal.net> - 2013-05-30 15:01 -0700
      Re: How clean/elegant is Python's syntax? Chris Angelico <rosuav@gmail.com> - 2013-05-31 04:44 +1000
      Re: How clean/elegant is Python's syntax? Ian Kelly <ian.g.kelly@gmail.com> - 2013-05-30 12:51 -0600
      Re: How clean/elegant is Python's syntax? MRAB <python@mrabarnett.plus.com> - 2013-05-30 20:38 +0100
      Re: How clean/elegant is Python's syntax? Chris Angelico <rosuav@gmail.com> - 2013-05-31 07:28 +1000
      Re: How clean/elegant is Python's syntax? Ian Kelly <ian.g.kelly@gmail.com> - 2013-05-31 09:43 -0600
      Re: How clean/elegant is Python's syntax? Chris Angelico <rosuav@gmail.com> - 2013-06-01 04:52 +1000

#46422 — Re: How clean/elegant is Python's syntax?

FromMa Xiaojun <damage3025@gmail.com>
Date2013-05-30 09:14 +0800
SubjectRe: How clean/elegant is Python's syntax?
Message-ID<mailman.2389.1369876474.3114.python-list@python.org>
On Thu, May 30, 2013 at 8:24 AM, Dan Stromberg <drsalists@gmail.com> wrote:
> I'm finding it kind of hard to imagine not finding Python's syntax and
> semantics pretty graceful.
>
> About the only thing I don't like is:
>
>    var = 1,
>
> That binds var to a tuple (singleton) value, instead of 1.
>
> Oh, and method decorators seem much more complex than they should've been.

Yes, you touched something. IMHO, Python has far more built-in
features so it looks at least complicated from time to time.

For example, some people use "generating 9x9 multiplication table" as
an programming exercise.

What interest me is a one liner:
print '\n'.join(['\t'.join(['%d*%d=%d' % (j,i,i*j) for i in
range(1,10)]) for j in range(1,10)])

I don't like code like this. But Python at least allow such practise.

> But on the whole, python is a pretty beautiful language.  It's not just
> another rehash of Pascal though; if that's what you want you might be better
> off looking elsewhere.

That's a fair point.

[toc] | [next] | [standalone]


#46425

Fromrusi <rustompmody@gmail.com>
Date2013-05-29 19:49 -0700
Message-ID<851ce96a-0223-42b0-8d99-902294c71f58@hc4g2000pbb.googlegroups.com>
In reply to#46422
On May 30, 6:14 am, Ma Xiaojun <damage3...@gmail.com> wrote:
> What interest me is a one liner:
> print '\n'.join(['\t'.join(['%d*%d=%d' % (j,i,i*j) for i in
> range(1,10)]) for j in range(1,10)])

Ha,Ha! The join method is one of the (for me) ugly features of python.
You can sweep it under the carpet with a one-line join function and
then write clean and pretty code:

#joinwith
def joinw(l,sep): return sep.join(l)

def mktable(m,n):
    return [[(j,i,i*j) for i in range(1,m+1)] for j in range(1,n+1)]

def prettyrow(r):
    return joinw(['%d*%d=%d' % ele for ele in r],'\t')

def prettytable(t):
    return joinw([prettyrow(r) for r in t],'\n')

> I don't like code like this. But Python at least allow such practise.

Are you saying VB etc disallow dirty code??  Dirty code is always
possible in all languages. Of course the shape and size and smell of
the dirt will differ

[toc] | [prev] | [next] | [standalone]


#46527

FromIan Kelly <ian.g.kelly@gmail.com>
Date2013-05-30 12:36 -0600
Message-ID<mailman.2443.1369939057.3114.python-list@python.org>
In reply to#46425
On Wed, May 29, 2013 at 8:49 PM, rusi <rustompmody@gmail.com> wrote:
> On May 30, 6:14 am, Ma Xiaojun <damage3...@gmail.com> wrote:
>> What interest me is a one liner:
>> print '\n'.join(['\t'.join(['%d*%d=%d' % (j,i,i*j) for i in
>> range(1,10)]) for j in range(1,10)])
>
> Ha,Ha! The join method is one of the (for me) ugly features of python.
> You can sweep it under the carpet with a one-line join function and
> then write clean and pretty code:
>
> #joinwith
> def joinw(l,sep): return sep.join(l)

I don't object to changing the join method (one of the more
shoe-horned string methods) back into a function, but to my eyes
you've got the arguments backward.  It should be:

def join(sep, iterable): return sep.join(iterable)

Putting the separator first feels more natural to me because I expect
the separator to usually be short as compared to the iterable, which
is often a longer expression (as is the case in both of your
subsequent usages).  Placing the separator first also preserves
consistency of interface with the str.join and bytes.join functions,
as well as the older string.join function.

[toc] | [prev] | [next] | [standalone]


#46530

Fromrusi <rustompmody@gmail.com>
Date2013-05-30 11:47 -0700
Message-ID<0debce7e-f05c-40c4-b688-737e7ad49a40@z10g2000pbn.googlegroups.com>
In reply to#46527
On May 30, 11:36 pm, Ian Kelly <ian.g.ke...@gmail.com> wrote:
> On Wed, May 29, 2013 at 8:49 PM, rusi <rustompm...@gmail.com> wrote:
> > On May 30, 6:14 am, Ma Xiaojun <damage3...@gmail.com> wrote:
> >> What interest me is a one liner:
> >> print '\n'.join(['\t'.join(['%d*%d=%d' % (j,i,i*j) for i in
> >> range(1,10)]) for j in range(1,10)])
>
> > Ha,Ha! The join method is one of the (for me) ugly features of python.
> > You can sweep it under the carpet with a one-line join function and
> > then write clean and pretty code:
>
> > #joinwith
> > def joinw(l,sep): return sep.join(l)
>
> I don't object to changing the join method (one of the more
> shoe-horned string methods) back into a function, but to my eyes
> you've got the arguments backward.  It should be:
>
> def join(sep, iterable): return sep.join(iterable)
>
> Putting the separator first feels more natural to me because I expect
> the separator to usually be short as compared to the iterable, which
> is often a longer expression (as is the case in both of your
> subsequent usages).  Placing the separator first also preserves
> consistency of interface with the str.join and bytes.join functions,
> as well as the older string.join function.

This is a subjective view of course...
My problem is not method vs function but the order.
Ive seen/used join dozens of times. Yet I find
"".join(["apple","bear","cat"])
backkwards as compared to
["apple","bear","cat"].join("")

The consistency is a separate question -- not arguing about that. Just
that I dont like the look

[toc] | [prev] | [next] | [standalone]


#46547

FromJohn Ladasky <john_ladasky@sbcglobal.net>
Date2013-05-30 15:01 -0700
Message-ID<32d47a30-8b74-41f4-a774-c878c60c7f73@googlegroups.com>
In reply to#46527
On Thursday, May 30, 2013 11:36:54 AM UTC-7, Ian wrote:

> I don't object to changing the join method (one of the more 
> shoe-horned string methods) back into a function, but to my eyes
> you've got the arguments backward.  It should be:
>
> def join(sep, iterable): return sep.join(iterable)
> 
> Putting the separator first feels more natural to me because I expect
> the separator to usually be short as compared to the iterable, which
> is often a longer expression (as is the case in both of your
> subsequent usages).  Placing the separator first also preserves 
> consistency of interface with the str.join and bytes.join functions,
> as well as the older string.join function.

That may all be true, but the join() function shown will return a sequence starting with iterable[0] (followed by sep, and then iterable[1], then sep, etc.).  I find it more natural to see iterable as the first argument passed to join() for that reason.  Season to taste, I guess.

[toc] | [prev] | [next] | [standalone]


#46529

FromChris Angelico <rosuav@gmail.com>
Date2013-05-31 04:44 +1000
Message-ID<mailman.2445.1369939485.3114.python-list@python.org>
In reply to#46425
On Fri, May 31, 2013 at 4:36 AM, Ian Kelly <ian.g.kelly@gmail.com> wrote:
> On Wed, May 29, 2013 at 8:49 PM, rusi <rustompmody@gmail.com> wrote:
>> On May 30, 6:14 am, Ma Xiaojun <damage3...@gmail.com> wrote:
>>> What interest me is a one liner:
>>> print '\n'.join(['\t'.join(['%d*%d=%d' % (j,i,i*j) for i in
>>> range(1,10)]) for j in range(1,10)])
>>
>> Ha,Ha! The join method is one of the (for me) ugly features of python.
>> You can sweep it under the carpet with a one-line join function and
>> then write clean and pretty code:
>>
>> #joinwith
>> def joinw(l,sep): return sep.join(l)
>
> I don't object to changing the join method (one of the more
> shoe-horned string methods) back into a function, but to my eyes
> you've got the arguments backward.  It should be:
>
> def join(sep, iterable): return sep.join(iterable)

Trouble is, it makes some sense either way. I often put the larger
argument first - for instance, I would write 123412341324*5 rather
than the other way around - and in this instance, it hardly seems as
clear-cut as you imply. But the function can't be written to take them
in either order, because strings are iterable too. (And functions that
take args either way around aren't better than those that make a
decision.)

ChrisA

[toc] | [prev] | [next] | [standalone]


#46531

FromIan Kelly <ian.g.kelly@gmail.com>
Date2013-05-30 12:51 -0600
Message-ID<mailman.2446.1369939917.3114.python-list@python.org>
In reply to#46425
On Thu, May 30, 2013 at 12:44 PM, Chris Angelico <rosuav@gmail.com> wrote:
> On Fri, May 31, 2013 at 4:36 AM, Ian Kelly <ian.g.kelly@gmail.com> wrote:
>> I don't object to changing the join method (one of the more
>> shoe-horned string methods) back into a function, but to my eyes
>> you've got the arguments backward.  It should be:
>>
>> def join(sep, iterable): return sep.join(iterable)
>
> Trouble is, it makes some sense either way. I often put the larger
> argument first - for instance, I would write 123412341324*5 rather
> than the other way around - and in this instance, it hardly seems as
> clear-cut as you imply. But the function can't be written to take them
> in either order, because strings are iterable too. (And functions that
> take args either way around aren't better than those that make a
> decision.)

The reason I like having the shorter argument first (at least for
function calls) is for when I'm reading the code.  If I'm interested
in the second argument, then to find it I have to scan over the first
argument.  I would rather scan over something short like '\n' than
something longer like a list comprehension.  It sounds like a trivial
thing, but it really does make it easier to find where an expression
starts and ends when the expression is short.

[toc] | [prev] | [next] | [standalone]


#46538

FromMRAB <python@mrabarnett.plus.com>
Date2013-05-30 20:38 +0100
Message-ID<mailman.2448.1369942708.3114.python-list@python.org>
In reply to#46425
On 30/05/2013 19:44, Chris Angelico wrote:
> On Fri, May 31, 2013 at 4:36 AM, Ian Kelly <ian.g.kelly@gmail.com> wrote:
>> On Wed, May 29, 2013 at 8:49 PM, rusi <rustompmody@gmail.com> wrote:
>>> On May 30, 6:14 am, Ma Xiaojun <damage3...@gmail.com> wrote:
>>>> What interest me is a one liner:
>>>> print '\n'.join(['\t'.join(['%d*%d=%d' % (j,i,i*j) for i in
>>>> range(1,10)]) for j in range(1,10)])
>>>
>>> Ha,Ha! The join method is one of the (for me) ugly features of python.
>>> You can sweep it under the carpet with a one-line join function and
>>> then write clean and pretty code:
>>>
>>> #joinwith
>>> def joinw(l,sep): return sep.join(l)
>>
>> I don't object to changing the join method (one of the more
>> shoe-horned string methods) back into a function, but to my eyes
>> you've got the arguments backward.  It should be:
>>
>> def join(sep, iterable): return sep.join(iterable)
>
> Trouble is, it makes some sense either way. I often put the larger
> argument first - for instance, I would write 123412341324*5 rather
> than the other way around - and in this instance, it hardly seems as
> clear-cut as you imply. But the function can't be written to take them
> in either order, because strings are iterable too. (And functions that
> take args either way around aren't better than those that make a
> decision.)
>
And additional argument (pun not intended) for putting sep second is
that you can give it a default value:

    def join(iterable, sep=""): return sep.join(iterable)

[toc] | [prev] | [next] | [standalone]


#46544

FromChris Angelico <rosuav@gmail.com>
Date2013-05-31 07:28 +1000
Message-ID<mailman.2453.1369949301.3114.python-list@python.org>
In reply to#46425
On Fri, May 31, 2013 at 4:51 AM, Ian Kelly <ian.g.kelly@gmail.com> wrote:
> On Thu, May 30, 2013 at 12:44 PM, Chris Angelico <rosuav@gmail.com> wrote:
>> On Fri, May 31, 2013 at 4:36 AM, Ian Kelly <ian.g.kelly@gmail.com> wrote:
>>> I don't object to changing the join method (one of the more
>>> shoe-horned string methods) back into a function, but to my eyes
>>> you've got the arguments backward.  It should be:
>>>
>>> def join(sep, iterable): return sep.join(iterable)
>>
>> Trouble is, it makes some sense either way. I often put the larger
>> argument first - for instance, I would write 123412341324*5 rather
>> than the other way around - and in this instance, it hardly seems as
>> clear-cut as you imply. But the function can't be written to take them
>> in either order, because strings are iterable too. (And functions that
>> take args either way around aren't better than those that make a
>> decision.)
>
> The reason I like having the shorter argument first (at least for
> function calls) is for when I'm reading the code.  If I'm interested
> in the second argument, then to find it I have to scan over the first
> argument.  I would rather scan over something short like '\n' than
> something longer like a list comprehension.  It sounds like a trivial
> thing, but it really does make it easier to find where an expression
> starts and ends when the expression is short.

Yes, I do agree with that argument. But there's more to picking
argument order than simply "sort by predicted length" :) I'm not
saying it's *wrong* to put sep first, just that it's not as
clearly-and-obviously-the-one-right-way as you suggested.

ChrisA

[toc] | [prev] | [next] | [standalone]


#46609

FromIan Kelly <ian.g.kelly@gmail.com>
Date2013-05-31 09:43 -0600
Message-ID<mailman.2493.1370015077.3114.python-list@python.org>
In reply to#46425
On Thu, May 30, 2013 at 1:38 PM, MRAB <python@mrabarnett.plus.com> wrote:
> And additional argument (pun not intended) for putting sep second is
> that you can give it a default value:
>
>    def join(iterable, sep=""): return sep.join(iterable)

One argument against the default is that it is specific to the str
type.  If you then tried to use join with an iterable of bytes objects
and the default sep argument, you would get a TypeError.  At least not
having the default forces you to be explicit about which string type
you're joining.

[toc] | [prev] | [next] | [standalone]


#46624

FromChris Angelico <rosuav@gmail.com>
Date2013-06-01 04:52 +1000
Message-ID<mailman.2501.1370026382.3114.python-list@python.org>
In reply to#46425
On Sat, Jun 1, 2013 at 1:43 AM, Ian Kelly <ian.g.kelly@gmail.com> wrote:
> On Thu, May 30, 2013 at 1:38 PM, MRAB <python@mrabarnett.plus.com> wrote:
>> And additional argument (pun not intended) for putting sep second is
>> that you can give it a default value:
>>
>>    def join(iterable, sep=""): return sep.join(iterable)
>
> One argument against the default is that it is specific to the str
> type.  If you then tried to use join with an iterable of bytes objects
> and the default sep argument, you would get a TypeError.  At least not
> having the default forces you to be explicit about which string type
> you're joining.

What about:

def join(iterable, sep=None):
    if sep is not None: return sep.join(iterable)
    iterable=iter(iterable)
    first = next(iterable)
    return first + type(first)().join(iterable)

Granted, it has some odd error messages if you pass it stuff that isn't strings:

>>> join([[1,2,3],[4,5,6]])
Traceback (most recent call last):
  File "<pyshell#241>", line 1, in <module>
    join([[1,2,3],[4,5,6]])
  File "<pyshell#235>", line 5, in join
    return first + type(first)().join(iterable)
AttributeError: 'list' object has no attribute 'join'

but you'd get that sort of thing anyway.

(NOTE: I am *not* advocating this. I just see it as a solution to one
particular objection.)

ChrisA

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.python


csiph-web