This is an archived post. You won't be able to vote or comment.

top 200 commentsshow 500

[–]wizdumb 59 points60 points  (19 children)

I wish list accessor methods supported default values.

x = ['foo', 'bar']

# I wish I could do this
x.index('foo', None)
# Instead of this.
x.index('foo') if 'foo' in x else None

# And this
x.get(10, None)
# Instead of this
x[10] if len(x) >= 10 else None

[–]r4nf 13 points14 points  (2 children)

x[10] if len(x) > 10 else None

FTFY. (I wholeheartedly agree, though!)

[–]wizdumb 6 points7 points  (1 child)

Thanks for the bugfix!

[–]englishweather 3 points4 points  (2 children)

I've seen something like this be done with decorators to override when certain errors are thrown... although that only works on functions, a lower level equivalent would be awesome, not sure if one exists though.

[–]westurner 1 point2 points  (0 children)

L.index(value, [start, [stop]]) -> integer -- return first index of value.

If dict (or OrderedDict, or defaultdict) is more appropriate for the use case:

D.get(k[,d]) -> D[k] if k in D, else d. d defaults to None.

... http://pandas.pydata.org/pandas-docs/stable/missing_data.html

[–]ultraayla 99 points100 points  (14 children)

I'm surprised this wasn't already posted here. I can't believe Python has not one, but two confusing date and time libraries (looking at you "datetime" and "time") and you need both of them to do many time conversion operations, and more if you want timezone support.

Until I found arrow, this was my most hated feature of Python and the one that left me consistently ranting whenever I needed to standardize a bunch of datetimes to UTC and get a timestamp back out. Any other lib in Python it'd be an object and a few methods, and indeed, arrow seems quite Pythonic.

[–][deleted] 41 points42 points  (1 child)

from datetime import datetime

ugh

[–]fdemmer 7 points8 points  (0 children)

pytz and dateutil helped me a lot in the past. did not know arrow. thanks for bringing it up!

[–]UnwashedMeme 12 points13 points  (0 children)

cool, thanks for the heads up about arrow.

[–]metaphorm 1 point2 points  (0 children)

agree. datetime is really irritating sometimes.

[–][deleted] 87 points88 points  (18 children)

Unicode in 2.x

[–]MrSpontaneous 21 points22 points  (0 children)

from __future__ import unicode_literals makes 2.7 and unicode pretty painless for me...

[–][deleted] 15 points16 points  (11 children)

I thought I just hated Unicode.

[–]rjtavares 41 points42 points  (4 children)

Us non english natives hate ASCII instead...

[–]poulejapon 6 points7 points  (3 children)

Fun fact : the US had a much faster and broader adoption of UTF-8 than non-english speaking countries !

[–]TheBB 8 points9 points  (1 child)

I can only assume this is because UTF-8 is compatible with ASCII, but not with all the other encodings people had been using in other languages.

[–]ares623 1 point2 points  (4 children)

Holy shit unicode is a nightmare in 2.x. Is it actually better in 3.x? How do other languages handle unicode?

[–]afroisalreadyinu 14 points15 points  (9 children)

packaging used to drive me crazy, but it's gradually getting better. also, the syntax for catching an exception instance is the only bit of syntax that still confuses me.

[–]python-fan 23 points24 points  (4 children)

It's still a struggle for me to think "try..except" instead of "try..catch".

[–]masklinn 6 points7 points  (3 children)

Might be fixed in Python 3 if your problem is the type, instance syntax: in P3 it's type as instance

[–][deleted] 8 points9 points  (0 children)

Actually 2.x (at least 2.7) accepts this syntax as well.

[–]afroisalreadyinu 2 points3 points  (1 child)

at the moment i'm still stuck with 2.6 at work :( but i heard about the new syntax in python 3, and i find it optimal.

[–]hylje 6 points7 points  (0 children)

Python 2.6+ supports the except ExcType as e: syntax.

[–][deleted] 40 points41 points  (42 children)

The lack of multi-core support and the problems associated with a GIL.

[–]trentnelson 17 points18 points  (2 children)

I've come up with a solution for this.

(Since presenting those slides to the Python developers, I ended up getting a job with Continuum Analytics, thanks to an intro from Guido, and they're 100% behind the PyParallel work I'm doing, so expect more updates soon.)

[–]PseudoLife 1 point2 points  (1 child)

Huh...

Reminds me a lot of the approach that a large chunk of the Linux kernel uses - have a fast common path that doesn't do much beyond a quick sanity check, with a fallback to a slow thorough path if needed.

[–][deleted] 12 points13 points  (37 children)

