Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
How To Let People Know You're A Bad Python Programmer (artificialcode.blogspot.com)
27 points by _zhqs on Aug 28, 2009 | hide | past | favorite | 37 comments


Call Perl from Python

This is an oldie but a goodie, but a lot of bad programmers don't realize they can make their Python code even worse, if they embed a bunch of untested, legacy, Perl code in it. There is a Perl/Python module that makes this a snap.

Yes, throw in a Perl slight for good measure. A surer way of endearing yourself to your fellow Pythonistas, I know of not. This is not unlike what happens on reddit.com/r/programming, where an opportunity to sneer at Java is never missed, and every kind soul you encounter will gladly regale you with tales of the imaginary programs they claim to have written in Haskell or Lisp.

Perl, that miserable little unwanted orphan of a language, has real anonymous, first-class functions complete with closures. Python, sadly, does not, and that is an undeniable, glaring defect in the language. And for what reason? Because its Benevolent Dictator for Life decreed that functional programming--even in the greatly-diluted form in which one finds it in mainstream languages--is bad and "unpythonic"--heretical, essentially. He recently lashed out against tail call optimization, and before that attempted to exile some Lisp constructs that had been resident in the language for many years, but back-peddled as soon as his subjects threatened to revolt.

When Python catches up to Perl, Ruby, Javascript and every other decent dynamic language in this department, then you can condemn Perl as much as you like. Until that time, hold your tongue.


Why call Perl from Python?

Why not just do everything in Perl?

This is an awful lot of invective from one paragraph that, personally, implies an itinerant bad programmer migrating from 'cool language' to 'new cool language' and carting along everything he'd written before.

On another note, everyone seems to love anonymous, first-class functions with closures, and yet they never give nontrivial examples - what am I missing out on? (For that matter, I still haven't seen what TCO offers that is new, but that was April's issue.)

