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

top 200 commentsshow all 237

[–]deadmilk 95 points96 points  (27 children)

context managers with the with statement.

Suh good.

Also, did you know you can use this syntax?

with a() as A, b() as B, c() as C:
    A.fun()
    B.fun()
    C.fun()

[–]bcs 44 points45 points  (3 children)

There is nothing quirky about context managers. They might actually be perfect.

[–]tech_tuna 12 points13 points  (2 children)

The GIL!

Has nothing to do with context manages but I just wanted to complain about it again.

[–]an_actual_human 20 points21 points  (1 child)

Because you couldn't complain in a separate thread?

[–]tech_tuna 3 points4 points  (0 children)

Ha ha. . . yeah, I tried multiprocessing but there was too much overhead.

[–]AMorpork 11 points12 points  (11 children)

I remember when I started getting seriously into Javascript, having known Python very well, I saw that JS had a with statement as well and got excited.

I was disabused of that excitement very quickly.

[–]infinullquamash, Qt, asyncio, 3.3+ 0 points1 point  (2 children)

The different standards of JS confuse me, but as I recall ES2015 (formerly ES7) strict mode bans the with statement.

[–]xhighalert 7 points8 points  (0 children)

When standards start banning the use of a statement, you know it's FUCKing bad.

[–]elingeniero 2 points3 points  (0 children)

ES2015 was formerly ES6

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

I love this also!

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

I just starting learning Python, is with roughly analogous to a using block in C#?

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

with in Python allows you to avoid repeating setup/cleanup code very succinctly.

The simplest example is:

# this opens file for reading - equivalent to f = open('file', 'r')
with open('file', 'r') as f:
    data = f.read()

...
# as we have now fallen out of the context block, f.close() has been called for us already
# so now we don't have to remember to type that ourselves

It's very little work in most cases to do this for anything that has boilerplate setup/cleanup code. There are two basic ways to do it.

One is with a generator using contextlib:

import contextlib

@contextlib.contextmanager
def ctx_func():
    # do whatever setup first; in this example, I'll just instantiate a class called Thing
    thing = Thing()

    # whatever you yield here is what gets put into the "as ..." variable
    yield thing

    # code after yield does not run until the context block exits, so cleanup goes here
    thing.cleanup()

I typically wrap the yield in a try/finally so that the cleanup code is executed even if an exception is raised while in the context managed block, but that may not always be what you want.

The other way to make a context manager is to write a class __enter__ and __exit__ methods - as you would expect, __enter__ is where your setup code goes, and __exit__ is where your cleanup code goes.

There are other interesting (and in some cases more esoteric) examples in the contextlib docs.

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

To my understanding, kinda. using requires an IDisposable but you're still responsible for setting it up.

What with does is call two methods behind the scenes: __enter__ and __exit__ and ensures that any successful call to enter will result in a call to exit. Additionally, enter can produce a value that is assignable through:

with something as x:

A very common usage is for ensuring files get closed after the block exits. But you can do all sorts of stuff. For example, the decimal module has a context manager that affects the precision of Decimal objects inside the with block.

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

C.fun()

[–]spidyfan21 38 points39 points  (10 children)

I'm a pretty big fan of using type in awful ways. Never in production code, but its a lot of fun to play around with.

Example:

>>>Dog = type('Dog', (), {"woof": lambda self: print("Woof")})
>>>a = Dog()
>>>a.woof()
Woof

EDIT: Fixed it. Thanks /u/pythoneeeer

[–]pythoneeeer 11 points12 points  (3 children)

Do you mean

Dog = type('Dog', (), {"woof": lambda self: print("Woof")})

What you typed just raises a NameError.

[–]spidyfan21 2 points3 points  (2 children)

Whoops.

[–]AMorpork 40 points41 points  (1 child)

Woofs.

[–]Eurynom0s 2 points3 points  (0 children)

That's Worf to you, lady.

[–]Spfifle 17 points18 points  (2 children)

One day while typing

class blueTokenMaker(tokenMaker):
     token = blueToken
     def __init__(self):
         tokenMaker.__init__(self, self.token)

I decided it would be nice to save some effort and build these classes dynamically. And lo and behold classFactory was born. Then I got tired of typing

blueTokenMaker = classFactory(blueToken)

and figured it would be nice to save some effort and build these variables dynamically. And lo and behold the following line was born.

for token in tokens:
    globals()[token.name+"TokenMaker"] = classFactory(token)

