Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Actually Perl's characterization was that the easy things should be easy, and the hard things possible. Sometimes Python could learn from that.

Oh you want to print to stderr hmm?



Some things that should be easy are ridiculously hard in Python. Regexes for one have a horrible API story. Another one is the import system which I view as a totally broken effort to heal self-inflicted complexity with more complexity. Here is the code I came up when presented with the task to import a module when its name is given:

    def module_from_path( ctx, name, path ):
      ### thx to https://stackoverflow.com/a/50395128/7568091 ###
      ### thx to https://stackoverflow.com/a/67692/7568091 ###
      import importlib
      import importlib.util
      spec                      = importlib.util.spec_from_file_location( name, path )
      module                    = importlib.util.module_from_spec( spec )
      sys.modules[ spec.name ]  = module
      spec.loader.exec_module( module )
      return importlib.import_module( name )
Details may change any time without notice. The complexity here is a consequence of Python's design decision to treat module names as identifiers, not as quoted strings. The import system is full of such poor choices (dot/relative imports, `__init__.py`, `*.pyc` / `*.pyo` files littering one's source directories, and so on)


Agree on regex. I started in perl many years ago and loved how integrated regexes were. Was appalled that was was a simple one liner in perl turned into multiple lines in python for every regex. Making a powerful tool easy to use means it will be used more.

It would be nice if that flaw could be fixed, as I like coding in python in general


Here' an ancient hack that showed how that might look like - http://dalkescientific.com/Python/python4ply-tutorial.html#m... .

  count = 0
  t1 = time.time()
  for line in open("nucleosome.pdb"):
    if line =~ m/(ATOM  |HETATM)/:
        count += 1
  print count, "atoms in", time.time()-t1, "seconds"
It used it own PLY-based parser to generate the Python AST.

None of it would work now. :)


I realize now how much of a hack it is. The portion 'm/(ATOM |HETATM)/' could be part of valid Python expression, as:

  >>> ATOM = HETATM = 1
  >>> m = 2
  >>> m/(ATOM  |HETATM)/1
  2.0
so either m// is enabled only after =~, or there has to be some way to recognize the lexically correct match term -- something more powerful than the "m/[^/]*/[a-z]*" used here.


I have to say I really like Python's module system. Modules as objects, scoped import by default and filesystem-backed module resolution (+sys.path) are all good choices in my opinion. Cosmetic warts like __pycache__ are unfortunate, but not deal-breakers.


My main memory of perl (I used it for CGI and local CLI tooling back in the day) was that it was usually very terse, to the point of being a write-only language. I learned an important lesson with it: the more clever you feel writing code, the more you are likely to hate maintaining it after a few months away!


There was a long time period (IMHO good few years in early 2000s) where Python looked better on paper but Perl was still better for production.

All the Perl libraries for doing certain things (db access, web stuff, process management) were "actually battle tested" and worked well even if they were utterly unreadable. Python looked a lot nicer but when you tried to do any real work with it everything seemed to leak memory or give you continuous paper cuts - and it was a lot slower.

I made the switch to Python eventually but it took a while.


> (IMHO good few years in early 2000s)

That tallies with when I was using Perl (late 90s / early 00s). Python was very much on the up in that time but I didn't feel compelled to switch, then DayJob and personal projects took me away from such thing completely (DayJob was Windows/VB6/IIS/ASP based, home web stuff went PHP for a while and admin stuff to Bash).


Perl also has the motto "there's more than one way to do it".

https://en.wikipedia.org/wiki/There%27s_more_than_one_way_to...


This is also the motto I learned. This would explain Python's motto of "There Is Only One Way to Do It".

(It's a joke due from this page: http://james-iry.blogspot.com/2009/05/brief-incomplete-and-m..., actual motto is "there should be one -- and preferably only one -- obvious way to do it")


What's wrong with printing to stderr in python?


Agreed!

In fact, I think this makes it so all print() calls by default write to stderr:

  >>> import sys, functools, builtins
  >>> real_print = print
  >>> builtins.print = functools.partial(real_print, file=sys.stderr)
  >>> print("Hello")
  Hello


Or use logging module as you should, which prints to stderr by default.

    import logging
    logging.basicConfig()

    logging.info('something happened')


The problem for me with logging is that it's slow for production code:

Python 2.7.15 Linux (logging is 60x slower):

  [root@hbtest ~]# py -m timeit -s 'import logging' "logging.info('something happened')"
  1000000 loops, best of 3: 1.31 usec per loop

  [root@hbtest ~]# py -m timeit -s 'import sys; debug = False' "if debug: print >>sys.stderr, 'something happened'"
  10000000 loops, best of 3: 0.0216 usec per loop
Python 2.7.15 OSX (logging is 71x slower):

  $ py -m timeit -s 'import logging' "logging.info('something happened')"
  1000000 loops, best of 3: 0.925 usec per loop

  [jim@mbp hbrel]$ py -m timeit -s 'import sys; debug = False' "if debug: print >>sys.stderr, 'something happened'"
  100000000 loops, best of 3: 0.013 usec per loop
Python 3.6.8 Linux (logging is 99x slower):

  [root@hbtest ~]# python3 -m timeit -s 'import logging' "logging.info('something happened')"
  1000000 loops, best of 3: 1.62 usec per loop

  [root@hbtest ~]# python3 -m timeit -s 'import sys; debug = False' "if debug: print >>sys.stderr, 'something happened'"
  100000000 loops, best of 3: 0.0163 usec per loop
And, as usual, Python 3 is 25% slower than Python 2 for the logging case (but 2x faster for the noop if debug case). I hope the recent efforts to increase Python 3 performance are successful.


Microseconds are not important unless in a very tight loop. Avoid there and/or make a shortcut beforehand.


And we don't know why tus666 wants to print to stderr, nor what the issue was with Python, so this digression seems built on sand.


I don't think I follow the stderr comment. Isn't it just:

Perl

    print STDERR "foo"
Python

    print(file=sys.stderr, "foo")
Those look fairly similar. I prefer that print() is obviously a function call and file is a named parameter so the purpose is clear.


Well in Perl there is...

warn("foo")

In Python you have to at least:

- remember not to forget to import sys - remember the file= syntax for the print statement - type about 10 extra characters

Bunch of annoying stuff when you are hurriedly debugging something...


The file=sys.stderr came with Python 3. Because of that, I tend to see sys.stderr.write("foo\n") more often.


Python 2 was even more terse with it's print statement

    print >>sys.stderr, "foo"


Or, on the first Python3 releases, do you want to output binary data at all?




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

Search: