In Python there is no one obvious documentation system (Sphinx, epydoc, pydoctor, ...).
Syntax for working with regular expressions is not builtin in Python.
One-liners are useless in Python (due to whitespace sensitivity).
Chaining of expressions (in functional style) is more cumbersome in Python than in Perl. Compare (from http://www.hidemail.de/blog/perl_tutor.shtml):
Print the canonical sort order in Perl:
say sort grep /\w/, map { chr } 0 .. 255;
Literal translation to Python: print ''.join(sorted(filter(lambda c: re.match(r'\w', c), map(chr, range(256)))))
A more pythonic version: print ''.join(sorted(re.findall(r'\w', string.maketrans('', ''))))
Ruby version: puts (0..255).collect { |i| i.chr }.select { |c| c =~ /\w/ }.sort.join ''
Output: 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz print ''.join(chr(i) for i in range(256) if re.match(r'\w', chr(i))
Learn to use list comprehension.2. where is closing `)`.
3. DRY principle is more important than a couple of parentheses here and there (there could be a heavier function than `chr()`).
And I know list comprehension (and generator expressions, and dictionary comprehension, and set comprehension).
One of versions I've considered for Python was:
print ''.join(sorted(c for c in map(chr, range(256)) if re.match(r'\w', c)))
And even: print ''.join(sorted(c for i in range(256) for c in (chr(i),) if re.match(r'\w', c)))The last ')' character is missing. Sorry about that. I have been spoiled by show-paren-mode.
The DRY principle is great when applied to large swaths of code but in this case, seriously, it is faster and more concise to just write it again. Either the language optimizer will optimize out the extra work (not in CPython though...) or it will not. Either way, your functions would be slower as they have to explicitly allocate either two lists or a list and a tuple unless they are optimized further, not to mention that the added structures will make optimization challenging.
Principles are great in theory but try considering practical aspects once in a while.
DRY is not about performance; it is about: I've changed here some code and oops I've got a bug because I forgot (or didn't know or it is impossible to decide whether it is the same code or not and therefore should we change it or not) to change it in other places.
Performance:
$ python -mtimeit -s"import re" "''.join(sorted(chr(i) for i in range(256) if re.match(r'\w', chr(i))))
1000 loops, best of 3: 1.29 msec per loop
$ python -mtimeit -s"import re, string" "''.join(sorted(re.findall(r'\w', string.maketrans('', ''))))"
10000 loops, best of 3: 60.8 usec per loop
My variant is 20 times faster. However performance doesn't matter in this case.I'm all for practicality but principles are condensed experience and it is dangerous to ignore them without a good reason.
$ python -m timeit -s 'import re' '"".join(chr(i) for i in range(256) if re.match(r"\w", chr(i)))'
1000 loops, best of 3: 841 usec per loop
$ python -m timeit -s 'import re' "''.join(sorted(c for c in map(chr, range(256)) if re.match(r'\w', c)))"
1000 loops, best of 3: 792 usec per loop
$ python -m timeit -s 'import re' "''.join(sorted(c for i in range(256) for c in (chr(i),) if re.match(r'\w', c)))"
1000 loops, best of 3: 921 usec per loop
Your DRY variants (against which my complaint was) are not faster.As to the principle of DRY: Which is easier to debug? my code or your code? mine is certainly easier to read. Principles are the average of large amounts of experience. Its never a good idea to ignore them completely but just blindly following them without keeping in mind the context they were formulated in is just as stupid.
PS: Your version with the re.findall is faster but requires the user to bring up a definition of string.maketrans and re.findall, both things that an experienced python coder would know but its another little thing that they now have to track. OTOH, the generator expressions (especially mine) are straightforward and blindingly obvious as to their purpose.
If u like left to right chains then Perl can also be written like so...
use autobox::Core;
say [ 0..255 ]->map( sub { chr } )->grep( sub { m/\w/ } )->sort->join('');
/I3az/Conversely, I like Python better than Perl in two major departments though:
1) The way you import stuff in Python. If you have a long namespace in Perl you have to type it out every time you instantiate an object. Example:
use Organisation::Project::App::Models::Feature;
my $feature = Organisation::Project::App::Models::Feature->new();
In Python you would do: from organisation.project.app.models import feature;
feat = feature();
It's a small point, but when you have multiple views/actions inside a controller that all use the same model you start to get annoyed typing that namespace in Perl.
2) The native OOP system in Python is much easier than Perl. With Moose this is far less important than it used to be, but comparing core Perl to core Python it is an issue.
However check out the excellent "aliased" module... http://search.cpan.org/dist/aliased/
From its POD...
use aliased 'My::Company::Namespace::Customer';
my $cust = Customer->new;
use aliased 'My::Company::Namespace::Preferred::Customer' => 'Preferred';
my $pref = Preferred->new;