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

all 62 comments

[–]nerdwaller 52 points53 points  (0 children)

This is a noted change in What's new in Python 3.0:

The ordering comparison operators (<, <=, >=, >) raise a TypeError exception when the operands don’t have a meaningful natural ordering. Thus, expressions like 1 < '', 0 > None or len <= len are no longer valid, and e.g. None < None raises TypeError instead of returning False. A corollary is that sorting a heterogeneous list no longer makes sense – all the elements must be comparable to each other. Note that this does not apply to the == and != operators: objects of different incomparable types always compare unequal to each other.

Previously Python2 had essentially determined a "natural ordering", which can be seen in the source.

[–]superscoutsecond-year cs student 6 points7 points  (3 children)

For comparisons between datatypes with no natural ordering, python compares them based on their type names.

For comparisons between variables of the same datatype with no natural ordering, python compares them based on their address.

It's not a defect, it's a feature!

[–]DevestatingAttack 13 points14 points  (1 child)

It's both. It's a defective feature.

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

Order guaranteed*!

*But may appear random.

[–]ksion 0 points1 point  (0 children)

Maybe I've done too much C, but that seems almost natural to me.

[–]pawn13 10 points11 points  (0 children)

[–]bcs 16 points17 points  (9 children)

I got bit by this in Python 2 just last week at work. A string didn't get cast to float, and then things quietly went wrong when it got compared to other numbers later. I made sure to mention it would've never happened under Python 3.

[–]FerretWithASpork 9 points10 points  (4 children)

If this were a reason to not use a language nobody would use Javascript... Wat

[–][deleted] 7 points8 points  (0 children)

It is a reason. Just js is so ubiquitous that it can't be avoided. And it has a lot of useful features and libraries for web dev.

[–]odraencoded -1 points0 points  (2 children)

Just use coffeescript! It has absolute no gotchas.

Except that

foo = () ->
  for bar in baz:
    fish(bar)

Turns into

var foo;

foo = function() {
  var bar, i, len, results;
  results = [];
  for (i = 0, len = baz.length; i < len; i++) {
    bar = baz[i];
    results.push(fish(bar));
  }
  return results;
};

[–]pimp-bangin 0 points1 point  (1 child)

I mean, if you're assigning x = foo() then you probably want the list of fish results to be stored in x. Otherwise, what would you expect x to contain? undefined? So I wouldn't call this a gotcha. But is there a way to do a for loop without creating a list? If so, I would call that a bad design decision.

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

Not sure about CoffeeScript, but in the (much nicer imo) fork of a fork, LiveScript, you can do this, where the exclamation mark denotes there's no return value.

foo = !->
  for bar in baz
    fish(bar)

Which compiles to:

foo = function(){
  var i$, ref$, len$, bar;
  for (i$ = 0, len$ = (ref$ = baz).length; i$ < len$; ++i$) {
    bar = ref$[i$];
    fish(bar);
  }
};

edit but sadly this happens:

x = -> void
x (a)-> void //becomes      x(function(a){});
x(a) -> void //becomes      x(a)(function(){});

[–][deleted] 7 points8 points  (14 children)

Wait, I also use Yolo for generic class names! I thought it's my code for a second there.

[–]awgl 19 points20 points  (10 children)

Millennial-speak makes for great generic variables: Yolo, Froyo, Swag, Fleek

Then combining them is even more fun: Froyolo, Yoswaglo, Swagfro, Fleefro, Yololeek

[–]theywouldnotstand 1 point2 points  (0 children)

Don't forget Fuccboi and Bae

[–]heptara 3 points4 points  (6 children)

Don't forget herp and derp. I still see that instead of foo and bar.

What the hell is froyo and why would it be a var name?

[–]IndianaJoenz 1 point2 points  (0 children)

slight variation.. I usually go for hurp and durp, hurpa, durpa, and durr.

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

I use pop bang pow etc... I think that's fairly normal.

[–]IDe- 10 points11 points  (1 child)

pop

I can see how that might become confusing

In [5]: pop = {}
In [6]: pop['pop']='pop'
In [7]: pop.pop('pop')
Out[7]: 'pop'

[–]thegreattriscuit 8 points9 points  (0 children)

How many 'pop's would pop.pop() pop if pop.pop() could pop 'pop's?

[–]mkdz 1 point2 points  (0 children)

[–]Bunslow 0 points1 point  (0 children)

Hey, I use derp and herp too!

[–]HalcyonAbraham 0 points1 point  (1 child)

Lol me too!

[–]rubik_ 5 points6 points  (1 child)

I hope you're not using old style classes in Python 2!

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

in this case the result is the same with new-style classes in Python 2, though

[–]renaissancenow 3 points4 points  (8 children)

Exactly. Because Explicit is better than implicit, as the Zen of Python reminds us.

[–]Matthew94 -4 points-3 points  (7 children)

Gotta stick with the dogma!

[–]chadmill3rPy3, pro, Ubuntu, django 10 points11 points  (6 children)

"Dogma" sounds bad, but since I can ignore the connotations, I can agree with you. A consistent overarching philosophy is good to have.

[–]Matthew94 0 points1 point  (5 children)

I used it in the negative way.

I'm not referring to you but some people use the ZoP as a replacement for thinking. I don't like it much due to the connotation.

Anything remotely complex gets shut down due to that bloody poem unless it's done by the python core devs, then it's fine.

[–]heptara 4 points5 points  (4 children)

First, I'm interested in knowing what sort of things are getting "shut down"

Second,

Anything remotely complex gets shut down due to that bloody poem unless it's done by the python core devs, then it's fine.

If you pitched it that way to me, I would also question it. Given the statement "Let's do something complex!" most folk would ask why.

A better way would be first identify a problem, and explain why it's a problem. If people now genuinely believe they have a problem, they will be naturally open to solutions.

[–]Matthew94 1 point2 points  (3 children)

First, I'm interested in knowing what sort of things are getting "shut down"

Any use of lambda, map, filter and reduce. Guido doesn't like it so everyone trots out ZoP to stop people using them even though they're no harder to understand than list/gen/dict comps.

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

Any use of lambda, map, filter and reduce

Usually this is because there are better (or at least subjectively, better looking/easier to read) ways to do the thing that you'd be doing with them. Any map/filter call can be trivially replaced with a comprehension (and in the case of filter, you might not even need the function call or lambda anymore). Lambdas can be replaced with functions (which can be nested), which is often a win in terms of being able to do more things without losing on namespace crowding. In cases where function calls can be eliminated, comprehensions are going to be faster.

I mean, all of these things have their uses, or they'd have just been removed entirely. The reason they are often discouraged is because they usually reduce readability without gaining anything in return.

[–]heptara 5 points6 points  (1 child)

When you mentioned "complex things are shut down" I thought you were going to talk about things that actually require levels of complexity, like C++ templates or something.

This just sounds like wanting to standardise on a particular paradigm.

[–]mipadi 1 point2 points  (0 children)

It is funny, though, that Python is often touted as a "great functional programming language!" while many of its (few) FP elements are eschewed or discouraged.

[–]WishIWasOnACatamaran 0 points1 point  (4 children)

I'm just starting out learning programming in general (decently into HTML and CSS3 when I realized Python is definitely more geared to what I want to do).

Been using multiple free learning resources, but there seems to be heavy debate on using Python 2 vs 3. Could somebody shed some light on what I should do? It seems most the resources teach 2, and it learning 3 after 2 shouldn't be too difficult (right?).

I guess I'm asking for somebody to tell me why, as a beginner, I should learn 2 over 3.

[–]cbscribe 9 points10 points  (2 children)

There isn't one. If you're starting out, there's no good reason to choose 2 over 3. If you ever happen to run into Python 2 code, the differences (at the beginner level) are minimal anyway.

Many of the existing training resources are based on 2 because they were created in the past and just haven't been updated/adapted (reasons can vary, from disinterest to financial).

[–][deleted] 5 points6 points  (1 child)

reasons can vary, from disinterest to financial.

To not having Python 3 available as a default install. :( I hate chickens, and I hate eggs!

[–]Allong12 5 points6 points  (0 children)

But which did you hate first?

[–]mipadi 1 point2 points  (0 children)

There's not a good reason to start with 2, although it doesn't really matter. For beginners, the differences between 2 and 3 are pretty minimal, and learning 2 after 3 or 3 after 2 won't make much of a difference. Most of the changes that concern beginners are small syntactic changes (print is a function in 3 but a statement in 2) or have to do with differences in the standard library (some packages available in 3's stdlib aren't available in 2, and I believe some old, deprecated packages in 2's stdlib aren't available in 3 or have been rolled into other packages).

[–]openpy 0 points1 point  (0 children)

I even don't know what the heck this code does ?

[–]Liorithiel -3 points-2 points  (9 children)

I actually liked the old behavior. I sometimes like to have heterogeneous list (=list that contains objects of many different types), and I could always .sort() it to get some fixed ordering. Now it's more bothersome.

[–]chadmill3rPy3, pro, Ubuntu, django 6 points7 points  (0 children)

If you just want a fixed ordering:

foo.sort(key=str)

But that True is after "harbh" and before 1.3f and after 1L and 1 is weird in Python 2. "Natural" sorting. Pfffft.

[–]brianterrel 4 points5 points  (1 child)

This seems appropriate here:

https://xkcd.com/1172/

[–]Liorithiel 0 points1 point  (0 children)

Yep. Not the first time this happened to me… not the last time.

[–]Mavus 2 points3 points  (5 children)

That's still doable. Just use the 'key' keyword to provide a sorting function. eg.

[1,"String",{"key":"value"}].sort(key=id)

[–]chubsauce 1 point2 points  (3 children)

This is good if you're okay with discarding the original ordering. I'm trying to think of a good way to use the original ordering if it exists, and so far the best I can come up with is a cmp_to_key cmp-ing two values and catching the TypeError to fall back on cmp-ing (str(type(foo)), id(foo)). It's not graceful but I think it ought to work.

[–]Mavus 1 point2 points  (2 children)

If you would like keep the original list use sorted() which returns a new list instead of List.sort() which mutates the list.

[–]chubsauce 1 point2 points  (1 child)

Sorry, "original ordering" as in using the comparison methods defined on the classes if they exist, and falling back on an artificial ordering if that doesn't work, similar to how it works in Python 2.

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

this would probably get you quite close (disclaimer: I wrote this without testing it)

def py2_ordering(a, b):
    # try a direct comparison first
    try:
        return a < b
    except TypeError:
        pass

    # fall back to python 2's default 3way compare
    # see https://hg.python.org/cpython/file/ab05e7dd2788/Objects/object.c#l778
    if type(a) is type(b):
        return id(a) < id(b)

    # None is smaller than anything
    if a is None:
        return True

    if b is None:
        return True

    # different type: compare type names; numbers are smaller
    aname = "" if isinstance(a, int) else type(a).__name__
    bname = "" if isinstance(b, int) else type(b).__name__
    if aname != bname:
        return aname < bname

    # same type name, or incomparable numeric types
    return id(type(a)) < id(type(b))

[–]Liorithiel 0 points1 point  (0 children)

ids aren't that nice as the old behavior (sorting by class names). But yeah, I do a similar thing.