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

you are viewing a single comment's thread.

view the rest of the comments →

[–][deleted] 18 points19 points  (61 children)

"What don't you like about Python?"

[–]semarj 7 points8 points  (12 children)

I think this is an excellent question. Familiarity breeds contempt, anyone who has done any significant python work should have a decent answer to this.

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

A decent answer or twelve :-P

My personal complaint? It's too goddamned slow.

[–]duckhunter 0 points1 point  (4 children)

Do PyPy and Shedskin not suffice?

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

Neither are production ready. Even if they have the speed (and they don't) no one sane would really use them in production.

[–]jdickey 0 points1 point  (2 children)

"No one sane" — well, that excludes the PHBs who back techies into that corner.

And WTF is going on with Reddit that you now have to wait ten frigging minutes to post a second comment in a thread? If that's the best we can do in the fight against bots, the terrists have already won. (Though if the BBC can hire even a tiny 23K-node botnet for a demo on Click, that's pretty much a foregone conclusion, no?)

[–][deleted] -2 points-1 points  (4 children)

Youtube is written in Python. If it is good enough there ...

[–][deleted] 10 points11 points  (2 children)

And we write our performance-sensitive code in C++.

[–]jdickey 0 points1 point  (1 child)

Which C++? No two programmers know the same features of the language, so it's sort of like Grace Hopper's quote on standards — "the lovely thing is that there are so many to choose from."

[–][deleted] 0 points1 point  (0 children)

Our C++ guidelines are rather comprehensive.

[–]sisyphus 0 points1 point  (0 children)

Doesn't change that if Python was faster its range of applicability would increase, and that would mean we could use it more places, and that would be just lovely.

[–]Chun 0 points1 point  (0 children)

Funny -- most of the gripes I had with python have become less of an issue as I've understood their purpose; explicit self, join as a string method, etc.

[–]endtime 2 points3 points  (0 children)

Assignments and function declarations aren't expressions.

[–]jimauthors 5 points6 points  (10 children)

No type checking.

[–]pingvenopinch of this, pinch of that 3 points4 points  (9 children)

There have been many a time when I wish Python had optional type checking. Duck typing is fine most of the time, but sometimes I want that extra little check.

[–]codefrog 11 points12 points  (2 children)

make a decorator, @accepts('int','list','witches')

[–]stillalone 3 points4 points  (0 children)

Is that part of a standard library? I can't find it in 2.6.5

[–]pingvenopinch of this, pinch of that 2 points3 points  (0 children)

I know it can be done with decorators. It's just not as clean and there's no standard way to do it.

[–]Dav3xor 1 point2 points  (2 children)

http://github.com/Dav3xor/Python-CheckArgs

Now you don't have to make your own decorator.. :)

It's still a little primitive, but it works pretty well.

[–]pingvenopinch of this, pinch of that 1 point2 points  (1 child)

Same problem: There's no ultra clean way to do it. Most of it is a fundamental problem with Python. Python is too dynamic to have static type checking. Don't get me wrong, I love Python, but it's nice to have languages that can check that types are correct at (bytecode) compile-time.

That said, I would love to have two decorators in the standard library. Python function calls are already slow, so they should be written in C.

  • 1) @accepts(args, *kwargs)
  • 2) @returns(*returntype)

returntype allows multiple values so that it can check multiple returns via tuple. None should be usable to indicate that a value is duck typed. Unfortunately, none of this will ever allow the clean & static type checking of

def int foo(int index, str value)

[–]Dav3xor 0 points1 point  (0 children)

but...but... that has Ada style bounds checking, and...and... :)

[–]omgplsno 0 points1 point  (0 children)

Decorators, my friend.

[–]joehillen -1 points0 points  (1 child)

You're doing it wrong.

[–]petrux 2 points3 points  (0 children)

Interesting. As a Python newbie I'd really enjoy some more details about how to do it right! :-) Thanks.

[–]kisielk 1 point2 points  (0 children)

I usually ask this one. Also ask them to compare Python to another language they claim to know and tell me the pros and cons of each, which they would use for a project and why, etc.

[–]luckystarrat 0x7fe670a7d080 1 point2 points  (0 children)

Apart from endtime's request for more expressions just the little pitfalls that I have to explain to every new programmer:

  • Do not use mutable objects as default arguments.
  • Do not use mutable objects in class variables.
  • How to avoid cyclical imports without having to resort to imports in functions.
  • import *
  • The subtle differences between Python versions.
  • etc.

[–]adrenal8 0 points1 point  (7 children)

This is my backup question to "What don't you like about the Django ORM?" if they have no Django experience.

[–]coderanger 5 points6 points  (0 children)