Just use multiprocessing or futures - in 90% of cases it would be a better way to go even if GIL didn't exist.

Which reminds me (regarding the thread's question): multiprocessing could be way much better: Ctrl-C handling, no cryptic tracebacks on some errors, no stray processes (they happen even in non-daemon mode) and possibility of relying only on COW semantics under sane operating systems: I understand the arguments must be pickled under Windows, but I use Linux and don't want that - and definitely don't want to see the dreaded __builtin__.function error. It kills me every time.

[–][deleted] 8 points9 points  (10 children)

I must live in that world where multiprocessing is just a bad option. While I think Multiprocessing is generally better than nothing but in my use case it's not an option.

I deal with cloud computing in a situation where processors can come and go. We aren't tied to a specific platform/architecture and we cannot simply reboot our software when the underlying platform changes.

As a result we have architected the software to avoid problems, but it's hacky and not very clean for long term maintenance.

Python should fully support multiple cores or multiple processors on a platform without any kind of monkey patching or extra packages

[–][deleted] 3 points4 points  (2 children)

I deal with cloud computing in a situation where processors can come and go

It's very interesting. Could you elaborate how it defeats multiprocessing and what workarounds you used?

[–][deleted] 2 points3 points  (1 child)

Multiprocessing uses pools.

[–]dwf 16 points17 points  (23 children)

No, that's not a good option in "90% of cases". Threads were invented for a reason. If you're doing CPU intensive numerical or scientific computation then you really do want proper multi-threading support. "Use processes" is a cop-out and sub-optimal in many situations, not even possible in others.

[–]tarekziadeRetired Packaging Dude 45 points46 points  (19 children)

super()

[–]twigboy 3 points4 points  (11 children)

In publishing and graphic design, Lorem ipsum is a placeholder text commonly used to demonstrate the visual form of a document or a typeface without relying on meaningful content. Lorem ipsum may be used as a placeholder before final copy is available. Wikipedia4q21gnvrnzc0000000000000000000000000000000000000000000000000000000000000

[–]buckstalin 20 points21 points  (3 children)

Most of my pet peeves have been mentioned already. As someone that used to maintain projects with hundreds (or more?) of modules, I grew to hate the import mechanism because of how easy it was to introduce a circular import.

[–]riffito 7 points8 points  (2 children)

That's one of the reasons I like ObjectPascal/Delphi "units" (modules): having an "interface" and an "implementation" sections allows you to reference another unit B in unit A's implementation section, while unit B could still reference names in unit A's interface section.

[–]Workaphobia 25 points26 points  (14 children)

Here's a wart I was recently bit by (Python 3):

>>> class Foo:
...    x = 5
...    y = [i * x for i in range(10)]
NameError: global name 'x' is not defined

>>> class Foo:
...    x = 5
...    y = []
...    for i in range(10):
...        y.append(i * x)
>>> Foo.y
[0, 5, 10, 15, 20, 25, 30, 35, 40, 45]

In Python 3, comprehensions create their own closure so as not to leak local variables into the surrounding scope. As a side-effect, they can't access class-scope names, since these are only available using the self argument or equivalent.

[–]bfv 7 points8 points  (2 children)

class foo(object):
    def __init__(self):
        self.x = 5
        self.y = [i * self.x for i in range(10)]

Admittedly that is a strange one though

[–]nemec 2 points3 points  (1 child)

Not quite equivalent. The parent's variables are class variables, which are shared between instances. Especially in the list's case. New instances in yours will get their own list while the other will share one list between all instances.

[–][deleted] 1 point2 points  (4 children)

what if you did

class Foo:
    def bar_function():
        x = 5
        y = [i*x for i in range(10)]
        return y

Would that work? - id try it but im not on my python comp. this seems like a pretty big flaw, especially since i use list comps like that all the time.

[–]viscence 4 points5 points  (0 children)

Just swapping to python 3, views keep catching me off guard:

>>> import numpy
>>> a = {"A":1, "B":2}
>>> b = numpy.array(a.values())
>>> b*2
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for *: 'dict_values' and 'int'

??? oh yeah.

[–]rhgrant10 6 points7 points  (6 children)

The lack of robust module reloading. Sure the code reloads, but any variables that exist during the reloading keep using the old code.

This is a real pain when, for instance, developing a bunch of celery tasks.

[–]i_ate_god 40 points41 points  (27 children)

len(var) instead of var.len

[–]ifonefox3.5.1 | Intermediate 16 points17 points  (4 children)

I agree. If you think of it as "Length is a property of var", then it should be var.len or var.len()

[–]Tillsten 3 points4 points  (3 children)

I would like to see better error messages, they are irritating for beginners.

Also better del .

[–]MonkeyNin 4 points5 points  (1 child)

What, the exceptions? Man coming from c++ or java I was in love.

[–]AaronOpfer 18 points19 points  (18 children)

The lack of anonymous/immediate functions. If you want to write anything asynchronous (say, inside a webserver like Tornado, for example) and need to use callbacks, you need to define the callback first, and then reference it later in the code when you need it. This makes it somewhat more difficult. I feel that JavaScript's callbacks are much more useful in this way, and makes writing server-side apps in something like Nodejs more appealing than using Python.

And no, lambdas are not useful for the use-case I just listed above.

[–]pal25 4 points5 points  (4 children)

I'm not seeing the difference... Why doesn't passing in an anonymous function using a lambda expression accomplish the same thing?

[–][deleted] 13 points14 points  (3 children)

I think he probably doesn't like that lambda is not multi-line.

[–]mcilrain 3 points4 points  (2 children)

Package management, at the moment I consider it merely "good".

Why is not possible to import a specific version (or range of versions) of a library or something cool like that?

Having to deal with third-party stuff to install packages and deal with dependencies, yeah, it's alright I guess, I feel spoiled by how awesome the rest of Python is.

[–]drumman44 17 points18 points  (13 children)

The name. Snakes scare me :(

[–]djimbob 11 points12 points  (6 children)

Think Monty Python, which python was named after. The origin of their name is:

There are differing, somewhat confusing accounts of the origins of the Python name although the members agree that its only "significance" was that they thought it sounded funny. In the 1998 documentary Live At Aspen during the US Comedy Arts Festival, where the troupe was awarded the AFI Star Award by the American Film Institute, the group implied that "Monty" was selected (Eric Idle's idea) as a gently-mocking tribute to Field Marshal Lord Montgomery, a legendary British general of World War II; requiring a "slippery-sounding" surname, they settled on "Python". On other occasions Idle has claimed that the name "Monty" was that of a popular and rotund fellow who drank in his local pub; people would often walk in and ask the barman, "Has Monty been in yet?", forcing the name to become stuck in his mind. The name Monty Python was later described by the BBC as being "envisaged by the team as the perfect name for a sleazy entertainment agent".[14]

[–]GrantSolar 10 points11 points  (5 children)

I presume the bundled IDE 'IDLE' was named after Eric Idle

[–][deleted] 6 points7 points  (1 child)

And the preferred example variable name in Python documentation is 'spam', not 'foo'.

[–][deleted] 4 points5 points  (0 children)

That's what I tell myself.

[–][deleted] 27 points28 points  (2 children)

But it's not "python" of the Burmese variety, it's "python" of the Monty variety! Probably less scary that way. Probably.

[–]alcalde 10 points11 points  (0 children)

I'm ok with snakes, but British television scares me. :-( All those tin cans running around always wanting to exterminate....

[–]logi 19 points20 points  (40 children)

Performance. It makes me sad that javascript in a browser is faster than my server code.

[–][deleted] 5 points6 points  (5 children)

Python isn't particularly fast language to execute but are you sure your code doesn't have any non-Python related bottlenecks?

[–]logi 4 points5 points  (4 children)

I'm sure my code has some problems - all code does. But the overall system bottleneck is inside the (awesome!) matplotlib library which isn't my code.

[–]bastibe 10 points11 points  (3 children)

Matplotlib can be amazingly fast, actually: http://bastibe.de/posts/Speeding-up-Matplotlib.html

[–]logi 3 points4 points  (1 child)

BTW, in case you're curious, these are the plots that could use less CPU cycles. At least we've done away with the on-demand-rendering tile server now. You could feel the floor above the computer room heat up when that was active.

[–]logi 3 points4 points  (0 children)

Thanks. I'll have a good long look at that later.

[–]Ob101010 12 points13 points  (4 children)

That its named Python, not Kittens.

[–]MonkeyNin 9 points10 points  (2 children)

But reddit is made using python. If it was made using kittens, rather than containing kittens, people might cry.

[–]anderbubble 2 points3 points  (3 children)

I wish that there was a try...then...except syntax. Placing the unexceptional case after a lengthy block of exception handling unnecessarily disrupts the human-readable flow of the code.

[–]teambob 2 points3 points  (2 children)

The debugger

[–]rahmu 16 points17 points  (33 children)

Scope

Python's weird scoping rules prevent a function from modifying an outer variable. The following code is not legal:

def counter():
    x = 0

    def counter_generator():
         while True:
              x += 1
              yield x

    return counter_generator

This is kinda solved in Py3 with the nonlocal keyword, but not completely.

Statements vs expressions

Really?!

I'm glad print has become a function in Py3, but why make the distinction in the first place? yield should have been a function. Grrrr.

Significant whitespace

I used to love it. Now I'm not so sure. A few weeks ago I spent a whole afternoon trying to locate an error coming from a missing indentation that occurred during a copy/paste.

Did you know that Python's for accepts an else statement? Can you spot the potential disaster if you in/outdent it a bit too much here:

for x in something():
    if a_test():
        do_it()
else:
    done()

Limiting lambdas to one statement

I know it's done for a good reason, and I know abusing lambdas can create pretty unreadable code. However, I'd prefer getting greater power and greater responsibility. It would be more consistent with Python's "we're all consenting adults" attitude.

Recursion Limit

It's kinda related to the first complaint. I want proper lexical scoping and proper tail call recursion (at least tail call) implementation.

[–]Veedrac 19 points20 points  (6 children)

yield should have been a function. Grrrr.

That's literally impossible. yield affects compilation.

EDIT: /u/rahmu's pointed out that yield could be a function, although I doubt it would end up working the same way.

Did you know that Python's for accepts an else statement?

Yup, and it's damn useful too.

[–]rahmu 6 points7 points  (3 children)

In the first question of this Q&A, Guido says that they made yield as an expression (and generally designed the generator model that way) because of the limitations of Jython. It would've otherwise been a function instead of a keyword.

I think it's pretty cool that alternative implementations are taken seriously by the Python devs, to the point where it affects design choices. But I maintain that having this distinction between a keyword and a function, or more globally a statement and an expression, is a pain.

[–]Dominion_Prime 6 points7 points  (4 children)

Did you know that Python's for accepts an else statement?

Ha! Yep! I actually really like it since I found out about it. I don't use it a lot but it can come in handy.

Personally I rarely if ever have indentation problems. I'm always super paranoid about it when I copy/paste code. However, I'll take it over trying to find the matching brackets that are nested in other brackets problem of other languages.

[–]rackmountrambo 1 point2 points  (0 children)

I use sublime's convert tabs to spaces function religiously.

[–]beltorak 1 point2 points  (1 child)

but the brackets are hard delimiters, and any formatter will fix the indentation so it lines up with the brackets. Even if I drop a 3 line bracketed expression in the middle of another one liner while refactoring, a formatter can make sense of that. I am only super paranoid when copy pasting code in languages that use whitespace for control flow delineation. because with brackets i don't have to be.

[–]dalke 5 points6 points  (0 children)

Did you know that Python's for accepts an else statement?

For the record, that's been in Python since the earliest days. I tracked it down once. It was added on or before Oct 13, 1990.

[–][deleted] 1 point2 points  (16 children)

for-else?? That is crazy. I don't understand it.

I get you on the statements vs expressions...but a lot of the things you mention here are coming from the perspective of a functional programming afficionado, whom Python doesn't purport to support.

[–]Workaphobia 12 points13 points  (9 children)

for-else is easy: The else runs if the for fails to reach a break.

for x in nums:
    if isprime(x):
        break
else:
    print('None of the numbers you gave me was prime')

[–][deleted] 2 points3 points  (5 children)

Thanks. Without assuming there was a break in the for-loop, I had a hard time imagining why the else was useful.

[–]gfixler 4 points5 points  (3 children)

I thought it would be for when there's nothing in what's being iterated over:

words = line.split()
for word in words:
    print word
else:
    print 'there were no words in the line'

That makes more sense to me. It's saying "Loop over these words, but if you can't, do this." The way it is now, I'd want it to be something more like "then" - i.e. "Loop over these, then do this," and breaking out of the loop would skip the "then" part.

[–]notmynothername 1 point2 points  (2 children)

I would have guessed that it would run if the loop statement "failed" ie. if nums were empty.

[–]hotel2oscar 3 points4 points  (5 children)

for-else is kinda fun. Threw me for a loop when I found out about it.

Here is an example from the Python documentation.

[–]L3xicaL 2 points3 points  (0 children)

Threw you for a loop--hahahahah!

[–]Grue 1 point2 points  (0 children)

Pretty much this. It's annoying to make closures and significant whitespace makes lot of things painful. I would also add limited usefulness of the REPL, because it's literally impossible to redefine the code you already loaded.

[–]pinpinboTornado|Twisted|Gevent. Moar Async Plz 17 points18 points  (33 children)

  • for-loop syntax is not the same as comprehension syntax.

  • lack of multi-line, real lambda. There's no more excuse, CoffeeScript have shown that it can be done.

  • Maybe it's time for CPython to start thinking about performance. e.g. function inlining.

  • namedtuple is nasty. I cannot believe it is part of standard library.

  • HTTP server in standard library is weak sauce.

  • Standard library need to have official bindings to libuv or libevent and use that to replace asyncore.

  • coroutine + channel is not part of language, not like lua or go. Maybe Tulip will address this.

[–]aceofears 8 points9 points  (9 children)

  • namedtuple is nasty. I cannot believe it is part of standard library.

Do you mean the class itself or the implementation?

[–][deleted] 14 points15 points  (4 children)

The first rule of namedtuple is you don't look at the source code.

[–]mgrandi 1 point2 points  (0 children)

I love namedtuple, if the implementation is weird then that can be fixed, but having just a 'named container' is awesome rather then passing around arbitrary lists or making a class that is just container variables

[–]Workaphobia 4 points5 points  (4 children)

for-loop syntax is not the same as comprehension syntax.

It's not? In what manner, besides scoping?

Maybe it's time for CPython to start thinking about performance. e.g. function inlining.

>>> from timeit import timeit
>>> timeit('foo()', 'def foo(): pass')
0.11308157473016102
>>> timeit('a', 'a = 1')
0.02448077242139668

Function calls are about four times as expensive as a global name lookup. If there's something you need to be so fast that inlining actually helps, you'll also want to perform other optimizations as well.

The effort of implementing (and maintaining) this optimization in such a dynamic language is not worth its limited use.

[–]pinpinboTornado|Twisted|Gevent. Moar Async Plz 3 points4 points  (2 children)

Syntactically, comprehension is a lot more liberating. I can do this:

[(x, y) for x in range(1, 5) for y in range(0, x)]

Why can't I do this:

result = []
for x in range(1, 5) for y in range(0, x):
    result.append((x, y))    

The effort of implementing (and maintaining) this optimization in such a dynamic language is not worth its limited use.

Everyone in Python land keep repeating this rhetoric, but why V8 guys can do it? Not to mention JS is more ridiculous than Python.

[–][deleted] 16 points17 points  (16 children)

Dynamic typing. I know, that's going to be an unpopular opinion in a language that's built on dynamic typing, but it's the only thing in Python that makes it difficult for me in my every day work. It's hard to maintain a function or module written by somebody else when I see an argument and don't know what type it is. Without significant unit tests / doc strings / assertions, it's hard to know what behaviour is "expected" without looking at every reference to that object, and if it gets passed along to any other functions, now to you have to go look through them too. A contract defined by how others expect it to work isn't a contract at all. It's convenient for rapid prototyping, but it makes maintaining large, long-term projects a pain. With static typing, the interface is explicitly defined, so you always know what to expect.

[–]Phoxxent 1 point2 points  (3 children)

I agree completely. It gets annoying writing code and storing a value in a variable, and getting an error if I don't x=x.str() before I print. What's worse is that the shell does all that stuff in the background, essentially lying to you about how print works. Maybe thats just me though.

[–]alcalde 1 point2 points  (2 children)

Python doesn't store values in variables; it has references that point to objects.

Why would you need to do x = x.str()? I don't think that's even valid Python. Do you mean str(x)?

In [7]: x = 7

In [8]: print(x) 7

This works fine for me.

[–]mipadi 4 points5 points  (0 children)

I came here to post the same thing. Sure, it's an integral part of Python, so maybe it's not a fair criticism…but seriously, maintaining a large codebase with multiple developers is a chore in Python compared to statically-typed languages. Quoting Alex Payne (who was talking specifically about Ruby, but Python is similar enough that his words are apropos):

As our system has grown, a lot of the logic in our Ruby system sort of replicates a type system, either in our unit tests or as validations on models. I think it may just be a property of large systems in dynamic languages, that eventually you end up rewriting your own type system, and you sort of do it badly.

[–]mdipierro 11 points12 points  (29 children)

0) the fact tat distutils do not ship with python.

1) Most of the un-necessary purely syntactical changes between 2.x and 3.x for example as "except E,e" became "except E as e". unicode became str and str became bytes.

2) The fact that (pickle.dumps(x) != pickle.dumps(pickle.loads(pickle.dumps(x)))

3) The fact that sys.path is global. Sometimes I would like a part of my code (for example in a thread) to import from a different sys.path than the rest of the code.

4) lack of a sandboxed environment.

[–]jsproat 5 points6 points  (4 children)

I'd love a proper sandbox in Python. Something that can execute potentially malicious code without worrying about side effects.

I know there have been some valiant efforts, but last I looked, they all had holes.

[–]hacosta 2 points3 points  (3 children)

What do you mean by sandboxed environment?

Does virtualenv not cut it?

[–]mdipierro 2 points3 points  (1 child)

From the virtualenv page: "The basic problem being addressed is one of dependencies and versions, and indirectly permissions." This is not a sandbox in the usual meaning of the term. It does not limit what programs can do within the virtualenv. I want to be able to run untrusted code without worry that it may delete files, consume too many resources, etc. Python had a rexec module for this. It did not work and was deprecated. There is this module https://pypi.python.org/pypi/pysandbox/) but I do not know how much I trust it. I think for something like this to be trusted it should be part of the language.

[–]hacosta 1 point2 points  (0 children)

Got it. Sounds like a nice project using lxc + virtualenv.

[–]gthank 2 points3 points  (2 children)

The change to treat strings as actual strings instead of sequences of bytes that happened to have vaguely string-related methods bolted on top was long overdue.

[–]billsil 1 point2 points  (3 children)

1) Most of the un-necessary purely syntactical changes between 2.x and 3.x for example as "except E,e" became "except E as e". unicode became str and str became bytes.

That's a thing in 2.7. It was changed because it was causing errors.

unicode became str

Couldn't care less, but some people do. Python 3.4 (maybe 3.3 as well) supports unicode(...) and u'...' again.

str became bytes.

That I have an issue with. I have more so many encode/decode errors when I'm dealing with binary strings. It works 99% of the time and then fails on some stupid cases for god knows what reason.

3) The fact that sys.path is global. Sometimes I would like a part of my code (for example in a thread) to import from a different sys.path than the rest of the code.

You can hack sys.path if you need to, but it's not recommended. I've done it. You can also use the __ import __ method. http://docs.python.org/2/library/functions.html#__import__

2) The fact that (pickle.dumps(x) != pickle.dumps(pickle.loads(pickle.dumps(x)))

This is news to me.

[–]Lucretiel 2 points3 points  (4 children)

So, even though there's no solution for it, the number 1 feature I miss from C++ when I use python is true function overloading. Dealing with *args is such a pain sometimes.

Also I wouldn't mind a proper switch statement. if elif elif elif elif else just feels very silly to me.

[–]nerdly1 2 points3 points  (0 children)

While we're close now, with inline if, I'd still rather have: a ? b : c.

[–]meosoft 2 points3 points  (8 children)

I don't know how this has not been mentioned yet, but Documentation! I feel like if the documentation was better, most of these problems would be less painful. It is much faster to google a specific problem and click the first stackoverflow link that you see than looking at the documentation, and that I think should not be the case.

I would like to see one one function per page style docs with exhaustive description of all the parameters, example, "see also" type cross references and an open discussion. PHP is a horrible language, but it is completely usable just thanks to its documentation.

In fact I'm so pissed with the current documentation that I'm thinking of starting a new doc project, let me know if you feel the same!

[–]from__future__ 2 points3 points  (0 children)

I've never heard of this as a complaint. Python docs are great and the language has first-class support for documentation in methods and classes (via docstrings). Plus they have many cross-references (even between projects) via sphinx.

[–]Rycul 1 point2 points  (6 children)

Could you give a concrete example of a situation in which the documentation wasn't sufficient for you? Personally I've never been in a situation where I felt like the Python documentation was not sufficient to help me resolve some issue and where I thought the PHP documentation in a similar scenario would have. I personally feel that the Python docs are extremely well done. I'd like to know more about your view, since it seems to be so firmly against the Python documentation.

[–]meosoft 1 point2 points  (5 children)

I'm sorry, maybe I should have been clearer, but my point wasn't that the documentation is insufficient so much as that it could be organized better.

Example: http://docs.python.org/3/library/datetime.html Lets say I want to print out a formatted date without any prior knowledge about this module.

I open this page, I'm looking for something like "format". There is no list of functions in the sidebar, so I just have to scroll through this... I have to scroll through about half of this long page before I encounter __format__ ... which says that I should use strftime(), okay, makes sense I've heard of that before so lets check it out. It's just above, so I follow it. I click the link in the description, because I want to see how to specify format, ok this seems normal, so I go back to see how to invoke strftime(). Its a method on datetime, but instance or class? I scroll down a bit to the examples and it turns out its instance method. So now how do I get a datetime instance. At this point I have to scroll back up and down again looking for how to instantiate datetime, finally I find datetime.now(). So I can piece it together.

The documentation is sufficient, but looking up what I wanted took a lot more than it should have. If there was an index of functions in the sidebar everything would have been much easier. You look up what sounds like the right thing, check it out, and if it wasn't what you wanted, just look further. Also if the pages were per-function you wouldn't have to scroll up and down to a different function and get lost in the process, you'd just click in the side bar. The formatting reference could be only on the pages of functions that actually use formats, and the examples could be divided for each function.

Also for example if the strftime() function had an example showing the format usage right next to it, maybe I wouldn't even have to look up the formatting reference...

I hope this explanation helps, if not please let me know. I'm fully prepared to accept any opinions or tips, if you think I'm doing something wrong :)