[edit: http://gmarceau.qc.ca/blog/2009/05/speed-size-and-dependabil... indicates that it doesn't bring anything- any counter offers?]


This is an awful lot of invective from one paragraph that, personally, implies an itinerant bad programmer migrating from 'cool language' to 'new cool language' and carting along everything he'd written before.

If he had meant only that and meant nothing more, he wouldn't have singled out Perl, or he would have done so in a more tactful manner. And ask yourself, is this really a big problem? How often have you actually seen someone embed Perl (or any other language) in Python? Why is that admonition sandwiched between remarks on unit testing and maintaining control flow?

On another note, everyone seems to love anonymous, first-class functions with closures, and yet they never give nontrivial examples - what am I missing out on?

Spend some time with a language that not only supports them but actually encourages their use, and you will see for yourself. For example, both Smalltalk and Ruby make heavy use of blocks, and because of that classes can be written to allow users to greatly customize their behavior without the need of subclassing.

(For that matter, I still haven't seen what TCO offers that is new, but that was April's issue.)

TCO allows programs to, in certain circumstances, reuse existing stack frames for possibly many function invocations. For example, if a function is written to be tail recursive, a VM with TCO could reuse the same stack frame for each recursive function invocation until the terminating condition is reached, at which point the last return value is caught and the frame is popped off the stack. (TCO isn't strictly limited to making tail recursion more efficient, but that is its most often cited benefit.)

The main reason Guido and his Pythonistas have no use for TCO is that they also have no use for recursion. If Python supported TCO, more recursive Python code would probably be written--and that would be very unpythonic.


Spend some time with a language that not only supports them but actually encourages their use, and you will see for yourself.

This isn't an example and does nothing to convince me that it's actually useful. Your suggested application just hints at difficult debugging when a Car object can be a stealth Truck. Maybe it isn't actually difficult, but why is this actually better than subclassing?

TCO allows programs to, in certain circumstances, reuse existing stack frames for possibly many function invocations. For example, if a function is written to be tail recursive, a VM with TCO could reuse the same stack frame for each recursive function invocation until the terminating condition is reached, at which point the last return value is caught and the frame is popped off the stack. (TCO isn't strictly limited to making tail recursion more efficient, but that is its most often cited benefit.)

Sounds like a loop.


Don't fall into the Turing equivalence tarpit. It's indeed possible to rewrite recursive code in terms of iteration and vice versa, but the most natural expression of many algorithms is recursion. If you can convince the compiler and/or runtime to manage your stack for you, you can concentrate on the interesting parts of the algorithm.

It's like the difference between using objects in Smalltalk and writing your own object system in C.


The problem is that adding TCO to a mature and widely-used language introduces a massive compatibility problem!

  If Python supported TCO, more recursive Python code would probably be written
And not be able to run on Python implementations without TCO!

Code that takes advantage of TCO is utterly dependent on it. It is absolutely not an 'implementation detail', or really an 'optimization' -- its presence is a major part of the semantics of any language implementation that does it.


I agree wholeheartedly with the first half of your comment, but the second half is the same uninformed dogma you rail against in the first!

Python is not really a functional programming language -- it has statements and suites, neither of which are first-class.

lambda is implemented as an inline (suite-less) value-returning statement (like the ternary statement) because dealing with indentation would be a bitch. Since statements cannot contain other statements outside of suites, it's impossible to implement full-fledged anonymous functions in the language grammar without breaking something.

While I'd love TCO in python, I like the stack traces better (ever dealt with a stray head [] in GHC?).


> first-class.

I'm not sure I follow. This looks first-class to me.

  def name_printer(name):
      def printer():
          print(name)
      return printer

  erlanger_printer = name_printer('erlanger')
Python doesn't support creating anonymous functions, but functions are first-class. Sorry if you already knew this; it seems like you know Python pretty well so I'm sure you do.


Of course functions are first-class, and the lambda statement does return anonymous functions. Functions in Python are just objects that have a __call__ method, and methods are just functions partially-applied to the object they are bound on -- LOVELY METACIRCULARITY

What aren't first class are statements and suites (indented blocks of expressions) -- they're part of the syntax and thus can't be constructed or referred to. Particularly nasty is the way non-value-returning statements can't be used in expressions passed to other statements.

Your example is perfect -- in Python < 3, print is a statement and not a built-in function!

  # this is invalid syntax:
  name_printer = lambda x: lambda: print x
  
  # with print as a function it works:
  from __future__ import print_function
  name_printer = lambda x: lambda: print(x)


Nice explanation. Note that I did wrap my print arg in parens, however. When I heard they were changing it to a function in 3 I made this a habit.


Using parens that way with the print statement is a bad idea. You aren't using it like a function -- the parens are parsed as an expression.

                 statement   function
  print(1)       1           1
  print(1,2)     (1, 2)      1 2
  print(1,2), 3  (1, 2) 3    SyntaxError
Just use the old syntax, and let 2to3 take care of you when the time comes.


I don't think I've ever used print that way. If I need to print more than one thing, it's clearer to use regular string formatting. Thanks for clarifying that though, interesting.


Perl, that miserable little unwanted orphan of a language, has real anonymous, first-class functions complete with closures. Python, sadly, does not

Which Python are you talking about? The language I use has had closures and first-class functions for years.


They don't seem to work very well:

  >>> def foo():
  ...   blah = 42
  ...   def wibble():
  ...     print "blah is " + blah
  ...   wibble()
  ... 
  >>> foo()
  blah is 42
Great! Looks like we have real closures!

  >>> def foo():
  ...   blah = 42
  ...   def wibble():
  ...     blah += 1 
  ...   wibble()
  ...   print "blah is " + blah
  ... 
  >>> foo()
  Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    File "<stdin>", line 5, in foo
    File "<stdin>", line 4, in wibble
  UnboundLocalError: local variable 'blah' referenced before assignment
Oh. Maybe not.


That's a scoping problem, not a closure problem. The issue in this example is that python doesn't have true lexical scope. It has three scopes: function level, class level, file level. If you wrote "global blah", it would look at file level, not the next function level.

I agree it's broken, but it's a different flaw than the closure problem.


I think the nonlocal keyword would make your second example work as you expect (but I can't test it as I don't have Python 3.0 installed here).

See http://www.python.org/dev/peps/pep-3104/


Only since Python 3000, with the addition of the "nonlocal" declaration, can python claim to have closures. And yes, Python does also have "first-class functions"--in the same way that C has first-class functions. It's the "anonymous" part that it has difficulty with.


Glad to know I can add you to my list of people who believe that Haskell does not (and by definition cannot) have closures.


You can't have closures without variables to close over! :)


2. Never return anything in a function, especially not some type of value that could demonstrate your function succeeded or failed.

First, why would you do his in a language where the idiomatic way to express that a function has failed is to throw an exception? Second, this is a pretty extreme failure and probably rare in (useful) Python code; why complain about about this when there is a real, extremely common problem in Python programming: not documenting your exceptions, so users who want to distinguish between different failure modes are forced to experiment and/or read your code.


> Brag that you called Perl from Python because it was "quicker" to experienced Python programmers.

A coworker found that calling out to grep can be faster than using Python's regular expressions for large amounts of text processing. My first reaction was to cringe, but it was indeed much faster for this particular problem; I think I was the bad programmer for reflexively cringing instead of saying "nice performance hack".


There are times and cases where a Perl script is faster than grep. It's ridiculously heavily optimized for that particular task.


Make up excuses like, "I am used to other people testing my code" (This one sounds especially good if your a former .NET developer.)

Why single out .NET? Am I missing something?


I'm pretty sure this guy is just trying to impress his friends on codinghorror's comment section.


The one issue I have is with the PEP 8 camel case reference. I can see the value of everyone keeping the same style while coding, but at the same time who says that style is the best? In terms of "expecting" that style when using other's libraries, you still have to read the docs for library to understand how to use it, so I don't see the ultimate value.


I disagree, as a rubyist I find it really useful that everyone uses underscores.

Language-wide style conventions make it easier to remember methods and classes since remembering a method like each_with_index as a phrase is easy, attaching a piece of useless data unrelated to what it does like Camel Case vs underscore is harder.


From PEP 8:

    But most importantly: know when to be inconsistent -- sometimes the style guide just doesn't apply. When in doubt, use your best judgment.


Settling on language-wide naming conventions reduces cognitive dissonance. Naming conventions don't supplant reading library docs, but they support it. In any case, you have to pick something, and some people will always be dissatisfied.

The answer to any "who says" question about Python is "Guido van Rossum says". (In the case of PEP 8, Barry Warsaw says as well.)


I agree, but I don't agree that deviating from PEP 8 in terms of naming makes one a bad python programmer. I've seen so many deviations of these rules in libraries that if I were to expect a certain style I would be more frustrated than I am.


Funny, you could replace "Python" with "Java" and it would still make sense. I guess idiots will be idiots regardless of the language.


Except for the camel case bit...


a few of these are the same as those mentioned in http://news.ycombinator.com/item?id=746873

i too think the distinction between camel case and lowercase underscore as one being somehow more readable or better than the other is a little silly.


I'm shifting to prefer lowercase underscore, but I actually wasn't aware of that detail of PEP 8, either. Not that I can claim to have built anything sizable in Python, just lots of little to moderate-sized scripts.


This post reminds me of PHP 'best practices' :)


> Add comments in the doc string or anywhere, that say, this is "magic", or "bad" and needs to be rewritten.

These are XXX comments and they're pretty common even with the best developers. They're so common that pretty much every editor has a syntax highlighting regex to detect them.


I'd go further - it's a good thing to do. It allows you to cruise through and get your main algorithm going, and then focus on details when you can afford for your brain to be doing that. I used to get distracted by this stuff and then forget about the big picture thing I was doing. Sometimes you can eve stub out lists of things with these as comments and then fill in the gaps as you're able to. Sometimes I review and realise the initial idea was too complicated and that I've saved energy.


Yup, they're common, and I agree with cturner - they're a very good thing. Comments that point out bad sections of code that need rewriting are invaluable.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: