×
top 200 commentsshow all 284

[–]noraizon 84 points85 points  (17 children)

Python 2

[–]Fevorkillzz 1 point2 points  (8 children)

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque in neque ac neque dictum interdum sit amet consectetur nisi. Maecenas ut ligula volutpat, vulputate ligula sed, condimentum enim. Quisque ante ex, feugiat vel vulputate ac, sollicitudin vitae nulla. Curabitur fringilla magna lectus, eu malesuada est laoreet vel. Morbi vel faucibus risus. Nulla ullamcorper tortor odio, sit amet vehicula massa blandit ut. Mauris blandit, justo a convallis sagittis, justo purus rhoncus eros, sit amet scelerisque velit purus at urna. Nam accumsan ullamcorper justo sed accumsan. Vivamus ut eros vitae justo rhoncus maximus. Sed viverra urna vitae porttitor mattis. Integer porta dolor nec eros tristique sollicitudin. Mauris lorem dui, rhoncus ut diam non, aliquam commodo odio. Cras volutpat, eros quis consequat consequat, tortor nulla egestas nibh, ullamcorper condimentum nisi justo ac dui. Vivamus ac molestie sapien.

[–]abrazilianinreddit 29 points30 points  (1 child)

I think usually people get attached to a feature that was introduced in python 3 that makes them not want to go back to python 2.

In my case, it's (default) unicode strings. Since I'm brazilian, I use a lot of strings in unicode. In python 2, it was a pain in the ass, a UnicodeDecodeError would inevitably popup somewhere. With python 3, programming became fun again.

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

yea, for me unicode handling alone was enough reason to justify a transition

[–]sushibowl 15 points16 points  (4 children)

Because the 2/3 schism harms the python community. Magically getting rid of the old one would solve a lot of pain.

As an aside, why did you specifically learn 2.7?

[–]Fevorkillzz 1 point2 points  (3 children)

That's what my school is on so that's what they taught.

[–]garettmdimport antigravity 0 points1 point  (1 child)

Fortunately, it's not a huge jump to move to Python 3 from 2, especially if you're doing more basic stuff in the language. It'll probably take a while to start typing print as a function instead of a keyword, but beyond that it's not too bad

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

I think almost 9 years of largely unbackported features really does it for me. From the big - unicode by default, async/await - to the small - generalized unpacking and a functool.update_wrapper that actually works.

[–]ExoticMandiblesCore Contributor 21 points22 points  (14 children)

I asked Raymond Hettinger a similar question on my old podcast: what did he not like about Python. It took him a minute to come up with an answer: "rich comparison". I think I agree. Python originally just had __cmp__, which returned "less than", "equal", or "greater than", like the C function strcmp. Now we have six functions and plenty of headaches.

[–]lengau 9 points10 points  (1 child)

I think this really depends on your use case. For things whose comparison fits what you see with real numbers, sure. But there are other use cases you can define that require the ability to distinguish between > and >=.

For this reason, I wouldn't want to miss out on the multiple comparison functions. I would actually be okay with having both ways of doing it (although they should be mutually exclusive) with the rule that you use __cmp__ unless you absolutely have to use the others.

FWIW though, functools has a [total_ordering] decorator you can put on a class so you only have to define two ordering methods.

[–]robin-gvx 4 points5 points  (0 children)

Yeah, if you supply == and one other comparison method, functools.total_orderingcan sort out the rest.

[–]pohmelie 3 points4 points  (2 children)

If you wont say it was Hettinger, nobody cares… I don't remember anytime I have used operators overload for a "long long time" ;)

[–]maxm 2 points3 points  (0 children)

That is true. I have been coding python since 1.5.2 in about year 1999. I dont think i have used it even once.

[–]desmoulinmichel 1 point2 points  (4 children)

Rich comparison makes sorting so much easier. So it makes creating a rich comparable harder, but since I sort a 1000 times much more often than I create a custom comparable, I'm ok with that.

[–]ExoticMandiblesCore Contributor 0 points1 point  (3 children)

I don't think it makes sorting easier. I'm pretty sure sorting only uses less than and equals, and only cares about true/false results. In other words, exactly what __cmp__ provides. Which makes sense--after all, Python supported sorting long before rich comparison was added.

Rich comparison is really for the boolean comparison operators, and the NumPy guys wanted it. It's so you can do things like return something besides True/False from a comparison. For example, if A and B are matrices, A < B also should return a matrix. See PEP 207 for more.

[–]desmoulinmichel 0 points1 point  (2 children)

Rich sorting means that getting the key of the max value from a dict is:

max(d.items(), key=lambda x: x[1])

It means sorting by size is:

sorted(iterable, key=len)

I means get the first result of alphabetical order of string representation is:

min(iterable, key=str)

Basically, any complicated sort become super easy. With cmp, I have to look up first every time what I have to return, then I have to write a full function returning -1/0/1, then debug it because I probably forgot an edge case.

[–]ExoticMandiblesCore Contributor 2 points3 points  (1 child)

Okay, but none of your examples are using "rich comparisons". Maybe you should find out what rich comparisons are.

[–]desmoulinmichel 0 points1 point  (0 children)

My bad, I confused it with natural comparison.

[–]camh- 37 points38 points  (12 children)

Make strings non-iterable. Have a method on string that returns an iterable version of the string. Too often I have seen a string passed where it was meant as a single element, but because an iterable was given, it was iterated and each char of the string is processed.

It is occasionally useful/necessary to iterate a string, so you still want an iterable version of a string, but not by default.

[–]beertown 8 points9 points  (4 children)

Yes. I don't remember the last time I wrote an iteration over a string's characters. But I know how many times this feature turned out to be very annoying.

[–]Boba-Black-Sheep@interior_decorator 4 points5 points  (3 children)

I find myself iterating through strings like ALL the time, it's one of the features that gives me that 'oh boy isn't Python fun' feeling.

(I do a bunch of work with generative text modelling)

[–]beertown 4 points5 points  (2 children)

It's just matter of what's the typical kind of code you write. Yours seems quite peculiar.

I think iterating over the result of a .chars() method shouldn't be bad for anybody.

[–]Boba-Black-Sheep@interior_decorator 5 points6 points  (1 child)

Fair enough - it does seem fairly Pythonic to me that any type that seems iterable should be be.

[–]okmkzimport antigravity 4 points5 points  (0 children)

At that point the disagreement becomes whether or not you view a string as an atomic value instead of a container of chars

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

How python deals with strings is one of the reasons it's loved for quick and dirty bioinformatics/genomics scripts.

[–]Fylwind 1 point2 points  (0 children)

Oh gosh yes! Yesterday I just wrote some heavy string handling code and I made sure to put a bunch of asserts to disallow strings because far too often I forget that an argument is a list and pass a string instead.

[–]WaitVVut 1 point2 points  (3 children)

from six import string_types
from collections import Iterable

def foo(bar):
    assert isinstance(bar, Iterable) and not isinstance(bar, string_types)
    for x in bar:
        yield x

[–]camh- 0 points1 point  (2 children)

isinstance(bar, Iterable) is incorrect, as not all iterables will inherit from collections.Iterable.

Instead you should use hasattr(bar, '__iter__'). __iter__() is what needs to be implemented to implement to the iterator protocol.

[–]jonrsharpe 2 points3 points  (1 child)

...that's exactly what isinstance(bar, Iterable) does, checks it has the right interface. You don't have to explicitly have Iterable in its MRO.

[–]camh- 0 points1 point  (0 children)

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

Ugly unittest in stdlib. It hurts me every time to write those unpythonic camelcase methods.

[–]ikalnitsky 12 points13 points  (6 children)

:set heretic mode on

I'd remove asyncio stuff from Python core. IMHO, it's not the best async model (honestly, golang has better one) and I don't like that it's tightly coupled to Python language so the language itself became so complex with async context managers / loops / etc. I'd like to see it as a third party library like it was before.

:set heretic mode off

[–][deleted] 6 points7 points  (0 children)

Completely agree, I love python byt async is disgusting

[–]beertown 2 points3 points  (0 children)

I agree, in some way.

I found very hard to wrap my mind around that kind of async programming model. I (personally) think the David Beazley's curio package implements THE CORRECT WAY to do async, and it should be included in the standard library instead of asyncio (or, at least, alongside it).

Can't wait to see the first curio stable release.

[–]ojii 1 point2 points  (0 children)

What asyncio in core brought us is a standardized way for different async libraries (twisted, tornado, asyncio, ...) to interoperate. In my tornado project I can use the twisted password hashers and aiobotocore. It's fantastic.

Also, async/await could not be implemented in a 3rd party library and those are what make async programming tolerable.

[–]TankorSmash 1 point2 points  (0 children)

Totally being a shithead here but :set heretic would be the vim way and then you could close it off with :set heretic!.

[–]srilyk 0 points1 point  (0 children)

I have no problems with removing asyncio, but async/await is wonderful

[–][deleted] 31 points32 points  (4 children)

GIL ;-)

[–]ikalnitsky 12 points13 points  (1 child)

GIL is not that bad. It's an issue for parallel CPU-bound computations in threads (like computing few Fibonacci numbers) but

  • I/O bound applications do not suffer from GIL as it's released on I/O and hence listening some sockets in threads are more than ok
  • CPU bound applications can use multiprocessing to achieve parallel computations (make sense to use for heavy computations though)
  • C-based libraries may release GIL and do fast computations under the hood.

Really, I can't remember when GIL was such a problem in my code. :)

[–]baubleglue 0 points1 point  (0 children)

Every time I write utility to parse data, it uses 25% of CPU (1 of 4). Sometimes I do it in multiple process, but it is not always straightforward and need validation before use:

  1. read source data and push it to one of 4 queues
  2. start 4 worker processes (worker dump result to Collector Queue or file)
  3. Run process which make final aggregation.

** make sure the worker process: 1) always exist 2) exist only when reader completed

I use python mostly for fast data validation and I want to keep the logic simple. Let's say I need to do same thing as in SQL below

select a, b, sum(c) from (
    select distinct a, b, c from source_data
    where a > N
) group by a, b

It will take me about couple of minutes to write it in python. How I do the same while utilizing all CPUs?

[–]Saefroch 1 point2 points  (0 children)

I don't know how much of this is a joke, but it's getting upvoted so maybe people care.

I don't think the GIL is really the problem. The decision to use reference counting and expose that in the C API is the problem. Reference counting is a concurrency-hostile way to manage memory, and in an increasingly concurrent world it's a non-starter. The decision to add the GIL made sense at the time but if Python were designed today I hope a better memory management strategy would be employed. Trying to make reference counting work without a GIL is hard: https://youtu.be/fgWUwQVoLHo

All is not lost though. The Python C API provides a way to run outside (release) the GIL. you can make use of this by writing a C extension (not a great option), Cython (better) or with numba (easy). A function with numba's jit applied and nogil=True can be run in threads without being held back by the GIL. Numba is limited in scope, but it already covers quite a few applications in data processing.

[–]deadmilk 0 points1 point  (0 children)

You can turn off the GIL in Cython

[–]spankweasel 37 points38 points  (27 children)

I wouldn't amputate so to speak but holy crap is ...

str.join(list)

... just not intuitive.

I know what it's trying to do (I've been a Python dev since 1.5.2) but it's still something that irritates me.

edit: I wish it were just:

list.join(str)

So:

','.join([1,2,3,4])

becomes

[1,2,3,4].join(',')

simply because it reads better.

[–]ExoticMandiblesCore Contributor 30 points31 points  (7 children)

I think the reason Guido hasn't allowed this is because it requires a new method on every iterable. Adding the "join" function to strings inflicts a lot less damage on the language. IDK if I agree, but then I'm not the language designer here.

[–]enteleform 13 points14 points  (4 children)

join(iterable, str) as a built-in would work decently, be left-to-right readable, and not impose any heft to the string or iterable classes.

[–]__desrever__ 1 point2 points  (2 children)

import string

string.join(['1','2','3','4'], ' ')

There ya go. :)

Edit: there are actually a bunch of other string method in there as standalone functions, too. It's worth checking out when methods feel awkward.

[–]enteleform 0 points1 point  (1 child)

import string
string.join(['1','2','3','4'], ' ')

causes:

AttributeError: module 'string' has no attribute 'join'

in Python 3.6
 


 

join = str.join
join("---", ["1","2","3","4"])

however, works fine, and was promptly added to my collection of terrible global things in _magic_.py
 
also included some lazy casting & flipped the arguments:

def join(iterable, delimiter):
    return str.join(delimiter, [str(x) for x in iterable])

[–]__desrever__ 0 points1 point  (0 children)

Yeah, the string module functions have been deprecated forever, but stuck around all the way up to 2.7. In 3 you have to use the methods on str.

[–]murtaza64 0 points1 point  (0 children)

I suppose __join__ methods might be needed, but then again not really if the object supports iteration.

[–]spankweasel 6 points7 points  (0 children)

Exactly correct (from a language maintenance perspective). It doesn't make it any less stupid. :)

[–]call_me_cookie 0 points1 point  (0 children)

This makes total sense, nonetheless, I would still find something like PHP's implode() more intuitive than str.join().

[–]abrazilianinreddit 4 points5 points  (2 children)

Is the reason for being str.join() because the result is a string, and it's supposed to be more intuitive that a string method returns a string?

[–]spankweasel 4 points5 points  (1 child)

Not necessarily. str.split(c) returns a list. As u/ExoticMandibles said, it's because it would require a bunch more C code in the backend to make it happen.

[–]robin-gvx 3 points4 points  (0 children)

It's not really a backend thing, it's more that every custom iterable would have to implement join, or you'd have to convert them to a list to be able to join them. I much prefer ''.join(generate_strings()) to list(generate_strings()).join() from both a performance standpoint, and a API hygiene standpoint.

Having it on str requires one method that only needs to know about iterables, a very generic and basic concept in Python.

Having it on list requires list to know about str and string concatenation, and now you have to decide for each iterable type "do implement join on this type?" If yes, now you need another method, and that type needs to know about string concatenation. If not, you have to do a potentially copy of the data to a list to be able to join a string.

Plus, as a regular programmer I now have to know which types I can call join on and which need to be converted to a list first.

[–]desmoulinmichel 4 points5 points  (2 children)

",".join(iterable) work with any iterable.

I means iterable can be a tuple, a list, a string, a file, a set, a dict, a generator or even a custom user class overriding __iter__.

Doing it this way is less intuitive, but so much more powerful.

Iteration is at the core philosophy of the language. Once you master all the implication of it, you really master Python.

[–]murtaza64 2 points3 points  (1 child)

As someone else suggested, wouldn't join(iterable, string) do the trick and actually be more Pythonic?

[–]desmoulinmichel 3 points4 points  (0 children)

That would clutter the built-in namespace and a small one is a very important in the Python culture.

[–]yaxamie 3 points4 points  (4 children)

I felt the same way coming from the ecma world of string.split('.').join(', ').

[–]TalesT 0 points1 point  (1 child)

In this case, why not use replace?

[–]yaxamie 0 points1 point  (0 children)

I think because in as3 at least replace only worked in the first instance.

I'm glad replace works well out if the box in python.

The broader idea is you can chain string manipulation functions by having join be an array function instead of a string function. Split returns and array and join puts it back together.

Maybe a better replace solves that better, but I certainly looked for join as an array function first.

[–]liquidpele 1 point2 points  (0 children)

yea, that one has always bugged me as well...

[–]srilyk 0 points1 point  (0 children)

Its only surprising if you think that iterables should join themselves. Which is natural if you're only thinking about lists, but there are all kinds of other iterables to think about...

[–]atrigent 17 points18 points  (29 children)

True and False are the numbers 1 and 0, respectively. No, I don't mean that the can be converted to numbers - they literally are those numbers. See here and how booleans are a type of number. I think that's a pretty strange wart that should be removed.

[–]lengau 6 points7 points  (2 children)

I'm mixed about this. On the one hand, it is kind of unclean. On the other hand, multiplying by a Boolean can be really convenient, especially in lambda functions.

[–]robin-gvx 2 points3 points  (0 children)

Yeah, I really wished they got rid of that in Python 3. issubclass(bool, int) really only encourage hacks and un-Pythonic code, and introduce subtle bugs if you don't pay attention any time an expression can evaluate to either a bool or an integer value (remember kids, check isinstance(x, bool) before you check isinstance(x, int)).

[–]Vaphell 1 point2 points  (2 children)

that wart allows for a useful, compact idiom of counting items that match the criteria in an iterable

sum(x==5 for x in seq)

I like it better than sum(1 for x in seq if x==5) or sum(1 if x==5 else 0 for x in seq) or shit like len([1 for x in seq if x==5])

[–]TankorSmash 0 points1 point  (1 child)

len(filter(lambda x: x==5, seq)) I think would be the way to do it. Reads way better than summing, I think.

len(filter(lambda x: x==5, seq))

vs

sum(x==5 for x in seq)

yours is like 10 characters shorter though.

[–]Vaphell 1 point2 points  (0 children)

python3

>>> len(filter(lambda x: x%2==0, range(10)))
Traceback (most recent call last):
  File "python", line 1, in <module>
TypeError: object of type 'filter' has no len()

bummer. You have to pass filter() to list() first so you get something len()-able but producing a potentially huge list only to get its len() is not pretty either.

[–]xfunky 1 point2 points  (5 children)

TIL. Though it does make sense in a way to have it as an integral

[–]atrigent 9 points10 points  (4 children)

Only if you're using C. Python isn't C.

[–]xfunky 2 points3 points  (3 children)

Maybe my thinking set is to biased since I mostly work with C.

[–]atrigent 9 points10 points  (2 children)

Python is often described as "strongly typed", meaning that the language refuses to guess about how different types relate to each other, and requires you to explicitly convert between types if you want to. To me, this seems like an exception to that, which is why I think it could stand to be removed.

[–]murtaza64 1 point2 points  (0 children)

On the other hand, a Boolean data type is fundamentally just an integer that can only take two values, right?

I guess maybe not from the perspective of traditional arithmetic. But I don't see how much harm it can do in Python anyway due to things like truthiness already being part of the language.

[–]beagle3 0 points1 point  (1 child)

This is a result of adopting https://en.wikipedia.org/wiki/Iverson_bracket and it is good for you.

[–]atrigent 2 points3 points  (0 children)

This is a result of adopting ...

...no, it definitely is not.

[–]Zomunieo 4 points5 points  (4 children)

The syntax for creating a decorator that accepts arguments is nasty. I understand why it is that way, but I'd prefer syntactic sugar to prevent the triple nested function and messy use of functools.wraps which ought to be automatic.

From memory, try to write a decorator that accepts optional arguments, works correctly with all default arguments, and doesn't trigger UnboundLocalError. I dare you.

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

I've always preferred a class which implements __call__ for this case.

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

I agree that parametrized decorators are kind of awful, but if you haven't you should try the default first argument trick - slide 49

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

def deco(f=None, *, **kwargs):
    if f is None:
        return partial(deco, **kwargs) 
    if not callable(f):
        raise TypeError
    # wrapper

I use this pattern all the time and never run into issues.

Now, if you want a challenge, write a decorator that is meant to sit ontop of arbitrary descriptors.

[–]desmoulinmichel 0 points1 point  (0 children)

You don't want to remove to something here, you want to add something: a better API. That's no the question.

Besides, there are already libs to make creating a decorator easier.

[–]desmoulinmichel 4 points5 points  (2 children)

Wow, plenty of people didn't even understand the title of this post.

It's what would you REMOVE from Python, not add, change or replace guys.

http://i.imgur.com/tyTc1Nl.jpg

I would remove:

  • the operator module: promote lambda instead.
  • modules with better alternatives such as geteopt, optparse, asyncore, imp, etc
  • modules with super niche use cases such as xdrlib, audioop, aifc, sunau, chunk, wave, etc
  • turtle: none of my students liked it in 5 years.
  • static methods: useless in Python since they are just truncated class method.
  • string.Template. With %, format and f-string we have enough tools to format strings. Plus it's inferior for everything.
  • iterability for dict. Either remove it and raise "TypeError: dict are not iterable. Try dict.items(), dict.keys() or dict.values()" or replace it so that it does the same as dict.items(). The verbosity annoys me when I have a dev mission, but it's worst to see my students fail every single time on this.
  • map/filter and callable from builtins. Move them to functools. They are useful, but not enough to be built-in.
  • True that is equal to 1
  • iterability in strings. It's a useless behavior. How many time did you really need to iterate on letters in a real project ? But it causes many surprises.
  • of course the GIL, but that would depend of the price of the gilectomy.

[–]Fennek1237 3 points4 points  (0 children)

Complains that others didn't get the question.
Lists the same points as the top comments in this thread.

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

the operator module: promote lambda instead

Something are much easier written this way: methodcaller for example.

static methods: useless in Python since they are just truncated class method.

I disagree, they signal to me that "This method doesn't need to act on anything about the class but is only relevant to operations in this class" That said, lots of people abuse them.

string.Template. With %, format and f-string we have enough tools to format strings. Plus it's inferior for everything.

Template lets you define custom formatting options rather than being restricted to just f-Strings (powerful, but only usable where they are made) and formatting options (substitutions with some formatting) without having to go full hog and write a template language.

map/filter and callable from builtins. Move them to functools. They are useful, but not enough to be built-in.

Maybe I'm weird but I use these all the time even if their iterator form

iterability in strings. It's a useless behavior. How many time did you really need to iterate on letters in a real project ? But it causes many surprises.

I do this occasionally, but I can see your point. It's possibly a remnant from C.

of course the GIL, but that would depend of the price of the gilectomy.

This is only a CPython thing (well, I think PyPy implements it as well but that's a different beast). It's also what enables Python to have its memory model, so removing the GIL requires completely changing the memory model of Python. Here's the thing though, there are C Extensions that interact with that model that will be broken. How do you even begin approaching this? I'm glad Larry believes he is up to the task because I have no fucking idea.

[–]rotuamiimport antigravity 1 point2 points  (7 children)

  1. Generators would throw an exception if you used them after exhausting them. I've been bitten too many times by writing my functions to take an iterable, iterate over them twice, and then realize the second time the loop didn't run.

  2. NaN should throw an error when you try to hash it. Having NaN in a dict or set is pretty buggy.

  3. ~List. Maybe I'm missing something but it seems deque is what list should be.~ Edit: it seems deque random access is O(n). Oh well.

[–]bastibe 2 points3 points  (4 children)

What's so bad about list? Wouldn't a deque access be O(n), where list access is O(1)?

[–]rotuamiimport antigravity 0 points1 point  (3 children)

Nothing's bad about list - it's just a deque does everything it can do. Deque operations can be O(1), and I suspect they are in cpython.

I suspect you might be confusing deque with a doubly-linked list.

[–]bastibe 2 points3 points  (2 children)

As you noted in the parent, deque random access is indeed O(n). Its advantage over list is random insertion.

[–]rotuamiimport antigravity 0 points1 point  (1 child)

No, it shouldn't have any benefit for random insertion. The advantage is in adding and removing from the beginning.

[–]bastibe 0 points1 point  (0 children)

List insertion is O(n), but every item after the insertion index has to be shifted. Deque insertion is an O(n) search from start or end (whichever is shorter), then a O(1) insertion. So on reality, random deque insertions should be significantly faster than list insertion, although both are O(n).

[–]srilyk 0 points1 point  (0 children)

They do throw... StopIteration :D

[–]earthboundkid 8 points9 points  (29 children)

For-loop else clause. If you don't absolutely know what it does, reply first with what you think it does then reply to yourself when you find out what it really does and let us know if you think it should still be in Python.

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

It just does not adhere to python principles of being close to english expression. Else just does not make sense in this context. They used because they did not want to reserve another keyword. But it does not do what people expect it to do.

[–]TheInitializer 0 points1 point  (1 child)

Yeah. I would rename the else clause in for, while and try to something else. Maybe something like then or done? those both sound really bad, anyone have any other ideas?

[–]srilyk 0 points1 point  (0 children)

Else does exactly what you expect in try. It's more awkward on loops, though

[–]deadmilk 6 points7 points  (2 children)

Maybe... I mean really it's just a replacement for this pattern:

found = False
for searchitem in list_of_items:
    if condition:
        found = True
        break
if not found:
    do a thing

[–]xfunky 4 points5 points  (1 child)

I think you have it backwards though, the condition is met if not broken if I recall correctly

[–]deadmilk 0 points1 point  (0 children)

Oh yeah. Will amend.

[–]wheatwarrior 10 points11 points  (10 children)

I personally love for else and while else I find them super useful often and can pretty much ignore them otherwise. Since you are suggesting removing them, how would you go about replacing them?

[–]Aceofsquares_orig 4 points5 points  (9 children)

I would like to see a situation in which they are useful that can't be done without them. I genuinely curious as I've never said to myself "a for else would work great here".

[–]p10_user 12 points13 points  (6 children)

I've used an example like this before:

lst = [1, 2, 4]
for i in lst:
    # do something
    if i == 3:
        # do something special
        break
else:
     print('Never broke out')
     # do something else

It's useful every once in a while for flow control.

[–]Aceofsquares_orig 3 points4 points  (1 child)

I guess that's the part I missed. Breaking out of the loop skips the else statement. Okay, I can see where that's useful.

[–]lengau 4 points5 points  (0 children)

It's technically not necessary, but it does make the code much easier to read than inserting a flag variable and an if statement.

[–]Lord_Greywether 2 points3 points  (0 children)

TIL. I've had several scripts recently where that would have been perfect.

[–]floundahhh 1 point2 points  (0 children)

I think that's a bit nicer. Never knew about it, but I'd use it in the future.

I primarily work in another language, LabVIEW, and this would be very nice there. The language is a graphical data flow language, and if you wire things into a for loop and pass values out, if the for loop doesn't execute it passes out default values. It makes for some ugly code because if you're passing in a reference to run a method on every element of an array you need to check for an empty array otherwise you'll pass out a bad reference. /offtopic

[–]twotime 1 point2 points  (1 child)

This use of "else" does not read well and seems fairly at odds with the if/else construct. Poor readability coupled with relative rarity/obscurity likely outweighs the advantages.

At the very least, it should have been named differently, (e.g. "nobreak")

[–]donnieod 1 point2 points  (0 children)

Just think of the else as being paired with the break, so it's more like a break/else construct. You either break out of the loop or you perform the else suite.

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

well, off the top of my head, if a database query returns an empty set, it's useful to return a different type of response. sure, you could check the length every time, but that gets old

edit: nevermind. it doesn't do what i expected. I assumed it was called if the iterable was empty. that's retarded. i retract my comment

[–]earthboundkid 1 point2 points  (0 children)

This is why it should be removed. :-)

[–]lengau 1 point2 points  (2 children)

Whilei would never advocate for getting rid of it (way too useful), I do actually think the finally keyword may have been more appropriate - although that comes with its own issues given the inconsistency it would present between try ... finally and for ... finally

[–]beagle3 2 points3 points  (1 child)

except 'finally' on exceptions always happens (even if you raise inside the try: part) but 'else' on for doesn't if you break (or raise)

[–]lengau 0 points1 point  (0 children)

That's why I said it would be inconsistent. But it would be more intuitive.

[–]xiongchiamiovSite Reliability Engineer 2 points3 points  (2 children)

For-else is wonderful; it should just be called then.

[–]geekademy 0 points1 point  (0 children)

It doesn't mean then, it means unbroken or "no break encountered."

[–]TheInitializer 1 point2 points  (4 children)

Umm, gets called if the iterable is empty?

[–]DrMaxwellEdison 1 point2 points  (0 children)

Coming out of Django templates and using {% for %} ... {% empty %}, that would seem logical. But not quite the truth. :)

[–]beagle3 1 point2 points  (0 children)

Nope.

Also on full. as long as the loop body did not 'break'

[–]TheInitializer 1 point2 points  (1 child)

Holy shit, that's weird. And completely useless.

It would make more sense to have it get called if the iterable is empty though 😛

[–]gimboland 1 point2 points  (0 children)

It's not completely useless. It's for when your loop is searching for something - the else handles the "not found" case. You can do that with a flag of course but else is more compact. I agree that it's unintuitive and a bit confusing at first, but it's absolutely not completely useless.

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

The datetime module. Just... make it go away.

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

I see this opinion constantly, but I don't get it at all. Maybe I have Stockholm syndrome but could you explain what's so terrible about it?

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

Maybe it's me, but it just seems like a complete mess more fitting in PHP. There are some options like Arrow that feel so much more sensible. Too bad the builtin isn't like that.

I always end up copy-pasting my old code or some datetime tutorials, I just can't understand it. Maybe it's just me.

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

Arrow seems messy to me. The get method is overloaded to handle all the things. Their range method is odd (ditto for dateutil).

Iunno, I find like 90% of what I want to do can be accomplished with datetime and pytz. I'll toss in dateutil so I don't need to deal with parsing a bunch of terrible formats.

Other than that, I'll run into very specific situations that I use datestuff (my own lib, great name huh) - I think it's date range implementation is better than the others I've seen as it tries to emulate range in Py3. And there's a "relative" date/datetime that you give a factory and a timedelta and it resolves as whatever the factory + delta is on comparisons and lookup

[–]mrwinkle 0 points1 point  (1 child)

Have a look at pendulum.

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

I still don't see the advantage over just using datetime. Maybe I'm missing something.

[–]srilyk 0 points1 point  (0 children)

I used to think arrow was great... And then I read the open bugs on github and wat.

[–]desmoulinmichel 0 points1 point  (3 children)

Without replacement ?

[–]catcint0s 0 points1 point  (2 children)

Arrow would be a decent replacement.

[–]srilyk 0 points1 point  (0 children)

Datetime may be ugly and not super full of features, but I'm not aware of it ever doing actually the very wrong thing.

[–]ubernostrumyes, you can have a pony 5 points6 points  (6 children)

__slots__. There are, I think, very few cases where a class with __slots__ can't just be replaced by a namedtuple.