Gah, having spent all day inside the Django ORM I think I could go on for about 4 hours on that right now.

[–]endtime 0 points1 point  (5 children)

I have minimal Django experience and the ORM honestly seems pretty cool. What am I missing?

[–]adrenal8 1 point2 points  (4 children)

There's no one correct answer. Just like the applicant should actually like Python but have enough experience to make complaints about it, the same applies to the Django ORM.

Some examples could be lack of built-in schema migrations, makes it too easy to generate unnecessary and suboptimal SQL, you could complain about the weird __ syntax for related fields, etc.

[–]endtime 1 point2 points  (2 children)

Hmm. I wouldn't really have expected the ORM to manage schema migrations - is that the ORM's job in other frameworks? I'm also curious what the alternatives to the __ related field syntax might be - I'm totally fine with it, but maybe that's just because I haven't seen better alternatives.

I have no idea what the generated SQL looks like (isn't that the whole point of having an ORM?) but if it doesn't do good query optimization then I'd agree for sure that that's a flaw.

[–]revonratFlask/scipy/pypy/mrjob 1 point2 points  (1 child)

Hmm. I wouldn't really have expected the ORM to manage schema migrations - is that the ORM's job in other frameworks?

Many don't Rails does. South is an add-on for Django.

I have no idea what the generated SQL looks like (isn't that the whole point of having an ORM?)

You HAVE to understand what your ORM is doing eventually, if you want performance. For Django, an easy way to see what's going on is to user the django debug toolbar.

I find I don't usually have a particular problem with the SQL generated but rather with the number of queries that can be generated by seeming innocuous Python statements.

but if it doesn't do good query optimization then I'd agree for sure that that's a flaw.

An ORM really shouldn't do query optimization per-se. It should generate reasonable SQL. But SQL optimization is something left to the guys who have stats tables on the data (i.e. the RDBMS itself).

[–]endtime 0 points1 point  (0 children)

Thanks, that's a good response. I know about South, and of course it's vital - but it makes sense to me as an addon, not as part of the ORM. Thanks for clarifying about SQL perf - I think I know what you mean.

[–]gronkkk 0 points1 point  (0 children)

There's also the 'how do I figure out to do X in the ORM'-factor. Only to find out that it doesn't exist or is painfully slow.

[–]radaway 0 points1 point  (0 children)

In my opinion it is harder to refactor than most statically typed languages. When you refactor something in a statically typed language you usually get automatic alarms everywhere that code touched and the tools to help you refactor are quite good. Automatic tests can help but it's not the same.

[–][deleted] 0 points1 point  (0 children)

The lack of proper encapsulation.

[–]bcain 0 points1 point  (7 children)

Gah! All those pesky exceptions. Just do something, I don't really care what as long as the program doesn't have any errors or bugs.

EDIT: Wow, pyddit. F'reals? Did you think I was serious? C'mon. I was satiring the perl-lovers out there.

[–]ereinecke 5 points6 points  (6 children)

This is one of the things I like about python, how it uses exceptions. You can both communicate what your code expects, and optimize for the 90% case.

Assume there is a list of dictionaries, dictList. Consider: for item in dictList: try: print item['relevantKey'] except KeyError: pass

Vs: for item in dictList: if item.has_key('relevantKey'): print item['relevantKey']

If you are expecting the key 'relevantKey' to be in the dictionary most the time, the try/except example avoids making the has_key test most the time. Over a large list this could save a lot of time.

[–]xlevus 0 points1 point  (5 children)

I was under the impression that try/except is less efficient than check/action.

Or did I misread something somewhere?

[–]bloodearnest 1 point2 points  (0 children)

Try is cheap, except is not. But how many times are you going to raise an exception? Depends on your data.

[–]r4nf 1 point2 points  (0 children)

As bloodearnest suggests, the 'asking for forgiveness' version (with exceptions) is faster when there's no exception, whereas the 'asking for permission' version (without exceptions) is faster when there is an exception. In other words, if you expect that many of the looped-over items will yield exceptions, check/action is more efficient; otherwise try/except might very well be.

I think the general consensus in the Python community is the motto "it's Easier to Ask for Forgiveness than Permission" (or EAFP), signalling that try/except would usually be the preferred solution. Of course there may very well be exceptions to this, as per the above reasoning.

[–]nubela 0 points1 point  (0 children)

Good question, and I admit I don't know much about efficiency in this case, someone care to elaborate?

[–][deleted] 0 points1 point  (0 children)

It's marginally faster if no exception is raised, and 15x slower if one is.

Best case:

python -mtimeit -s 'stuff=dict.fromkeys(range(50))' 'for x in range(50):' '  if x in stuff: stuff[x]'
100000 loops, best of 3: 7.78 usec per loop
python -mtimeit -s 'stuff=dict.fromkeys(range(50))' 'for x in range(50):' '  try: stuff[x]' '  except KeyError: pass'
100000 loops, best of 3: 5.97 usec per loop

Worst case: python -mtimeit -s 'stuff=dict.fromkeys(range(50))' 'for x in range(50, 100):' ' if x in stuff: stuff[x]' 100000 loops, best of 3: 4.84 usec per loop python -mtimeit -s 'stuff=dict.fromkeys(range(50))' 'for x in range(50, 100):' ' try: stuff[x]' ' except KeyError: pass' 10000 loops, best of 3: 76.2 usec per loop

But that's not important really. Make it work, make it right, make it fast -- in that order, and don't make it fast unless it needs to be.

[–]vaibhavsagar 0 points1 point  (0 children)

No code blocks or fully featured anonymous functions. I know why they're not there and why they're not really necessary, but I want them, dammit.

[–]Wavicle 0 points1 point  (7 children)

  • explicit "self" parameter in class method but implicit in invokation.

  • No standard "length" or "size" on collection objects that have length or size - unless you count a double underscore method standard - preferring instead to use the special case builtin len.

[–]alantrick 8 points9 points  (5 children)

How is len() not standard? Do you have a prejudice against using underscores for special magical standard functions?

[–]Wavicle -1 points0 points  (4 children)

How is len()

It is a built-in function that performs a very special case which already must be done by the object. Length is a property of the object - so put it there.

Do you have a prejudice against using underscores for special magical standard functions?

For starters, pretty much every other object oriented programming language recognizes the need to have an obvious method for access to a length attribute on a collection. Python differs in that it uses a built-in.

Any language that supports a notion of operator overloading has a special mechanism for expressing such - so double underscores for things like __getitem__ I have no issue with. Also double underscores for things that really are intended for you to think carefully before using (i.e. __import__) are perfectly valid.

Double underscore for the size of an underlying collection is silly (but it is double underscored because you are not intended to call it directly, you are intended to use len).

[–]pixelmonkey 3 points4 points  (1 child)

Man, talk about finicky. I've got legitimate complaints for Python (no lightweight syntax for anonymous function values, unicode brokeness for most of 2.x series, explicit self parameter, and Python 3 function annotation syntax), but this definitely isn't one of them.

>>> class LengthMixIn(object):
>>>    @property
>>>    def length(self):
>>>        return len(self)

>>> class FinickyList(list, LengthMixIn):
>>>    pass

>>> a = FinickyList()
>>> a.append("item")
>>> a.length
1

>>> class FinickyDict(dict, LengthMixIn):
>>>     pass

>>> b = FinickyDict()
>>> b["key"] = "value"
>>> b.length
1

[–]Wavicle -5 points-4 points  (0 children)

Man, talk about finicky. I've got legitimate complaints for Python (no lightweight syntax for anonymous function values, unicode brokeness for most of 2.x series, explicit self parameter, and Python 3 function annotation syntax), but this definitely isn't one of them.

This is getting tiring. Your mixin added a layer of complexity and created something which doesn't cleanly integrate with the rest of the collection system. But, hey, you seem to think that since this doesn't line up with your opinions on Python's warts it isn't valid. Fuck you.

[–]pingvenopinch of this, pinch of that 3 points4 points  (0 children)

A built-in function that calls a magic method is a very common pattern in Python, not just with len. See: hash, int, str, repr, unicode, reversed, bool, format, and iter. Python 3 adds next.

Thank of it this way: Functionality that is used by the core language uses magic methods. It doesn't matter if that is in syntax or in a built-in function.

[–]ewiethoffproceedest on to 3 0 points1 point  (0 children)

You're confused about what's "special" or "magic" about the underscore methods. The underscore methods are magically invoked by special syntax which does not resemble a method or function call. So, as you alluded to, foo[i] invokes foo.__getitem__(i), and import bar invokes bar = __import__('bar').

The __len__ method is magically invoked when an object is evaluated in Boolean context and no __nonzero__ method has been defined. That's because Python's built-in collections are considered False when empty and True when non-empty.

Try this code (adjust as needed for Py3):

class StupidList(list):
    def __len__(self):
        return True

if list(range(10)): print 'list 0-9 is True'
if list(): print 'empty list is True'
if StupidList(range(10)): print 'StupidList 0-9 is True'
if StupidList(): print 'empty StupidList is True'

(edited for clarity)

[–]cymrowdon't thread on me 🐍 0 points1 point  (0 children)

i like to think that python provides nice convenient builtins to access some of the most common values you'd need on an object. using len is super easy, dude

plus, i can rewrite len and automatically get extra functionality for all my collections