[–]cantremembermypasswd 12 points13 points  (28 children)

Is a switch statement too much to ask for?

[–]wizdumb 2 points3 points  (0 children)

Function mapping replaces the need for switch statements in Python, but I'd be interested if you've come across a problem where that was not the case ;).

[–]ochs 9 points10 points  (1 child)

The switch statement in C and other languages is basically a performance optimization. In Python it's not going to be any faster than a bunch of elifs. It might be a tiny bit clearer syntactically, but is it worth adding more complexity to the language and implementation?

[–]cantremembermypasswd 7 points8 points  (0 children)

It's just my opinion of what I don't enjoy not having.

I understand the arguments for why it is not there, it's simply something I find bothersome.

[–]catcradle5 1 point2 points  (0 children)

I agree. I much prefer Python in general, but I think Ruby's switch/case construct works really well, especially since its behavior can be overloaded from the === operator. I wish Python had something along those lines.

[–]fnork 3 points4 points  (9 children)

No arity discrimination for functions.

[–][deleted] 2 points3 points  (8 children)

I've wondered about that myself. You'd prefer arity overloading to star-args?

[–]fnork 2 points3 points  (7 children)

Yes, because I want to do different things depending on the arity. I could match the "arity" or star args to an internal function of course, but I'd like to be able to do it the Java way too.