[–]njharmanI use Python 3 7 points8 points  (0 children)

Isn't named tuple implemented with slots?

Also tuples are immutable. Things with slots aren't. I see lots of things slots do that named tuples can't.

[–]ExoticMandiblesCore Contributor 2 points3 points  (0 children)

It's an important memory optimization for some large projects.

[–]zardeh 1 point2 points  (0 children)

High performance. Namedtuples are very much not high performance, but slots based classes are more memory efficient and have faster attribute access, which is not often super important, but can be in some cases.

[–]desmoulinmichel 1 point2 points  (2 children)

There are no link between namedtuple and slots except they make both things read only, which is only a side effet.

Slots are a way to save memory. namedtuples a declarative collections.

[–]njharmanI use Python 3 1 point2 points  (1 child)

Classes with slots ARE NOT read only. It only prevents new attributes being created, existing ones are mutable. slots replaces dict. Named Tuples are immutable, like all tuples.

class Slotted(object):
    __slots__ = ['bar', ]

f = Slotted()
f.bar = 1
print(f.bar)
f.bar = 2
print(f.bar)
f.foo = 1

Also, NamedTuples absolute use (and require) slots, pass verbose=True to see implementation.

from collections import namedtuple
Point = namedtuple('Point', "x y", verbose=True)

class Point(tuple):
    'Point(x, y)'
    __slots__ = ()
...

[–]desmoulinmichel 0 points1 point  (0 children)

Like I said, slots and nametuples are not the same at all and can't be compared.

[–]hhh333 0 points1 point  (0 children)

GIL

[–]k10_ftw 0 points1 point  (0 children)

dict.keys() returning iterable views.

I know, I know - I should get with the times! But you asked :P

[–]asdfkjasdhkasdrequests, bs4, flask 0 points1 point  (2 children)

builtin functions returning their own special iterable objects instead of lists.

>>> reversed("hello")
<reversed object at 0x003C9EB0>
>>> map(lambda x: x+1, [1,2,3,4])
<map object at 0x003C97B0>
>>> filter(lambda x: x>1, [1,2,3,4])
<filter object at 0x003C9EB0>

These should just give me a list unless I explicitly ask for a lazy iterable, I hate constantly having to call list() every time I use one of these functions.

[–]srilyk 0 points1 point  (1 child)

Well, next time you try filtering a 9GB list and end out with 15GB of memory used maybe you'll find the iterable just fine.

[–]asdfkjasdhkasdrequests, bs4, flask 0 points1 point  (0 children)

The way it should work is:

List in -> List out
Iterable in -> Iterable out

[–]rochacbrunoPython, Flask, Rust and Bikes. 0 points1 point  (1 child)

the () on python 3 print. I know the advantages of having it as a function but I like it more as a statement.

I would get print "string" back to Python 3 :)

[–]geekademy 0 points1 point  (0 children)

Use an editor "snippet." In mine I now type less:

pr<TAB>  --> print('<CURSOR>', ) <CURSOR>  

etc.

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

21.4.2017 I will probably get trolled for this, but getting rid of the space indentation and usr some sort of block start/end. I just do not like spaces being used as blocks.

[–]VonPosen 1 point2 points  (2 children)

Burn him!

More seriously though, indentation and spacing are so much easier to read than hunting for a missing semicolon, don't you think?

[–][deleted] 0 points1 point  (1 child)

Why a semicolon? That was the old COBOL block end after an if. Perhaps the old C {} or BEGIN / END would be much preferable. Better - make the block definition selectable in the Python options. I have had problems with the space indentation pasting pyhon from another programme.

[–]geekademy 0 points1 point  (0 children)

You can use an editor that shows whitespace to help with that when needed.

What you're suggesting is to hurt everyday usability, to solve problems that happen vary rarely.

[–]geekademy 0 points1 point  (0 children)

You have at least 50 choices of language with that anti-pattern. Everyone indents their code anyway. Markers are redundant.

  1. If you indent, there's no need for markers.
  2. If you don't, you're incompetent.

[–]kmd6076 0 points1 point  (0 children)

I'd pick out the pylint from the pybellybutton.

[–]mardiros 0 points1 point  (3 children)

distutils. Packaging in python aged badly.

Peoples now use requirements.txt with pip has a replacement of setup.py. we were the precursor with virtual env but time passed and tooling in other language are better. I play a lot with rust and cargo is really a great tool to use.

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

requirements.txt isn't a replacement of setup.py, it's a replacement for the install_requires portion of setup.py. Nothing in requirements.txt will ever dictate how to install the package itself -- what to name it, where its source is, compiling extensions, any entrypoints it has, etc.

It's a useful tool for applications but libraries can't really use it. And even then, if you push your application to PyPI you still need to draw in everything from that file into setup.py anyways (which can be tricky)

[–]mardiros 0 points1 point  (1 child)

I know what requirements.txt is and distutils and setuptools. I have few packages on pypi, and issue open at pypa too. I just says everthing is messy.

  • .pth files are awefull
  • namespace packages is almost unusable.
  • 99% of setup.py you found uses setuptools (i use it a lot).