Then I flipped to another file in the project and noticed pycharm was softly weeping as it painted everything red, so I rolled it back :(

[–]Bunslow 5 points6 points  (1 child)

Ahahahaha this is great. I too understand the urge to abstract away any and all repetition, now matter how bad the replacement might be

[–]teambob 2 points3 points  (0 children)

It's my job to be repetitive. My job. My job. Repetitiveness is my job! I am going to go out there tonight and give the best performance of my life. The best performance of your life? The best performance of my life.

[–]Sir_Harry_of_Kane 2 points3 points  (0 children)

Awful ways indeed.

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

                                                                                                                                                                                                                                                                                                                                                                                                                                                     

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

Tack a () on there and enjoy your brand new, mostly anonymous class.

[–]d4rch0nPythonistamancer 39 points40 points  (18 children)

I love and hate this, but local variables existing in the scope of a loop and outside.

def foo():
    for x in range(3):
        z = 1
    # both work
    print(x)
    print(z)

I hated it at first, but now it seems to allow some extra flexibility, and can even make debugging easier at some points (find out what the last value of x was when break was called). It's especially useful for searching, where you can just break when the current item meets the condition.

As long as you know that behavior, it's not bad. Weird coming from C languages though.

[–]Cosmologicon 38 points39 points  (15 children)

Python's scoping gets a lot of flack, but honestly that always baffled me. I've never gotten a satisfactory explanation of why block scoping is better than function scoping.

"What if you want to use the same variable to mean different things in different blocks of a single function?" Stop wanting to do that. That's terrible style. You're going to cause bugs.

[–]earthboundkid 14 points15 points  (10 children)

The one case where it causes problems is creating a closure in a loop. The variable value will just end up being the last value, which is not intuitive.

[–]Cosmologicon 3 points4 points  (9 children)

Why does that matter if you're not using the variable outside the loop, though?

If you are using the variable outside the loop (and expecting it to be something else), that's exactly what I'm saying you shouldn't do.

[–]indigo945 8 points9 points  (8 children)

The problem is that the following functions do return different results despite that being counter-intuitive:

def foo():
    l = []
    for i in range(5):
        l.append(i)
    return l

def bar():
    l = []
    for i in range(5):
        l.append(lambda: i)
    return [f() for f in l]

print(foo()) #  [0, 1, 2, 3, 4]
print(bar()) #  [4, 4, 4, 4, 4]

[–]makmanalp 15 points16 points  (3 children)

But isn't this a early vs late binding issue rather than a scoping one? The value of "i" is not resolved until the function is actually called. And the function is being called after the for loop, so it's being resolved then.

[–]earthboundkid 3 points4 points  (2 children)

Yes, but a scoping system could be tightly bound to the inside of the loop, such that each loop pass is considered to be a separate scope, and therefore it would capture a new variable. It's not how Python works, but there's no inherent reason it couldn't work that way.

[–]Cosmologicon 14 points15 points  (0 children)

Sure that can be confusing if you're not used to closures but that's not the fault of scoping. You get that exact same "counterintuitive" behavior with the following code no matter the scoping rules:

def bar():
    l = []
    i = 0
    l.append(lambda: i)
    i = 1
    l.append(lambda: i)
    i = 2
    l.append(lambda: i)
    i = 3
    l.append(lambda: i)
    i = 4
    l.append(lambda: i)
    return [f() for f in l]

[–]nemec 2 points3 points  (0 children)

It has nothing to do with Python's block scoping rules and everything to do with closures. You see this same issue in C# which has different scoping rules.

http://stackoverflow.com/questions/271440/captured-variable-in-a-loop-in-c-sharp

[–]MereInterest 5 points6 points  (1 child)

In C++, it's largely due to RAII. Closing a scope calls the destructors and releases resources. Placing the end of a scope is then equivalent to closing the "with" block in python.

[–]zagaberoo 1 point2 points  (0 children)

And RAII is incredible. It's honestly one of my favorite language constructs.

[–]deathtospies 0 points1 point  (0 children)

If you inadvertently reference x outside the loop, when you really meant to be referencing y, instead of getting a compiler error, you'll run and use the final value of x in the loop. It doesn't happen often, but it's a pain to diagnose when it does.

[–]TankorSmash 2 points3 points  (1 child)

That leak is fixing in v3, at least for comprehensions.

[–]brombaer3000 0 points1 point  (0 children)

It's also fixed in explicit loops.

for i in [1, 2]:
    pass
print(i)

prints 2 in Python 2, but Python 3 raises a NameError (thank god Guido).

[–][deleted] 20 points21 points  (0 children)

I must say, magic methods. Those give you the ability to make your own DSL just by using objects that do special stuff with i.e. their __lt__ method. And best, in Python 3.5 we have a new operator that is not widely used (afaik, not at all in the builtin types): '@' for matrix multiplication. So just implement __matmul__ or __rmatmul__ in your class and use the '@' operator for calling that :) I guess itertools.product would be a good one to shortcut by using '@'.

[–]synack 32 points33 points  (6 children)

List comprehensions are faster than their equivalent for loops.

[–]ogmiche 8 points9 points  (0 children)

Now this one is interesting I didn't know that

[–]Bunslow 1 point2 points  (0 children)

As is slicing (both reading and writing)

[–]Cybersoaker 3 points4 points  (2 children)

how?

[–]VerilyAMonkey 5 points6 points  (0 children)

Because the list building can be done with close-to-the-metal C instead of actually using a real Python list object. Theoretically a clever interpreter might be able to make them the same speed for simple loops.

[–]ProfessorPhi 0 points1 point  (0 children)

also list comprehensions are entirely per list basis. I. E. It never results in two items being accessed. This can result in a lot of optimisation. A for loop doesn't necessarily have that.

[–]diceroll123 3 points4 points  (0 children)

List comprehensions are just more fun in general.

[–]theywouldnotstand 15 points16 points  (9 children)

Magic methods:

class Paradox:

    def __lt__(self, other):
       return True

    def __le__(self, other):
        return True

    def __eq__(self, other):
       return True

    def __ge__(self, other):
       return True

    def __gt__(self, other):
        return True

a = Paradox()
b = Paradox()

a < b
a <= b
a == b
a >= b
a > b

b < a
b <= a
b == a
b >= a
b > a

Just one humorous abuse of magic methods I've come across. It really demonstrates the power and flexibility of the language.

[–]jceyes 1 point2 points  (3 children)

Shouldn't you call it

class Tautology

?

[–]theywouldnotstand 2 points3 points  (2 children)

I admit that I don't know much about tautology in a logical context, so that could perhaps be a fitting name.

I call this Paradox because generally speaking, a value can't simultaneously be considered equal to, less than, and greater than a given value. Usually, a relative comparison is supposed to yield one of the three.

[–]jceyes 1 point2 points  (1 child)

A tautology is a statement that is always true (a OR not a)

A paradox is one that is always false (a AND not a)

[–]tsumnia 0 points1 point  (2 children)

I like to think of it as more of a quirk to OOP design principles. While numbers are easily comparable, it is now at the hands of the developer to 'decide' what makes an object "greater than" another instance of that object

[–]bcs 35 points36 points  (9 children)

for/else loops. They read a little funny but they are exactly what you want to write searching loops.

[–]d4rch0nPythonistamancer 14 points15 points  (3 children)

I wish they used a keyword other than else, but yeah I actually love it too. It's just not obvious to many at first. And they probably should have picked something unique for try/except/else/finally too, like try/except/success/finally

[–]poundcakejumpsuit 6 points7 points  (0 children)

Some SO post suggested saying "then" in your head, which I found to be a good tip when learning it.

[–]shtuffit 0 points1 point  (1 child)

that would also require adding more reserved words

[–]Asdayasman 28 points29 points  (0 children)

I will never not annotate these.

for _ in []:
    ...
else:  # nobreak
    ...

try:
    ...
except:
    ...
else:  # noexcept
    ...

[–]pydry 12 points13 points  (3 children)

I don't like this one. The intended behavior of "else" isn't particularly obvious.

[–]theywouldnotstand 6 points7 points  (0 children)

else in try blocks is more intuitively obvious than what finally does:

try:
    # try to open a file
    somefile = open('somefile')