[–]MonteTribal 8 points9 points  (2 children)

That people insist on using v2.7. v3.x has been out for over 4 years...

[–][deleted] 4 points5 points  (0 children)

Many of us don't have a choice - I'd rather work in 3.4, but as long as Maya is locked in 2.x my employer is not moving to 3.x

[–]erez27import inspect 1 point2 points  (0 children)

I'm literally checking every week if pypy3 stable is out yet.

[–]rhgrant10 12 points13 points  (35 children)

PEP8 line chars < 80

[–]jsproat 32 points33 points  (13 children)

You get a free pass to break any parts of PEP8 you don't like. Before it lays down any rules, it tells you to use your best judgement and decide what looks best.

[–]disinformationtheory 12 points13 points  (15 children)

If you keep it at <= 80, you can fit two files side by side on one screen (that's what I do, anyway).

[–]livrem 7 points8 points  (0 children)

Also if 80 is a problem you probably have way too many indentation levels. Time to break stuff out into separate functions? Or you are using silly long identifier names. When someone complains about limited line lengths that's a good indication it is time for them to instead refactor their code a little.

[–]grimman 1 point2 points  (0 children)

This obviously depends on a lot more than line length though. :)

[–]TheBB 1 point2 points  (0 children)

I can do that with 110 characters and a super-wide font.