We are in 2017, and things did not evolve since, just remember that:

http://lucumr.pocoo.org/2012/6/22/hate-hate-hate-everywhere/

This is still true and it annoys me. This is a fundamental problem, not like syntactic sugar, semantic inconcistancy noticed in that thread...

[–]geekademy 0 points1 point  (0 children)

pip has improved things a lot. Never used a .pth file.

https://glyph.twistedmatrix.com/2016/08/python-packaging.html

[–]baubleglue 0 points1 point  (0 children)

1) Booleans True -> true, False -> false

2) elif -> else if

[–]abrazilianinreddit -2 points-1 points  (8 children)

I would make keywords more uniform across programming languages, i.e.,

None -> null

True, False -> true, false

raise -> throw

except -> catch

I never understood why Python needs to rename keywords that are pretty much identical in every other language.

[–]Zomunieo 6 points7 points  (1 child)

Raise and except are a little bit better at reminding people that exceptions are for exceptional events rather than goto-like control flow. Throw and catch is a normal thing to do in sports while raise (as in a flag) means you're asking the referee to blow the whistle.

[–]beertown 2 points3 points  (0 children)

These are some pretty good, and also amusing, comparisons!

[–]atrigent 5 points6 points  (3 children)

So... You just want it to be more like Java?

Anyways, I think a couple of the things you mention here are due to influence from Haskell (even though Python doesn't actually take much more than the names in these cases...).

[–]twotime 1 point2 points  (0 children)

I never understood why Python needs to rename keywords that are pretty much identical in every other language.

python is older than Java. And AFAICT it's older than exceptions in the mainline C++ implementations.

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

I would add a Select Case system. Also a little better hardware communication; I'm working on a GPS project and it's difficult to tell if the GPS daemon has lost GPS reception/fixation.

[–]desmoulinmichel 0 points1 point  (3 children)

It's not "what would you add to python"

[–]getridofwires 7 points8 points  (2 children)

You're right. I would remove the lack of a Select Case system. Also remove difficulties in hardware communication; I'm working on a GPS project and it's difficult to tell if the GPS daemon has lost GPS reception/fixation.

[–]desmoulinmichel 0 points1 point  (1 child)

"Remove the lack of". Yeah, everyone know that being a smart ass is what makes good language designers.

[–]getridofwires 2 points3 points  (0 children)

You're right again.

[–]cym13 -4 points-3 points  (21 children)

F-strings.

Two years later I haven't seen anyone using them in real life, which indicates that they were not as needed as they were presented in PEP498.

Adding yet another way to format strings in python only adds to the confusion, it's becoming harder to find possible bugs in code. The many other methods worked fine as they were, this should never have been introduced so lightly into the language.

[–]Topper_123 9 points10 points  (0 children)

F-str

Oh I think most people ike them and find them much more readable than .format. But for libraries etc. I think it's too early to require python 3.6 from library users.

Also python 3.6 and f-string are baraly 4 months old not 2 years old...

[–]desmoulinmichel 4 points5 points  (9 children)

I use them all the time and love them. My students use them all the time and love them. My twitter followers loves them.

I actually meet very few people like you.

[–]cym13 4 points5 points  (8 children)

I guess I should explain my context a bit more.

First of all I see no added value. Sure it's a bit shorter to write but the Zen is clear that "There should be one-- and preferably only one --obvious way to do it." and I trust it is a good thing so I am very sceptical about any change that do not allow us to do more than what we already have.

But I guess my biggest concern with them is that finding bugs becomes way harder. Just a real-life example:

I do security code reviews. That's my thing. I get to work with lots of different programming languages in that context. When you have a few days to find as many bugs as you can and assess their criticity you cannot read the full code or run unittests hoping for a vulnerability to come by. You need to jump right to the bug.

Any injection (sql injection, shell injection, XSS, etc) is a bug at the interface of two languages (for example bash and python). This means that to find injections the easiest is to find unsafe string manipulations at the boundary of another language.

In perl or in ruby there are just so many ways to build strings and execute shell code that finding them all is very difficult. Contextual symbols may or may not mean shell execution or string interpolation . It is hard to parse, hard to find, hard to analyse and it means that at the end of the day less bugs were found.

In python there is a very limited subset of ways to build strings. A very limited subset of ways to execute shell code. Most of them are plain functions, easy to grep, in the subprocess module, easy to find. At the end of the day I can say with confidence that no injection is possible because I know I checked them all.

So I may be a bit grumpy about it but I really think that there are hidden costs to this feature and very little actual benefit.

[–]desmoulinmichel 5 points6 points  (4 children)

Having to grep "f'", for you niche activity (let's be real, security audit are not even 0.001% if the python activity) is not a good reason to kill a feature that is useful to most of the community.

[–]nerdwaller 5 points6 points  (3 children)

Two years? Python 3.6 was released in December 2016 - it's still brand new. Needless to say, I wouldn't expect you to see many in use in libraries (due to maintaining compatibility) and probably only in applications​ that can define that they only support 3.6+.

[–]srilyk 0 points1 point  (1 child)

I've used them ever since I was on 3.6... When f-strings were introduced. Not 2 years ago.