Python for Perl programmers
everythingsysadmin.com
everythingsysadmin.com
However, most Python programmers tend to just read the
entire file into one huge string and process it that way.
I feel funny doing that. Having used machines with very
limited amounts of RAM, I tend to try to keep my file
processing to a single line at a time. However, that
method is going the way of the dodo.
contents = file('filename.txt').read()
all_input = sys.stdin.read()
This is not the correct way to do things. The first example given is better. for line in file('filename.txt'):
print line
Generators are a beautiful thing [1][2][1] http://stackoverflow.com/questions/519633/lazy-method-for-re...
Granted, our machine had a perhaps-unusual design in that it had multiple RAID 6 data banks, a very powerful dedicated IO controller, and about 128 GB of RAM. So your mileage may vary.
Unfortunately I don't have access to that machine any more so I can't perform the same benchmark, but I have a nagging feeling that if I ran the tests again with Python 3.2 I'd get different results.
A nicer way to do such things is to open the file with mmap, which does one system call and then just bumps a pointer. mmaps expose both a file and a list-like API.
This is so that the RE isn't compiled each time it's used. These days the RE module maintains an internal cache for compiled RE's, but that wasn't always the case.
The 1.5.2 docs for compile() say "using compile() is more efficient when the expression will be used several times in a single program" while the 2.7.2 docs add the note that "the compiled versions of the most recent patterns passed to re.match(), re.search() or re.compile() are cached, so programs that use only a few regular expressions at a time needn’t worry about compiling regular expressions."
Edit: apparently the cache was present in 1.5.2; it just wasn't documented. In 1.5.2 the cache size was 20. In 2.0 it was increased to 100.
Still: explicit is better than implicit.
As well, I find assigning the RE to a well-named variable tends to make for more readable code. RE patterns can be horribly ugly and I like to get their definitions out of the way of the logic using them.
It worth to be noted that the verbose flag (re.X or re.VERBOSE in Python) may help to get more readable/friendly regexes (by allowing whitespace and comments).
It's a declarative language without symbols or recursion: that means that it's just not well-suited to being "broken down and simplified". You just have to bite the bullet and learn it. With a little practice, the basic features (e.g. beginning/end of line markers, character classes and captures, maybe non-capturing parentheses too) should be readable without trouble.
I agree that for trivial regex it's useless. For instance (directly taken from Python doc) in this case:
a = re.compile(r"""\d + # the integral part
\. # the decimal point
\d * # some fractional digits""", re.X)
b = re.compile(r"\d+\.\d*")
that's useless. But for more complex problems it may be useful (e.g. http://www.doughellmann.com/PyMOTW/re/ I know email matching regexes are not really complex or even a good example of use of regexes but that's the first example I found).Another point is that even if I can read/write (that's the case) regexes other people may have to deal with my code and it's a well known fact that many people doesn't understand/like regex, so splitting them in small "chunks" may help them.
I'm just saying that 90% of the time when users complain about not being able to read a regex, the solution should be "hit the books" not "rewrite the expression".
And no, I simply have to disagree that a separate object instantiation is "more readable" than the straightforward syntax describing the object itself. That this argument should appear in a discussion of a dynamically bound scripting language shows as well as anything why the python community is eating itself. A LISP or Ruby nut would never have made that claim.
The point to having code there is to read it. Hiding it doesn't make it more readable, it just fools you into thinking you understand it better than you do. You probably call your regexes stuff like "split_at_word_boundaries", right? And how many bugs have you had to deal with because the whitespace conventions aren't clear from your source?
It actually took me 30 minutes today to figure out how to do:
text=open('file.txt').read()
without creating 3-5 lines of code which seems excessive for a simple operation.
There are apparently 20 ways to do it in Perl and they need their own CPAN library for it :-( [1]
[1] http://search.cpan.org/~drolsky/File-Slurp-9999.13/extras/sl...
Perl isn't batteries included, but its packages are usually actually tested on multiple versions. This allows for the community to move on its own. There is no dictator, by design. Try #perl for help as well, or the package channel if there is one.
my $file_handle = open(file.txt)
my $text;
while (read $file_handle, $buff, 1024) { $text = $buff }
read returns the number of characters read (0 when it's finished which will end the loop). I don't know of any generic "read" function, so it's up to you to define how many characters at a time and give the $buffer scalar to read into. it's just a different way of doing things
norkakn is a better resource than this comment
my $text = do { local( @ARGV, $/ ) = $file ; <> } ;
For the record, the do() block defines @ARGV (which normally holds the command-line arguments) to contain the value of the $file (presumably a file name), and sets $/ (which is the input record separator) to an undefined value. In Perl, <> is synonymous to <STDIN> which makes it read from stdin. Since @ARGV now contains a file name, Perl will open this file for reading. Since $/ is undefined, Perl will enter in "slurp" mode, and will gobble up the whole file in one shot. Since this is the last statement in the do() block, it will be returned as its value, and stored in $text.
Lots of Perl magic happening here. I advise you against using such shortcuts.
or
my $txt = do { local $/; <$file>; };
are as I know the preferred ways to do it. As a previous comment explained, $/ is the record separator and when you localize it it's value is set to undef. Which means we read the whole filehandle (the second part). As a do block evaluates to the value of the last expression, the contents of the file is the result of the whole expression.
If you're serious about Perl I recommend Modern Perl which is a 250 page really good introduction for the language, intended for programmers.
open( my $fh, '<', $file ) or die "cannot open $file\n";
my $text = do { local( $/ ) ; <$fh> } ;
http://perldoc.perl.org/perlopentut.html
http://perldoc.perl.org/functions/do.html
http://perldoc.perl.org/functions/local.html
http://perldoc.perl.org/perlop.html#I%2fO-OperatorsMy understanding is that Python usually has one established way of doing something, and what you find when you search "Python foo", what you find is usually what you want. Perl has more of a market based approach. I don't think "There Is More Than One Way To Do It" is intended to encourage the reinvention of wheels, that isn't really the Perl way. There often is an established way to do it in Perl and that way is File::Slurp or Template::Toolkit or Moose or DBI::DBD. The packages are great, they have maintainers so they can be updated, and as long as you know to use CPAN, they are easy to find.
On the other hand, that means the difference between a beginner who has problem X and says "Oh I'll look on CPAN for the source of the most popular package for X and see the examples the author put in" and a beginner who says "I don't know how to do that in Perl, where's a tutorial online?" is huge.
A couple of weeks ago there was a big to do in the Perl community that there needed to be more well-written up-to-date results for "how-to" searches. I think the reason that the community got into that situation is that for people who know to use CPAN, the quality curation is taken care of. It is always clear what the top 1 or top 3 packages are for a given use and the place to start is looking at the examples in that package's documentation.
TL;DR : For Perl, CPAN's packages serve as 'reuseable code' as well as ORMs, and web frameworks etc, whereas it seems to me that Python will port most pieces of reusable code into the main language itself.
Edited: Replaced "I don't need to do that in Perl" with "I don't know how to do that in Perl"
When looking at libraries, "There Is More Than One Way To Do It" becomes "More than one library will solve your problem and you're welcome to select the one that makes the speed/size/complexity/feature trade-offs that best fit the project at hand."
This is, absolutely, initially more confusing than "there should be one obvious way to do it", but it has other advantages, especially in the long run.
open(my $fh, "<", "file.txt") or die "wft?"
my @lines = <$fh>;
lines is now an array of lines, you can join them into a single string if you want. open(my $fh, "<", "file.txt") or die "Error reading file: $!";
my @lines = <$fh>;
To slurp into a string rather than an array of lines: open(my $fh, "<", "file.txt") or die "Error reading file: $!";
my $s = join('',<$fh>); my $data = `cat $file`;
Some folks dislike the useful use of cat, but anyone who's ever read a shell script will recognize the idiom. And it's a trivial one-liner much simpler still than the python code .For one-time uses there's not a problem. However, if you find yourself writing what amount to shell scripts in Perl, you might be better off just writing shell scripts.
Broadly, your argument seems to be that spawning processes in the external environment[1] (which, admittedly, is inherently nonportable) is a Bad Thing in perl, and that we shouldn't do it. When I rephrase it like that, does it sound as poo-flinging crazy to you as it does to me?
[1] Let's be honest: a working "cat" is pretty much the single most portable thing you can put between the backticks. If you won't allow this, what will you permit?
My point was more that slurping a file without spawning another process is already quite easy in perl. That method of slurping contradicts common patterns like "while (<$fh>)". I'm not saying it's strictly wrong or even bad, just not necassarily the best option.
Now if you want to just change a language for the sake of changing it, its Ok. But Python and Perl have opposite philosophies. And the actual problem while changing from Python to Perl occurs there.
To me Python looked like Java with a haircut and french beard. That fact simply keeps hovering over me, even in this tutorial all those variable = something.somethingElse.someMethod() thing gives a strong Java vibe .When I used it for the first time, It looked like a language for people who were frustrated with Java but at the same couldn't learn Perl either. It looked like a language designed for such people.
Parsing a program visually hurts my eyes. Especially for large code blocks. Inability to provide easy ways of writing throwaway command line hacks is just not acceptable at all on Unix machine. That's precisely where Perl won over sysadmins during its early days.
Having to bury each statement you suspect under piles of try/catch statements doesn't feel like a scripting language. No multi line lambdas is a major turn off.
Regular expression support looks totally alien and its no way closer to Perl's way $line =~ /<match something>/ and not just that, Matching is just one part. Extraction, substitution et all all part of regular expression operations. Now regexes combined with map/grep functions make parsing a whole lot easier in Perl.
Scoping sucks big time in Python. There is nothing remotely comparable to CPAN.
I don't know which versions to Program in, 2.x or 3.x? There is nothing like Moose and other associated modern perl packages in Python.
Lastly I never needed another C based language for scripting. What I needed was a more extensible language(like Perl6).
Python doesn't serve my scripting needs on Unix. But I agree it has good web frameworks and it may be helpful there.
It doesn't cover idioms like Tom's post, but helps me remember the basic syntax changes when jumping between these languages.
You can do neat one-liners in Python or Ruby but I've always liked Perl for this kind of thing.
I also have a weird penchant for using BASH scripting to do quite complicated things. Just because it can.
In perl,
> my ($a, $b) = '12' =~ /(\d)(\d)/;
In python,
> (a, b) = re.match('(\d)(\d)', '12').groups()
Note the python code here will throw an AttributeError if the match fails, whereas the perl will just assign undef to the variables.
> obj = re.match('(?P<id>\d\d)(?P<name>\w+)')
> id = obj.group('id')
> name = obj.group('name') if (my ($x, $y) = '12' =~ /(\d)(\d)/) {
<use $x and $y here>
}
is the normal idiom.