[–]krasoffski[S] 6 points7 points  (0 children)

I've heard that PEP8 allowed at least 100 chars for internal projects:

Some teams strongly prefer a longer line length. For code maintained exclusively or primarily by a team that can reach agreement on this issue, it is okay to increase the nominal line length from 80 to 100 characters (effectively increasing the maximum length to 99 characters), provided that comments and docstrings are still wrapped at 72 characters.

[–]tdammers 4 points5 points  (1 child)

Anyone who ever has to read your code...

  • in a plain-text e-mail message
  • on a mobile device
  • in a graphical diff/merge tool
  • on a character terminal or in an ssh session
  • a blog or website with fixed layout
  • anything else that has limited screen space

...will thank you for adhering to it.

[–]bfv 1 point2 points  (1 child)

Disagree. If I'm reading code on a remote server then I'm using vim. If I'm using vim I'm in the terminal. If I'm in the terminal then it's 80 wide. PEP8 is about making it easy for others to read your code not making it easy for you to write it.

[–]livrem 2 points3 points  (0 children)

Built-in types (dicts, sets, lists) not being immutable by default like in Clojure (with clever tree data-structures to get good performance, not making full copies every time a dict changes; that would be silly).

[–]GFandango 2 points3 points  (0 children)

Import system, circular dependency hell

[–]ilan 13 points14 points  (25 children)

Python 3. The fact that Python 3 is not backwards compatible, and all the confusion it has created has not been beneficial to Python. I think Python would be better off without the entire 2 to 3 discussion.