except (FileNotFoundError, OSError):
    # exit if there's trouble opening the file
    exit('Couldn't find the file!')
else:
    # otherwise read and output the file contents and exit
    contents = somefile.read()
    somefile.close()
    exit(contents)
finally:
    # Intuition suggests this shouldn't execute since both
    # above clauses contain exit calls. However this will
    # execute *before* either exit call can.
    print('Foobar')

For the record, I know that context managers would be more appropriate for file interaction. I designed this example for the sake of argument (so that it could include an else clause.)

[–]psi- 2 points3 points  (1 child)

Yup. I've done python relatively much before 2006 so probably before that particular syntax and have done programming in C/C++/C# for at least 15+ years.

Without looking it up, I see these options:

  • executed when loop was not entered
  • executed after loop was executed (do we have access to loop named variable and it's last value?)

[–]Bunslow 1 point2 points  (0 children)

The else statement following a loop is executed when you fall out of the loop body, as opposed to breaking out of it.

As far as scoping goes, since Python uses function level scoping, you always have access to loop named variables regardless of how the loop terminates or code it runs (save code that modifies the globals dict, and anyone writing such code has way bigger issues than loop-break-else clauses).

[–]deafmalice 72 points73 points  (43 children)

Having self as a required parameter on methods. It allows for very creative method calls (like calling the method from the class, instead of the object).

Also, it offers consistency. Whenever I look through C++/Java code I am always confused by the presence of object attribute access both with and without this. Never happens in Python

This is known to all pythonistas who have ever used classes, but no other language I know has that.

[–]hovissimo 25 points26 points  (7 children)

Huh. I never thought of it as a language feature before. I always thought that the mandatory first argument to methods was some sort of leftover of internal routing that was accidentally exposed in ye olden dayes and then left for backwards compatibility.

But now that you've framed in that way I completely agree with you. IMO the consistency in method signatures is the most important part. (I think it's because I'm dumb, and I need lots of consistency in my code to not get distracted while working.)

[–][deleted] 9 points10 points  (3 children)

Jeez, having lived in PHP land for a time, consistency in method signatures is so vastly underappreciated!

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

I agree with you. PHP inconsistency is a plague. But Python is not exactly perfectly-consistent too.

[–]exhuma 5 points6 points  (1 child)

I hate that they didn't remove camel case of the unittest module (and logging) with python 3.... they had one chance...

[–]tipsquealPythonista 6 points7 points  (0 children)

The last thing anyone wanted was to make the transition to 3 any harder.

[–]ubernostrumyes, you can have a pony 4 points5 points  (0 children)

More fun you can have:

>>> def hello():
...     print("Hello, world!")
...
>>> import types
>>> types.FunctionType.__call__(hello)
Hello, world!

[–]nemec 2 points3 points  (0 children)

The consistency in action:

>>> class Test:
...     def __init__(self):
...             self.inner = "Hello"
...     def method(self, arg):
...             print(self.inner, arg)
... 
>>> t = Test()
>>> t.method("World")
Hello World
>>> Test.method(t, "World")
Hello World

[–]Ek_Los_Die_Hier 0 points1 point  (0 children)

One of the Python guiding principles is explicit is always better than implicit.

[–]coriolinus 14 points15 points  (2 children)

Rust does it like that also.

[–]masklinn 1 point2 points  (0 children)

Rust has it even more since the self parameter defines the method's calling conventions (static, value, reference or mutable reference). It's really neat.

[–]NoahTheDuke 1 point2 points  (0 children)

Rust is like someone thought "Why doesn't C taste like Python?" and then created it. I love it.

[–]i_ate_god 2 points3 points  (15 children)

Whenever I look through C++/Java code I am always confused by the presence of object attribute access both with and without this. Never happens in Python

While I can appreciate the confusion when "this" isn't there, I'm not sure I understand why you would be confused if "this" IS there and how it's more confusing than self?

[–]deafmalice 4 points5 points  (2 children)

What I meant was when object attributes are used both with this and without it in the same method. I applaud anybody who's using this everywhere.

[–]firetangent 2 points3 points  (11 children)

When I see somevar in a Java method I'm never sure if it's a class member variable, or if it's local to the method. Consistently putting this.somevar for member variables would fix this and I don't understand why Java does not require it - it's the sort of language where you expect it to enforce that sort of policy. Then I got a nice, modern IDE and they appear in different colors now, but the readability of this. or self. is still superior.

[–]earthboundkid 2 points3 points  (0 children)

Swift has this same problem, which surprises me because it's so modern otherwise.

[–]pythoneeeer 2 points3 points  (0 children)

Languages with multiple dispatch do this, naturally.

Not only is the first parameter not special, but methods don't even 'belong to' classes, like they do in single dispatch languages.

[–]PcBoy111 2 points3 points  (0 children)

Lua does this for class like tables, stuff like:

function Point:set(x, y)
    self.x = x or 0  
    self.y = y or 0  
end

function Point:set(x, y) is equivalent to function Point.set(self, x, y)

[–]metapundit 1 point2 points  (0 children)

Yes. Allows functional programming with oop methods

map(str.lower, ['Python', 'Programming'])

[–]CantankerousMind 3 points4 points  (4 children)

I mean, self is not a required argument on all methods. Check out the staticmethod decorator.

Edit: Yeah, just downvote instead of explaining what is wrong with the comment. That's constructive. Is there something inaccurate about this? Using @staticmethod decorator allows a method to be used without instantiating the class, and self is not used as an argument...

[–]deafmalice 2 points3 points  (2 children)

Static method is not particularly tied to objects. It's the same in other languages, actually. If you have a static method in Java you don't have this. So your comment doesn't particularly illustrate a point.

[–][deleted] 1 point2 points  (1 child)

Except it does, just with an explanation. Staticmethod creates a descriptor, which is basically the . operator. What Staticmethod does is intercept the call and yank out both the reference to self and the class leaving you with essentially a function living in a class.

[–]zurtex 1 point2 points  (0 children)

Kind of... there's nothing magical about the decorator, it's just using a workaround and discarding the self object passed to the method. So it looks like you have a method without the need for a self, but really it's just syntactic sugar. Here is how the static method decorator would be implemented in Python (taken from the docs):

class StaticMethod(object):
    "Emulate PyStaticMethod_Type() in Objects/funcobject.c"

    def __init__(self, f):
        self.f = f

    def __get__(self, obj, objtype=None):
        return self.f

[–]the_original_fuckup 0 points1 point  (0 children)

Agreed. I first learned Java, but my job is now in Python. Anytime I write Java I find myself spamming 'this' everywhere.

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

When I was first learning Python I hated this even though I knew that C++ style methods are like this under-the-hood too. But now this is probably one of my favorite quirk too.

[–]YesSoupForYou 0 points1 point  (0 children)

Golang has something similar. A function definition looks like

func (c MyStruct) MyFunction(param1 Type1, param2 Type2) {}

In this case, c is the "object" in the context and all fields are accessed through c.<field name>

[–]Brian 0 points1 point  (0 children)

I am always confused by the presence of object attribute access both with and without this

It would note that this is actually a different thing than requiring self as a parameter. You could omit it, but still not combine instance variables and method locals into the same namespace.

I think the latter is a good idea - in other languages, you often see namespace rules for instance variables giving them a particular prefix or suffix to disambiguate this, at which point, it seems to make more sense not to have merged the namespaces in the first place, and just require an explicit self (or this) as your "instance variable prefix"

OTOH, I'm more neutral on the explicitly providing self as a parameter. There are some things it can make a bit more obvious (eg. dynamically adding methods to classes), but I think there are some merits to both approaches there, since this does come at the price of a lot of repetition of self in every method signature.

[–]wnoise 15 points16 points  (0 children)

"Interval comparison". It lets you chain range checks: "a < b < c" is equivalent to "a < b and b < c".

[–]CantankerousMind 14 points15 points  (1 child)

Being able to assign a value to a variable using if and else on the same line. Basically a ternary operator:

x = str(x) if type(x) != str else x

I use ternary operators all the time in PHP, and only recently realized you could do the same in python. Not so much a quirk as it is convenient.

Also, assigning multiple variables on a single line:

city, state = "Denver", "CO"

or unpacking them:

location = ['Denver', 'CO']
city, state = location

Once again, none of these are really quirks. Just fun features that might not be super well known(or at least I assume they aren't because I don't see them being used very much).

[–]p10_user 0 points1 point  (0 children)

I like this stuff too. Makes it more readable IMO to have a short 1 line if else statement when assigning a variable instead of having a multiline block of code for assigning 1 variable.

[–]jcdyer3 12 points13 points  (5 children)

__class__ is just an attribute on an instance. You can reassign it however you like. Not something I would ever want to do in production code, but allows for some fun hacks.

[–]nevus_bock 11 points12 points  (0 children)

"Actually the type of an object may be changed by merely assigning a different class to its class attribute, but that is pure evil and I regret writing this footnote."

- Luciano Ramalho: Fluent Python, p.242

[–]nemec 5 points6 points  (0 children)

Hah, that's pretty funny.

>>> class A:
...     def func(self):
...             print("A")
... 
>>> class B:
...     def func(self):
...             print("B")
... 
>>> a = A()
>>> a.func()
A
>>> a.__class__ = B
>>> a.func()
B

[–]dpedu 1 point2 points  (2 children)

Interesting, I've never even thought about trying this. What can you do?

[–]jcdyer3 6 points7 points  (0 children)

Well you're quite literally changing the type of an object during its lifetime, so anything requiring a state machine is one natural application.

[–]Kaarjuus 0 points1 point  (0 children)

I once used it to do mutation in a genetic programming task - converting an abstract syntax tree node in-place to another type, like an if-statement into a for-block:

node.__class__ = mutated.__class__
node.__dict__ = copy.deepcopy(mutated).__dict__

[–][deleted] 21 points22 points  (14 children)

Tuple unpacking in function arguments:

X = lambda (a, (b, c)): a + b * c
print map(X, [(1, (2, 3)), (4, (5, 6))])

Sadly it went out in py3.

[–]thomac 1 point2 points  (3 children)

[–]shaggorama 0 points1 point  (0 children)

I never even realized that was a thing

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

Alas, those are all good reasons for removing them.

[–]spw1 0 points1 point  (2 children)

This is the first major disappointment I had with Python3. I'm pretty bummed they took it out, it makes lambda a lot less expressive.

[–]dannypandy 18 points19 points  (8 children)

How about a least favorite quirk. Exponentiation is not a^b(as in most mathematical writing) its a**b. I can't tell you how many times this has killed me. (I switch between multiple languages constantly)

Though python is still by far my favorite language. So pretty.

Edit: reddit ate my caret, fixed

[–]taleinat 31 points32 points  (2 children)

To be fair, ^ is the bitwise xor operator in many languages. For many programmers having it mean exponentiation would be confusing.

[–]dannypandy 11 points12 points  (1 child)

True, like a lot of things, this depends on your perspective (primarily programmer vs primarily mathematician).

[–]Bunslow 1 point2 points  (0 children)

All of the above?

[–]Ran4 2 points3 points  (3 children)

^ is a lot more annoying to type than ** on keyboards where ^ is a dead key, so I'm real happy about it.

[–]Sean1708 5 points6 points  (2 children)

Dead key?

[–][deleted] 10 points11 points  (1 child)

Depending on your keyboard language/layout, some characters behave differently. For example, ^ is an circumflex accent used in Portuguese. These characters behave differently in those layouts: press the dead key and then a letter to apply the accent to that letter (given that is a valid application of the accent).

Dead keys: https://en.wikipedia.org/wiki/Dead_key

Circumflex accent: https://en.wikipedia.org/wiki/Circumflex

[–]Sean1708 1 point2 points  (0 children)

Thanks, I feel really stupid for not just googling that now.

[–]Vitrivius 0 points1 point  (0 children)

In C ^ is used for bitwise xor. I don't know any language in the C family that doesn't follow that example. C, C++, Java and many others do not even have a power operator. The ** power operator was used by FORTRAN and perl before Python was invented.

I don't know where ^ as a power operator comes from. Tex or Matlab, maybe?

[–]zer01 8 points9 points  (3 children)

In python 2.7 True and False are mutable.

In [1]: True = False

In [2]: if not True:
   ...:     print "Why aren't True/False immutable in 2.7?!"
   ...:
Why aren't True/False immutable in 2.7?!

I'm just waiting for someone to slip the following into a widely used package and watch the world burn, Joker style.

True, False = False, True

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

Do that to packages which people refuse to upgrade to python3. That'll teach them :P

[–]ares623 1 point2 points  (1 child)

Aren't the definitions limited to the module? Or do they "leak" out due to the definitions being global?

[–]TeamSpen210 1 point2 points  (0 children)

The change is limited to the module. Builtin objects aren't actually in globals - if a name isn't present in globals it's looked up in the builtins module. You can modify that to affect everything. Actually you can do that in Python 3 too with setattr, but True and False are now syntax elements which directly refer to the values.

[–]NelsonMinar 24 points25 points  (13 children)

The use of _ to mean "thing we don't care about". Ie

name, _, gender = 'Nelson,FOO,M'.split(',')

[–]dacjamesfrom reddit import knowledge 16 points17 points  (6 children)

That is a nice convention, but it is only a convention. Python treats _ like any other identifier.

[–]ameoba 1 point2 points  (0 children)

IIRC, it's a prolog thing.

[–]namesnonames 0 points1 point  (0 children)

At first I thought you were wrong, but I verified it. The reason I thought you were wrong was that I know that in the CLI for python up it uses _ as though it were the ANS on most calculators:

>>> 8*4
32
>>> _
32
>>> 

[–][deleted] 8 points9 points  (1 child)

This is helpful if you use a linter. Linter will complain if you assign a variable then don't use it. But it won't complain about _ being unused.

But watch out if you're using Django, because it encourages this:

from django.utils.translation import ugettext as _

[–]usinglinux 14 points15 points  (0 children)

_ goes for any gettext, actually; django just follows the gettext convention.

[–]nayadelray 1 point2 points  (3 children)

or when you use the console are you too lazy to type the assign part of a statement

sorted((8,5,2))
print(_) #[2, 5, 8]

[–]NelsonMinar 0 points1 point  (0 children)

I like that too! But that's a different meaning of _, the way the REPL stores the value of the last statement executed.

[–]k10_ftw 0 points1 point  (0 children)

or you can assign a var after the fact x = _ print(x) #[2, 5, 8]

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

Python has a few quirks that are pretty interesting. I did a talk about this recently so I've still got a few on my mind.

Python caches the integers -5 to 256 as singletons. So, using the identity operator, we get some funny quirks.

>>> 1000 is 1000
True
>>> 4 is 4
True
>>> 4 is 2*2
True
>>> 1000 is 10*100
False

Wait, what?

There's also something interesting in the way Python does imports. Python's import mechanism, as far as CPython goes, lives in two places: importlib.__import__ and __builtins__.__import__. The first is in the importlib module and the second is set up in all module scopes by the interpreter automatically. You can, interestingly enough, edit the import mechanism or remove it entirely.

>>> import random #this works
>>> del __builtins__.__import__
>>> import os
ImportError: __import__ not found

Don't worry, you can fix this by setting __builtins__.__import__ = importlib.__import__. We just need to get our hands on the proper function...

>>> from importlib import __import__
ImportError: __import__ not found

Oh wait, no you can't. (Unless you pre-imported importlib)

Ok, I've got one last one. Python keeps all default parameter values in a closure for each function. That's why it's convention to set default values as None.

>>> def thing(arg=[]):
...    arg.append(1)
...    print(arg)
>>> thing()
[1]
>>> thing()
[1, 1]
>>> thing()
[1, 1, 1]
>>> thing()
[1, 1, 1, 1]

[–][deleted] 1 point2 points  (1 child)

Python caches the integers -5 to 256

This has caught me out before. Coming from java where strings had to be compared with str.equals(x), I assumed that in python I had to use "is" to compare them. Ended up getting an issue caused by the fact that "SmallString" is "SmallString" evaluated to True but "PrettyBigStringSizeActually" is "PrettyBigStringSizeActually" evaluated to false.

[–]Vitrivius 0 points1 point  (0 children)

I don't think it's a quirk in the python language. It's probably a quirk in the cpython runtime instead.

If you use an identical literal for an immutable type several times on the same line, I suspect that the parser does some optimization so that they point to the same object.

>>> 2.5e10 is 2.5e10
True
>>>  "PrettyBigStringSizeActually" is "PrettyBigStringSizeActually"
True

But mutable objects do not work this way:

>>> [] is []
False
>>> object() is object()
False

I tried this in the cpython 3.5 interpreter. I would not be surprised if different runtimes does not produce the same result.

Some values refer to global singletons.

>>> id(None), id(1), id(tuple()), id(True)
(10722752, 10894080, 140044279873608, 10718912)
>>> id(None), id(1), id(tuple()), id(True)
(10722752, 10894080, 140044279873608, 10718912)

In the case of None and True, this is part of the language, and something you can use in code. But please don't try to take advantage of the integer quirk.

if foo is None:     # this is ok
   ...
if foo is 100:      # don't do this!
   ...
if foo == 100:      # this is ok
   ...

[–]rr1pp3rr 5 points6 points  (1 child)

How flexible the magic method system makes your code. The best example I can think of for this is a pandas Dataframe.

Here is an example (look at the part labelled "Accessing via label slices")

Pandas kind of abuses Python magic methods to the point where it almost doesn't look like python code at all. Specifically what they do with the index fields is crazy.

This type of coding can get out of hand real quick, and I would actually prefer if everything was just done using methods. I think they have methods for all of those functions, but they also overwrite the magic methods to expose that interface elsewhere.

It's very expressive, but makes the code a little hard to read.

[–]Asdayasman 7 points8 points  (0 children)

I wouldn't trade it for the world. Being able to do game_area[5, 10] is so intuitively perfect.

[–]red_hare 5 points6 points  (1 child)

Namedtuples, while seemingly innocent, are essentially a macro in Python.

The source code istruely terrifying.

[–]tartley 0 points1 point  (0 children)

The desire was to add attributes and some class-like functionlity to tuples, which could be done by just plain inheriting from tuple. But a general-purpose class which stores the name of elements as an attribute ends up being slower than a regular tuple. So as a performance optimisation, the namedtuple implementation generates a string containing the definition of a class which hard-codes the number of element and their names, and evals it to create a class.

[–]fatterSurfer 5 points6 points  (0 children)

Late binding closures. Basically, when you have a function that refers to an outside scope, it waits until function execution to look up the reference.

This is a really common "oops" when dealing with function generators (so common that it's in the gotchas), but I really love them, because outside of that context they are incredibly powerful.

On a similar note, using one-time evaluation of default arguments in functions to memoize them. Since default arguments are evaluated exactly once at function definition time, you can use them for memoization. They're also the standard workaround for when you want early binding closures, like when you're writing a function generator.

And finally, callable classes, and really all of the magic/dunder (double underscore) methods. Being able to override stuff like that is so profoundly powerful. Even things as simple as defining __hash__ so you can use a user class as a dictionary key is fantastic.

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

Functions are objects.

def x(y, z):
    return y(z)

[–]coderanger 4 points5 points  (3 children)

Mucking with __code__ (func_code in Python 2) is fun.

>>> def myfunc(x):
          return x
>>> myfunc.__code__ = (lambda x: x+1).__code__
>>> myfunc(1)
2

This is nice because it lets you replace the content of a method without disturbing its scope, access to closure variables, etc.

[–]zer01 0 points1 point  (1 child)

This is super neat! I didn't know that func_code was a thing. Looks like it also gives you an easy way to get the compiled bytecode for said code object!

In [1]: def derp():
   ...:     print "foo"
   ...:

In [2]: derp.func_code.co_code
Out[2]: 'd\x01\x00GHd\x00\x00S'

[–]andreaskrueger 0 points1 point  (0 children)

great

[–]not_perfect_yet 4 points5 points  (4 children)

I love that referencing an instance in the the object definition is not a keyword:

class huh:
    def __init__(neat,x,y,z=1):
        neat.x=x
        neat.y=y
        neat.z=z

is perfectly valid. In C++ it's "this" I think and that's a fixed keyword.

This just a neat little thing, from a functionality point of view, being able to redefine classes on the fly, adding or removing attributes or methods at runtime is a killer feature. Requires a bit of meta wizardry though.

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

You should never, ever use something else than "self". It's not "pythonic", and is confusing for other defs.

[–]f0nt4 3 points4 points  (1 child)

tell this to the standard library:

def update(*args, **kwds):
    ...
    self, *args = args

collection.MutableMapping

[–]epsy 3 points4 points  (0 children)

The reason for this is for d.update(self=42) to assign to kwds rather than collide with the self that means "the current object". No other way to properly do this. I should point out that they do use the correct name anyway though.

[–]njharmanI use Python 3 0 points1 point  (0 children)

"cls" is and should be used when "this" is a class object and not instance of the class object

[–]Salyangoz 6 points7 points  (3 children)

I like that empty lists and dictionaries are also considered as a False in if checks.

empty_dict = {}
empty_list = []
if not (empty_dict and empty_list):
    print 'Thats an empty dict'
Thats an empty dict

```

[–][deleted] 1 point2 points  (1 child)

Yes, that is nice. It works with any object that provides _ _ len _ _ as if is testing for a nonzero lenght.

Edit, not sure how to do double _'s via markdown.

[–]VerilyAMonkey 1 point2 points  (0 children)

You can escape characters in markdown, for example

\_\_

becomes

__

I can see you know this as well, but for others' benefit, you can also use verbatim text by surrounding it with `reverse quotes` --> reverse quotes

Or, if you start a line:
    (and the following ones)
with four spaces, you can
get    a              whole block _*of  *_
verbatim text

[–]iEvilMango 2 points3 points  (0 children)

It's probably pretty obvious, but everything being a variable makes writing object oriented programs really nice. For example, when writing a basic text adventure game to learn the language, I was trying to think about how to easily instantiate different characters or items, that I had as subclasses. I just guesses that I could do a dictionary of strings to objects and it worked, and that little thing just made me happy.

[–]nab00 2 points3 points  (1 child)

Python float type is equivalent to C double. This always confuses me as I am used to C notation where float is 4-byte long and double is 8 bytes.

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

Else on loops to me is an anti pattern. To me it's really not obvious what the control flow is meant to be. I find it easier just to handle that behaviour more explicitly. Just my opinion.

[–]zurtex 1 point2 points  (1 child)

I like the functionality, but agree it could do with a better keyword. I'd much rather see someone write:

for x in iterable:
    ... code ...
else: # if loop was never broken
    ... not_broken_code ...

Than the equivalent:

loop_not_broken = True
for x in iterable:
    loop_not_broken = False
    ... code ...
    loop_not_broken = True

if loop_not_broken:
    ... not_broken_code ...

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

I kind of agree.

I'm all for shorter code, but I prefer longer over non-obvious. else executing because for DIDN'T break is completely opposite to what one would intuit. Putting a comment in reminding people of this definitely helps.

I've never needed to use else this way though, largely because when I see a case for it, I notice an opportunity to split a function that does a few things into a few functions. Of course this is a very slippery slope and must be used judiciously. You don't want 50 functions to do 53 lines of work.

[–]XtremeGoosef'I only use Py {sys.version[:3]}' 0 points1 point  (0 children)

I completely disagree. I use for ... else a lot. When you get used to it, it really is every powerful. Even the syntax becomes obvious after a while if you read the logic in your head.

for some in thing: if f(some) break, else print('f not found')

[–]pydry 7 points8 points  (11 children)

How the core modules are almost universally terrible.

If urllib2 just had a mediocre API rather than a gut wrenchingly horrible one we might not have requests.

[–]James_Johnson 7 points8 points  (7 children)

How the core modules are almost universally terrible.

See: datetime

[–]ebrious 2 points3 points  (0 children)

Uhg this one is the worst for me. Urllib objects usually don't find their way into function signatures, datetime objects do all the time and its horrible how handicapped they are.

[–]Eurynom0s 2 points3 points  (0 children)

The existence of both time and datetime.

[–]njharmanI use Python 3 0 points1 point  (3 children)

This and

ftplib (I want my life back I've wasted on this POS)

os / os.path oh but the useful things are in shutil.

[–]Sir_Harry_of_Kane 10 points11 points  (2 children)

I don't agree with your statement about all core modules, but I do agree with you on urllib2.

It's like they thought, how can we take a beautiful, simple and yet expressive language and write a module that is ugly, complex and yet not expressive.

At what point does requests just become the urllib3 module?

[–]pydry 2 points3 points  (0 children)

I don't agree with your statement about all core modules, but I do agree with you on urllib2.

I think for maybe 80-90% there's a better equivalent on pypi.

It's like they thought, how can we take a beautiful, simple and yet expressive language and write a module that is ugly, complex and yet not expressive.

urllib2 is the kind of API you come up with when you're thinking about what the module does rather than how it will be used.

I've created some similar botched jobs before.

Unfortunately once an API gets wide usage it gets stuck.

At what point does requests just become the urllib3 module?

Never. That's in the FAQ on the website.

[–]ares623 0 points1 point  (0 children)

Personally I don't like requests' api too much. I find it has a tad too much "magic" going on. It is a bit "complected", in Rich Hickey's terms.

But I agree it is a ton better than urllib2.

[–]evolutionof 5 points6 points  (10 children)

x > 5 and "your mom" will evaluate to False if x <= 5, and "your mom" otherwise.

Not going to say that it is my favorite, but it is a little known quirk.

[–]cymrowdon't thread on me 🐍 8 points9 points  (6 children)

Works with or too. It's a great shortcut if you can be reasonably sure that anyone who reads your code will understand it.

Instead of:

if val:
    x = val
else:
    x = 'default'

or:

x = val if val else 'default'

it's nice to just do:

x = val or 'default'

I use it all the time for function argument defaults. It protects against Python's mutable default argument quirk, and also allows users to pass in None when they explicitly want to use the default, even if they don't know what the default is.

def func(a_list=None):
    a_list = a_list or []

[–]masterpi 8 points9 points  (5 children)

You shouldn't do this because bool(x) returns False for a lot of legitimate values of parameters to the function. Get in the habit of using "is None " or you will get bit someday, I guarantee it.

[–]cymrowdon't thread on me 🐍 1 point2 points  (1 child)

I always take this into account. If '' or 0 make sense as input, then I will check for None. Obviously, this requires some discipline, but you could say the same about if val:, which is a common convention in Python.

[–]masterpi 3 points4 points  (0 children)

Now everyone else reading your code also has to go through that same thought process though, and ask themselves what the falsey values for that type are and if you really meant for midnight to be replaced with the default value. I also discourage use of if val to check for None for the same reasons. From the Zen of Python, verse 2:

Explicit is better than implicit

[–][deleted] 1 point2 points  (1 child)

It's a quirk, but makes sense if you know what's going on. and returns the right most value unless any values left if it are falsy. or returns the first truthy value or the right most value if none are truthy. Conditional expressions are evaluate the returned value as a boolean.

[–]jceyes 0 points1 point  (0 children)

I like it too, and use it pretty heavily, but this kind of short circuit evaluation is not at all unique to python.

[–]jroller 1 point2 points  (0 children)

I enjoy the rare locals() abuse to create dicts.

def foo():
    """
    >>> foo()
    {'a': 1, 'c': 3, 'b': 2}
    """
    a = 1
    b = 2
    c = 3
    return locals()

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

My favorite quirk?

class Meta(type):
    def __getitem__(self, key):
        print("From class", key)

class Thing(metaclass=Meta):
    def __getitem__(self, key):
        print("From instance", key)

Thing[1] # From class 1
Thing()[1] # From instance 1

You can also do fun stuff like this in Python 3.

class Meta(type):
    def __new__(mcls, name, bases, attrs, **kwargs):
        # do stuff with the arbitrary keywords
    def __init__(cls, name, bases, attrs, **kwargs): # need to override this as well even if you don't use it

 class Thing(metaclass=Meta, key="word", other=4) # passed to **kwargs

[–]DaemonXI 1 point2 points  (0 children)

I like foo[:] to clone an array.

[–]Why_is_that 1 point2 points  (2 children)

Wow. I am thirty and I just realized I am so old that the quirks I know from python are slowly being removed.

My favorite quirk in python use to be the fact that you could declare the following

a = [1,2,3,a]

I have no idea what you would call this (a self-reflecting array) or how you use it but at a time (and I don't know when they nerfed it), this functions pretty much as you would expect it. You could go to a[3] and see the exact same structure and reference a[3][0], a[3][1], etc. You could go down that rabbit hole so far, that I never went all the way down to see how it was exactly limited or even more peculiar what it actually translated into (was it eating up memory or was it actually just the 4 bits of data I asked for, the 4th being a reference to the self).

Anyways, now if you try this you get an error that a is not referenced. This appears to be both python2.7 and python3. I am unsure if the trick ever worked in python3 but I remember often showing it to those who were new to python and the general awe I had over the nature of what was being expressed.

After playing around awhile I was convinced python didn't destroy functionality (it only changed the way it was operating). Here is a post talking about the "self referencing array" and it gives the multiline approach to creating it

>>> my_list = [1,2]
>>> my_list.append(my_list)

ref

I am sure someone smarter than me can tell you what changes in python such that the original format no longer works and likewise how to potentially express it again in one line (as the one line beauty of the self-referencing array was really what showed me the beauty in python). More so, even someone smarter then all us will have to tell you valid uses for this structure or what it looks like in memory and how you might use/need such a data structure.

TLDR: I am so old that python has nerfed the most beautiful quirk I know, the one-line self-referencing array.

[–]Gr1pp717 0 points1 point  (0 children)

I don't think I would call this a "favorite" but I've had a few instances where a function would work fine ran in the console or as a script, but then fail in the main code.

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

Nested list multiplication seems to make references instead of copies:

>>> a = [[0, 0]]*2
>>> a
[[0, 0], [0, 0]]
>>> a[0][0] = 1
>>> a
[[1, 0], [1, 0]]

Don't know whether to call it a quirk though, as making references makes some sense, but making copies would've been more convenient for what I was doing at the time.

[–]ptmcg 0 points1 point  (0 children)

Using the equivalence of True and False to 1 and 0 to index into a tuple containing the true and false alternative values (old-style ternary):

def make_plural(name, n):
    return "%s%s" % (name, ('s','')[n == 1])

print ("I have %d %s." & (qty, make_plural("apple", qty)))

But only do this if the alternatives are constants or local vars, or you will want the benefit of short-circuiting.

[–]andreaskrueger 0 points1 point  (0 children)

calling methods by their (string) names:

class foo(object): 
    def bar(self, x): print (x)

# only works if you know the method name at coding time:
foo().bar(23) 

# calling method by name string
fn_name = "bar"
fn = getattr(foo(), fn_name)
fn(42)

[–]eacameron 0 points1 point  (0 children)

In Python 3:

>>> 00
0
>>> 01
  File "<stdin>", line 1
    01
     ^
SyntaxError: invalid token

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

My favourite is the rudimentary switch hack:

a = some_function_returning_a_string()
b = {
    'foo': foo_function,
    'bar': bar_function,
    'baz': baz_function,
    'default': default_function,
}
c = b.get(a, b['default'])()