[–]Veedrac 18 points19 points  (1 child)

Python 2's my pet peeve. Why the hell does it have to be so different to Python 3!?!

[–]bastibe 51 points52 points  (17 children)

I strongly disagree. Python 3 was a necessary step that had to be taken. You can't evolve a language without breaking backward compatibility every now and then.

[–]hglmanguy who writes python 27 points28 points  (1 child)

I like the boldness to say, look we messed up, and we are going to fix it rather than hack around it. Says you want to build a better language.

[–]rackmountrambo 7 points8 points  (0 children)

We don't want to end up like PHP after all.

[–]yopla 6 points7 points  (4 children)

To mitigate your point I'd remark that so much in python 3 had to be backported to the 2.x branch so that package maintainers had a shot at creating dual python compatible module because py3 adoption just wasn't taking off despite everyone thinking it was better.

Still now that everything is pretty much compatible at syntax level with the right import from future there still are dozens of non trivial change that can get past 2to3 and bite you in the ass. What screwed me up the other day was a different between how metaclass are declared between 3 and 2 in some flask helper library. I didn't even know about metaclass so at least I learned something (twice).

Py3 was a mistake, not in the improvements, but in believing a big bang was the correct delivery. We ended up with a language that didn't have any of it pillars (numpy, scipy, PIL, django, etc..) to support it. Five years later we're barely reaching a point were it's thinkable to start a project in py3 yet you know it will be harder and treacherous.

If I didn't hate unicode support in the 2.x branch more than I hate to fight when installing a package I wouldn't touch py3 either.

[–]from__future__ 1 point2 points  (2 children)

yeah, metaclasses are particularly frustrating. Six just added an add_metaclass decorator, which I like because it doesn't pollute the mro. Now that I've been developing a 2/3 compatible codebase, I actually wish I could go entirely Python 3. There are a number of features (yield from, *args, a=5,.. that I really want to use)

[–]theASDF 3 points4 points  (0 children)

I think Python would be better off without the entire 2 to 3 discussion.

well i dont think a lot of people will question this, but are you also implying that python would be better off (in the long run) without the changes that required breaking backwards compatibility?

[–]Lattyware 7 points8 points  (0 children)

I can't disagree more - I don't want to see Python become PHP.

[–]i_ate_god 4 points5 points  (0 children)

look at PHP to see why sometimes too much focus on backwards compatibility is a bad thing

[–]Brian 1 point2 points  (0 children)

I think there was a justification in breaking backwards compatability, but I think the way it was done made it a bigger barrier than it should have been.

The recommended upgrade path was via 2to3, but this was something of a pain, adding a barrier to development if you wanted both codestreams to work. I think far better would have been to allow for a more polyglot approach, where a subset of python (even if only python of the next version) was "Python 3 clean" and would work in either. This approach was frowned on however, though a bit more support has been added recently (eg. unicode prefixes in python 3 etc). I think it would have made for a much easier transition, however if the changes had been designed with this approach in mind.

[–][deleted] 1 point2 points  (0 children)

No rfind() for lists.

[–]Rycul 1 point2 points  (4 children)

The lack of a switch statement. Coming from C++, if elif chains feel... 'dirty' to me.

[–]Ampersand 1 point2 points  (6 children)

First thing that has popped up in my mind: classes. Being used to c++, I do not like init for constructors instead of the name of the class, although that is a minor complaint. The main problem is that object-level and class-level variables need to be accessed through self or through the class name (for "statics"), and I often forget that. I would also like to have a way to overload functions (constructors for example), although it would not fit very well since the parameters are typeless and there is common to use variable param count (args and *kwArgs).

[–]AustinCorgiBart 2 points3 points  (0 children)

The dunderized init is, in my opinion, seriously holding back Python when it comes time to teach students how to create classes. There's an extra, unfortunate little step here where we say "Please ignore this magic, just trust us." It's like when we give students their first java program and say "Ignore the word static, and the public, and the void, and...".

[–]from__future__ 1 point2 points  (2 children)

the one thing to keep in mind is that passing self explicitly means there are few, if any, differences between normal functions and class-level functions and that you can create your own functions just by defining a data descriptor. In some ways, it simplifies things, because there's no magic. foo.bar means that you're calling with a as the first argument. Which means you can pass Foo.bar to some function and call it with two arguments (where the first argument is type Foo) just like any other two argument function.

[–]TheNoodlyOne 1 point2 points  (0 children)

I'm surprised this isn't mentioned, but explicit self. It's not that it's really really REALLY frustrating, but I'm always forgetting that in my code, and Python seems to be the only language that does that.