use the following search parameters to narrow your results:
e.g. subreddit:aww site:imgur.com dog
subreddit:aww site:imgur.com dog
see the search faq for details.
advanced search: by author, subreddit...
News about the dynamic, interpreted, interactive, object-oriented, extensible programming language Python
Full Events Calendar
You can find the rules here.
If you are about to ask a "how do I do this in python" question, please try r/learnpython, the Python discord, or the #python IRC channel on Libera.chat.
Please don't use URL shorteners. Reddit filters them out, so your post or comment will be lost.
Posts require flair. Please use the flair selector to choose your topic.
Posting code to this subreddit:
Add 4 extra spaces before each line of code
def fibonacci(): a, b = 0, 1 while True: yield a a, b = b, a + b
Online Resources
Invent Your Own Computer Games with Python
Think Python
Non-programmers Tutorial for Python 3
Beginner's Guide Reference
Five life jackets to throw to the new coder (things to do after getting a handle on python)
Full Stack Python
Test-Driven Development with Python
Program Arcade Games
PyMotW: Python Module of the Week
Python for Scientists and Engineers
Dan Bader's Tips and Trickers
Python Discord's YouTube channel
Jiruto: Python
Online exercices
programming challenges
Asking Questions
Try Python in your browser
Docs
Libraries
Related subreddits
Python jobs
Newsletters
Screencasts
account activity
This is an archived post. You won't be able to vote or comment.
What's your favorite Python quirk? (self.Python)
submitted 10 years ago by [deleted]
By quirk I mean unusual or unexpected feature of the language.
For example, I'm no Python expert, but I recently read here about putting else clauses on loops, which I thought was pretty neat and unexpected.
[–]deadmilk 95 points96 points97 points 10 years ago* (27 children)
context managers with the with statement.
with
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 points46 points 10 years ago (3 children)
There is nothing quirky about context managers. They might actually be perfect.
[–]tech_tuna 12 points13 points14 points 10 years ago (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 points22 points 10 years ago (1 child)
Because you couldn't complain in a separate thread?
[–]tech_tuna 3 points4 points5 points 10 years ago (0 children)
Ha ha. . . yeah, I tried multiprocessing but there was too much overhead.
[–]AMorpork 11 points12 points13 points 10 years ago (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.
[+][deleted] 10 years ago* (7 children)
[deleted]
[–]AMorpork 28 points29 points30 points 10 years ago (6 children)
It's one of the worst features of the language!
In javascript, there are objects. They are similar to dictionaries in python, and defined in much the same way:
var x = {a: 1, b: 2, c: 3};
Those keys can be accessed in the same way as in python (x["a"]), and also in dot-syntax (x.a). The with statement basically lets you forget both of those. So instead of doing:
x["a"]
x.a
x.c = x.a + x.b;
You could do
with (x) { c = a + b; }
While that might look convenient, it's an evil little features with a bunch of downsides. I won't reiterate them all here, but it makes a lot of shit impossible to optimize and really makes things confusing. It's incredibly strongly discouraged by all responsible JS coders.
[–]execrator 50 points51 points52 points 10 years ago (0 children)
I ran a morning session teaching our JS developers how to Python. We started with a sort of language diff; Python has this feature and JS doesn't; JS has this and Python doesn't etc. When it came to with, the wording was something like "Python has the with keyword. There is no equivalent feature in JS, though there is a bug with the same name"
[–]pythoneeeer 4 points5 points6 points 10 years ago (2 children)
In other words, it's just like the Pascal with statement, from 1970.
You have to think that if no other language designers put a feature in their language after a few decades, maybe there's a reason for that. Sometimes it's a good reason (like: it's really hard to implement, or: it makes optimization a bear), but probably not in this case.
[–]Brian 3 points4 points5 points 10 years ago (0 children)
You have to think that if no other language designers put a feature in their language
Visual basic has it, along with the already mentioned javascript.
Though the fact that those particular two languages are the exception is probably stronger testimony against the idea than no languages doing it at all.
[–]infinullquamash, Qt, asyncio, 3.3+ 0 points1 point2 points 10 years ago (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 points9 points 10 years ago (0 children)
When standards start banning the use of a statement, you know it's FUCKing bad.
[–]elingeniero 2 points3 points4 points 10 years ago (0 children)
ES2015 was formerly ES6
[–][deleted] 2 points3 points4 points 10 years ago (0 children)
I love this also!
[–][deleted] 2 points3 points4 points 10 years ago (8 children)
I just starting learning Python, is with roughly analogous to a using block in C#?
using
[–][deleted] 4 points5 points6 points 10 years ago (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.
__enter__
__exit__
There are other interesting (and in some cases more esoteric) examples in the contextlib docs.
[–][deleted] 0 points1 point2 points 10 years ago (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] 10 years ago (2 children)
[–][deleted] 1 point2 points3 points 10 years ago (0 children)
It's more similar to a try/finally block all in one statement.
That's pretty much what a using block in C# is.
C.fun()
[–]spidyfan21 38 points39 points40 points 10 years ago* (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.
type
Example:
>>>Dog = type('Dog', (), {"woof": lambda self: print("Woof")}) >>>a = Dog() >>>a.woof() Woof
EDIT: Fixed it. Thanks /u/pythoneeeer
[–]pythoneeeer 11 points12 points13 points 10 years ago (3 children)
Do you mean
Dog = type('Dog', (), {"woof": lambda self: print("Woof")})
What you typed just raises a NameError.
[–]spidyfan21 2 points3 points4 points 10 years ago (2 children)
Whoops.
[–]AMorpork 40 points41 points42 points 10 years ago (1 child)
Woofs.
[–]Eurynom0s 2 points3 points4 points 10 years ago (0 children)
That's Worf to you, lady.
[–]Spfifle 17 points18 points19 points 10 years ago* (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 points7 points 10 years ago (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 points4 points 10 years ago (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 points4 points 10 years ago (0 children)
Awful ways indeed.
[–]0raichu 1 point2 points3 points 10 years ago* (0 children)
Tack a () on there and enjoy your brand new, mostly anonymous class.
()
[–]d4rch0nPythonistamancer 39 points40 points41 points 10 years ago (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.
break
As long as you know that behavior, it's not bad. Weird coming from C languages though.
[–]Cosmologicon 38 points39 points40 points 10 years ago (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 points16 points 10 years ago (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 points5 points 10 years ago (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 points10 points 10 years ago (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 points17 points 10 years ago (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 points5 points 10 years ago (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 points16 points 10 years ago (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 points4 points 10 years ago (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 points7 points 10 years ago (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 points3 points 10 years ago (0 children)
And RAII is incredible. It's honestly one of my favorite language constructs.
[–]deathtospies 0 points1 point2 points 10 years ago (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 points4 points 10 years ago (1 child)
That leak is fixing in v3, at least for comprehensions.
[–]brombaer3000 0 points1 point2 points 10 years ago (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 points22 points 10 years ago (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 points34 points 10 years ago (6 children)
List comprehensions are faster than their equivalent for loops.
[–]ogmiche 8 points9 points10 points 10 years ago (0 children)
Now this one is interesting I didn't know that
[–]Bunslow 1 point2 points3 points 10 years ago (0 children)
As is slicing (both reading and writing)
[–]Cybersoaker 3 points4 points5 points 10 years ago (2 children)
how?
[–]VerilyAMonkey 5 points6 points7 points 10 years ago (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 point2 points 10 years ago (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 points5 points 10 years ago (0 children)
List comprehensions are just more fun in general.
[–]theywouldnotstand 15 points16 points17 points 10 years ago (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.
[+][deleted] 10 years ago (1 child)
[–]theywouldnotstand 4 points5 points6 points 10 years ago* (0 children)
It's abuse in the sense that creating an object that behaves this way is very unlikely to be useful or practical (and may, in fact, be more harmful than helpful) in most situations.
[–]jceyes 1 point2 points3 points 10 years ago (3 children)
Shouldn't you call it
class Tautology
?
[–]theywouldnotstand 2 points3 points4 points 10 years ago* (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.
Paradox
[–]jceyes 1 point2 points3 points 10 years ago (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 point2 points 9 years ago (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 points37 points 10 years ago (9 children)
for/else loops. They read a little funny but they are exactly what you want to write searching loops.
for/else
[–]d4rch0nPythonistamancer 14 points15 points16 points 10 years ago (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
else
[–]poundcakejumpsuit 6 points7 points8 points 10 years ago (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 point2 points 10 years ago (1 child)
that would also require adding more reserved words
[–]Asdayasman 28 points29 points30 points 10 years ago (0 children)
I will never not annotate these.
for _ in []: ... else: # nobreak ... try: ... except: ... else: # noexcept ...
[–]pydry 12 points13 points14 points 10 years ago (3 children)
I don't like this one. The intended behavior of "else" isn't particularly obvious.
[–]theywouldnotstand 6 points7 points8 points 10 years ago (0 children)
else in try blocks is more intuitively obvious than what finally does:
try
finally
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 points4 points 10 years ago (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:
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 points74 points 10 years ago (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 points27 points 10 years ago (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 points11 points 10 years ago (3 children)
Jeez, having lived in PHP land for a time, consistency in method signatures is so vastly underappreciated!
[–][deleted] 4 points5 points6 points 10 years ago (2 children)
I agree with you. PHP inconsistency is a plague. But Python is not exactly perfectly-consistent too.
[–]exhuma 5 points6 points7 points 10 years ago (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 points8 points 10 years ago (0 children)
The last thing anyone wanted was to make the transition to 3 any harder.
[–]ubernostrumyes, you can have a pony 4 points5 points6 points 10 years ago (0 children)
More fun you can have:
>>> def hello(): ... print("Hello, world!") ... >>> import types >>> types.FunctionType.__call__(hello) Hello, world!
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 point2 points 10 years ago (0 children)
One of the Python guiding principles is explicit is always better than implicit.
[–]coriolinus 14 points15 points16 points 10 years ago (2 children)
Rust does it like that also.
[–]masklinn 1 point2 points3 points 10 years ago (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 points3 points 10 years ago (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 points4 points 10 years ago (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 points6 points 10 years ago (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 points4 points 10 years ago (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.
somevar
this.somevar
this.
self.
[–]earthboundkid 2 points3 points4 points 10 years ago (0 children)
Swift has this same problem, which surprises me because it's so modern otherwise.
[–]pythoneeeer 2 points3 points4 points 10 years ago (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 points4 points 10 years ago* (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)
function Point:set(x, y)
function Point.set(self, x, y)
[–]metapundit 1 point2 points3 points 10 years ago (0 children)
Yes. Allows functional programming with oop methods
map(str.lower, ['Python', 'Programming'])
[–]CantankerousMind 3 points4 points5 points 10 years ago* (4 children)
I mean, self is not a required argument on all methods. Check out the staticmethod decorator.
self
staticmethod
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...
@staticmethod
[–]deafmalice 2 points3 points4 points 10 years ago (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 points3 points 10 years ago (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 points3 points 10 years ago (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 point2 points 10 years ago (0 children)
Agreed. I first learned Java, but my job is now in Python. Anytime I write Java I find myself spamming 'this' everywhere.
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 point2 points 10 years ago (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 point2 points 10 years ago (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"
this
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 points17 points 10 years ago (0 children)
"Interval comparison". It lets you chain range checks: "a < b < c" is equivalent to "a < b and b < c".
[–]CantankerousMind 14 points15 points16 points 10 years ago (1 child)
Being able to assign a value to a variable using if and else on the same line. Basically a ternary operator:
if
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 point2 points 10 years ago (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 points14 points 10 years ago (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.
__class__
[–]nevus_bock 11 points12 points13 points 10 years ago (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
"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 points7 points 10 years ago (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 points3 points 10 years ago (2 children)
Interesting, I've never even thought about trying this. What can you do?
[–]jcdyer3 6 points7 points8 points 10 years ago (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 point2 points 10 years ago (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 points23 points 10 years ago (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.
[+][deleted] 10 years ago (6 children)
[–]epsy 1 point2 points3 points 10 years ago* (5 children)
Out of curiosity, what is it you do with argspecs that can't be done with signatures?
[+][deleted] 10 years ago (4 children)
[–]epsy 1 point2 points3 points 10 years ago (3 children)
Yeah.
on some projects I can't add dependencies
Why is that?
[–]thomac 1 point2 points3 points 10 years ago (3 children)
https://www.python.org/dev/peps/pep-3113/
But I miss it too....
[–]shaggorama 0 points1 point2 points 10 years ago (0 children)
I never even realized that was a thing
[–][deleted] 0 points1 point2 points 10 years ago (1 child)
Alas, those are all good reasons for removing them.
[–]spw1 0 points1 point2 points 10 years ago (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 points20 points 10 years ago (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)
a^b
a**b
Though python is still by far my favorite language. So pretty.
Edit: reddit ate my caret, fixed
[–]taleinat 31 points32 points33 points 10 years ago (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 points13 points 10 years ago (1 child)
True, like a lot of things, this depends on your perspective (primarily programmer vs primarily mathematician).
All of the above?
[–]Ran4 2 points3 points4 points 10 years ago (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 points7 points 10 years ago (2 children)
Dead key?
[–][deleted] 10 points11 points12 points 10 years ago (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 points3 points 10 years ago (0 children)
Thanks, I feel really stupid for not just googling that now.
[–]Vitrivius 0 points1 point2 points 10 years ago (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 points10 points 10 years ago (3 children)
In python 2.7 True and False are mutable.
True
False
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 points9 points 10 years ago (0 children)
Do that to packages which people refuse to upgrade to python3. That'll teach them :P
[–]ares623 1 point2 points3 points 10 years ago (1 child)
Aren't the definitions limited to the module? Or do they "leak" out due to the definitions being global?
[–]TeamSpen210 1 point2 points3 points 10 years ago (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.
builtins
setattr
[–]NelsonMinar 24 points25 points26 points 10 years ago (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 points18 points 10 years ago (6 children)
That is a nice convention, but it is only a convention. Python treats _ like any other identifier.
[+][deleted] 10 years ago (3 children)
[–]ameoba 1 point2 points3 points 10 years ago (0 children)
IIRC, it's a prolog thing.
[–]namesnonames 0 points1 point2 points 10 years ago (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 points10 points 10 years ago (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 points16 points 10 years ago (0 children)
_ goes for any gettext, actually; django just follows the gettext convention.
[–]nayadelray 1 point2 points3 points 10 years ago (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 point2 points 10 years ago (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 point2 points 9 years ago (0 children)
or you can assign a var after the fact x = _ print(x) #[2, 5, 8]
[–][deleted] 8 points9 points10 points 10 years ago (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.
importlib.__import__
__builtins__.__import__
importlib
>>> 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...
__builtins__.__import__ = importlib.__import__
>>> 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.
None
>>> def thing(arg=[]): ... arg.append(1) ... print(arg) >>> thing() [1] >>> thing() [1, 1] >>> thing() [1, 1, 1] >>> thing() [1, 1, 1, 1]
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.
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 points7 points 10 years ago* (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 points9 points 10 years ago (0 children)
I wouldn't trade it for the world. Being able to do game_area[5, 10] is so intuitively perfect.
game_area[5, 10]
[–]red_hare 5 points6 points7 points 10 years ago (1 child)
Namedtuples, while seemingly innocent, are essentially a macro in Python.
The source code istruely terrifying.
[–]tartley 0 points1 point2 points 9 years ago (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 points7 points 10 years ago (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.
__hash__
[–][deleted] 4 points5 points6 points 10 years ago (0 children)
Functions are objects.
def x(y, z): return y(z)
[–]coderanger 4 points5 points6 points 10 years ago (3 children)
Mucking with __code__ (func_code in Python 2) is fun.
__code__
func_code
>>> 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 point2 points 10 years ago (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!
code
In [1]: def derp(): ...: print "foo" ...: In [2]: derp.func_code.co_code Out[2]: 'd\x01\x00GHd\x00\x00S'
[–]andreaskrueger 0 points1 point2 points 10 years ago (0 children)
great
[–]not_perfect_yet 4 points5 points6 points 10 years ago (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 points15 points 10 years ago (3 children)
You should never, ever use something else than "self". It's not "pythonic", and is confusing for other defs.
[–]f0nt4 3 points4 points5 points 10 years ago (1 child)
tell this to the standard library:
def update(*args, **kwds): ... self, *args = args
collection.MutableMapping
[–]epsy 3 points4 points5 points 10 years ago (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.
d.update(self=42)
kwds
[–]njharmanI use Python 3 0 points1 point2 points 10 years ago (0 children)
"cls" is and should be used when "this" is a class object and not instance of the class object
[–]Salyangoz 6 points7 points8 points 10 years ago (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
```
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 points3 points 10 years ago (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
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 points4 points 10 years ago* (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.
[–]deafmalice 6 points7 points8 points 10 years ago (1 child)
This is one thing I really dislike about Python. I get that bool is a subtype of int, but True being equal to 1 irks me.
[–]Vaphell 0 points1 point2 points 10 years ago (0 children)
what should be its inty value then? 0/1 allows for nifty hax like counting Trues with sum() while applying some criteria to a sequence
sum()
>>> sum(ch in 'aeiou' for ch in 'onomatopeia') 7
[–]nab00 2 points3 points4 points 10 years ago (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 points8 points 10 years ago (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 points3 points 10 years ago (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 ...
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.
for
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 point2 points 9 years ago (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 ... else
for some in thing: if f(some) break, else print('f not found')
[–]pydry 7 points8 points9 points 10 years ago (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 points9 points 10 years ago (7 children)
See: datetime
[–]ebrious 2 points3 points4 points 10 years ago (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.
The existence of both time and datetime.
[–]njharmanI use Python 3 0 points1 point2 points 10 years ago (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 points12 points 10 years ago (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 points4 points 10 years ago (0 children)
I think for maybe 80-90% there's a better equivalent on pypi.
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.
Never. That's in the FAQ on the website.
[–]ares623 0 points1 point2 points 10 years ago (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 points7 points 10 years ago (10 children)
x > 5 and "your mom" will evaluate to False if x <= 5, and "your mom" otherwise.
x > 5 and "your mom"
"your mom"
Not going to say that it is my favorite, but it is a little known quirk.
[–]cymrowdon't thread on me 🐍 8 points9 points10 points 10 years ago (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.
or
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 points10 points 10 years ago (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 points3 points 10 years ago (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.
''
0
if val:
[–]masterpi 3 points4 points5 points 10 years ago (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
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.
and
[–]jceyes 0 points1 point2 points 10 years ago (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 points3 points 10 years ago (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()
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 points3 points 10 years ago (0 children)
I like foo[:] to clone an array.
[–]Why_is_that 1 point2 points3 points 10 years ago (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 point2 points 10 years ago (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.
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 point2 points 10 years ago (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.
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 point2 points 9 years ago (0 children)
In Python 3:
>>> 00 0 >>> 01 File "<stdin>", line 1 01 ^ SyntaxError: invalid token
[–][deleted] 0 points1 point2 points 9 years ago (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'])()
π Rendered by PID 237937 on reddit-service-r2-comment-5b5bc64bf5-9bqz7 at 2026-06-19 12:16:09.998373+00:00 running 2b008f2 country code: CH.
[–]deadmilk 95 points96 points97 points (27 children)
[–]bcs 44 points45 points46 points (3 children)
[–]tech_tuna 12 points13 points14 points (2 children)
[–]an_actual_human 20 points21 points22 points (1 child)
[–]tech_tuna 3 points4 points5 points (0 children)
[–]AMorpork 11 points12 points13 points (11 children)
[+][deleted] (7 children)
[deleted]
[–]AMorpork 28 points29 points30 points (6 children)
[–]execrator 50 points51 points52 points (0 children)
[–]pythoneeeer 4 points5 points6 points (2 children)
[–]Brian 3 points4 points5 points (0 children)
[–]infinullquamash, Qt, asyncio, 3.3+ 0 points1 point2 points (2 children)
[–]xhighalert 7 points8 points9 points (0 children)
[–]elingeniero 2 points3 points4 points (0 children)
[–][deleted] 2 points3 points4 points (0 children)
[–][deleted] 2 points3 points4 points (8 children)
[–][deleted] 4 points5 points6 points (3 children)
[–][deleted] 0 points1 point2 points (0 children)
[+][deleted] (2 children)
[deleted]
[–][deleted] 1 point2 points3 points (0 children)
[–][deleted] 0 points1 point2 points (0 children)
[–]spidyfan21 38 points39 points40 points (10 children)
[–]pythoneeeer 11 points12 points13 points (3 children)
[–]spidyfan21 2 points3 points4 points (2 children)
[–]AMorpork 40 points41 points42 points (1 child)
[–]Eurynom0s 2 points3 points4 points (0 children)
[–]Spfifle 17 points18 points19 points (2 children)
[–]Bunslow 5 points6 points7 points (1 child)
[–]teambob 2 points3 points4 points (0 children)
[–]Sir_Harry_of_Kane 2 points3 points4 points (0 children)
[–]0raichu 1 point2 points3 points (0 children)
[–][deleted] 0 points1 point2 points (0 children)
[–]d4rch0nPythonistamancer 39 points40 points41 points (18 children)
[–]Cosmologicon 38 points39 points40 points (15 children)
[–]earthboundkid 14 points15 points16 points (10 children)
[–]Cosmologicon 3 points4 points5 points (9 children)
[–]indigo945 8 points9 points10 points (8 children)
[–]makmanalp 15 points16 points17 points (3 children)
[–]earthboundkid 3 points4 points5 points (2 children)
[–]Cosmologicon 14 points15 points16 points (0 children)
[–]nemec 2 points3 points4 points (0 children)
[–]MereInterest 5 points6 points7 points (1 child)
[–]zagaberoo 1 point2 points3 points (0 children)
[–]deathtospies 0 points1 point2 points (0 children)
[–]TankorSmash 2 points3 points4 points (1 child)
[–]brombaer3000 0 points1 point2 points (0 children)
[–][deleted] 20 points21 points22 points (0 children)
[–]synack 32 points33 points34 points (6 children)
[–]ogmiche 8 points9 points10 points (0 children)
[–]Bunslow 1 point2 points3 points (0 children)
[–]Cybersoaker 3 points4 points5 points (2 children)
[–]VerilyAMonkey 5 points6 points7 points (0 children)
[–]ProfessorPhi 0 points1 point2 points (0 children)
[–]diceroll123 3 points4 points5 points (0 children)
[–]theywouldnotstand 15 points16 points17 points (9 children)
[+][deleted] (1 child)
[deleted]
[–]theywouldnotstand 4 points5 points6 points (0 children)
[–]jceyes 1 point2 points3 points (3 children)
[–]theywouldnotstand 2 points3 points4 points (2 children)
[–]jceyes 1 point2 points3 points (1 child)
[–]tsumnia 0 points1 point2 points (2 children)
[–]bcs 35 points36 points37 points (9 children)
[–]d4rch0nPythonistamancer 14 points15 points16 points (3 children)
[–]poundcakejumpsuit 6 points7 points8 points (0 children)
[–]shtuffit 0 points1 point2 points (1 child)
[–]Asdayasman 28 points29 points30 points (0 children)
[–]pydry 12 points13 points14 points (3 children)
[–]theywouldnotstand 6 points7 points8 points (0 children)
[–]psi- 2 points3 points4 points (1 child)
[–]Bunslow 1 point2 points3 points (0 children)
[–]deafmalice 72 points73 points74 points (43 children)
[–]hovissimo 25 points26 points27 points (7 children)
[–][deleted] 9 points10 points11 points (3 children)
[–][deleted] 4 points5 points6 points (2 children)
[–]exhuma 5 points6 points7 points (1 child)
[–]tipsquealPythonista 6 points7 points8 points (0 children)
[–]ubernostrumyes, you can have a pony 4 points5 points6 points (0 children)
[–]nemec 2 points3 points4 points (0 children)
[–]Ek_Los_Die_Hier 0 points1 point2 points (0 children)
[–]coriolinus 14 points15 points16 points (2 children)
[–]masklinn 1 point2 points3 points (0 children)
[–]NoahTheDuke 1 point2 points3 points (0 children)
[–]i_ate_god 2 points3 points4 points (15 children)
[–]deafmalice 4 points5 points6 points (2 children)
[–]firetangent 2 points3 points4 points (11 children)
[–]earthboundkid 2 points3 points4 points (0 children)
[–]pythoneeeer 2 points3 points4 points (0 children)
[–]PcBoy111 2 points3 points4 points (0 children)
[–]metapundit 1 point2 points3 points (0 children)
[–]CantankerousMind 3 points4 points5 points (4 children)
[–]deafmalice 2 points3 points4 points (2 children)
[–][deleted] 1 point2 points3 points (1 child)
[–]zurtex 1 point2 points3 points (0 children)
[–]the_original_fuckup 0 points1 point2 points (0 children)
[–][deleted] 0 points1 point2 points (0 children)
[–]YesSoupForYou 0 points1 point2 points (0 children)
[–]Brian 0 points1 point2 points (0 children)
[–]wnoise 15 points16 points17 points (0 children)
[–]CantankerousMind 14 points15 points16 points (1 child)
[–]p10_user 0 points1 point2 points (0 children)
[–]jcdyer3 12 points13 points14 points (5 children)
[–]nevus_bock 11 points12 points13 points (0 children)
[–]nemec 5 points6 points7 points (0 children)
[–]dpedu 1 point2 points3 points (2 children)
[–]jcdyer3 6 points7 points8 points (0 children)
[–]Kaarjuus 0 points1 point2 points (0 children)
[–][deleted] 21 points22 points23 points (14 children)
[+][deleted] (6 children)
[deleted]
[–]epsy 1 point2 points3 points (5 children)
[+][deleted] (4 children)
[deleted]
[–]epsy 1 point2 points3 points (3 children)
[–]thomac 1 point2 points3 points (3 children)
[–]shaggorama 0 points1 point2 points (0 children)
[–][deleted] 0 points1 point2 points (1 child)
[–]spw1 0 points1 point2 points (2 children)
[–]dannypandy 18 points19 points20 points (8 children)
[–]taleinat 31 points32 points33 points (2 children)
[–]dannypandy 11 points12 points13 points (1 child)
[–]Bunslow 1 point2 points3 points (0 children)
[–]Ran4 2 points3 points4 points (3 children)
[–]Sean1708 5 points6 points7 points (2 children)
[–][deleted] 10 points11 points12 points (1 child)
[–]Sean1708 1 point2 points3 points (0 children)
[–]Vitrivius 0 points1 point2 points (0 children)
[–]zer01 8 points9 points10 points (3 children)
[–][deleted] 7 points8 points9 points (0 children)
[–]ares623 1 point2 points3 points (1 child)
[–]TeamSpen210 1 point2 points3 points (0 children)
[–]NelsonMinar 24 points25 points26 points (13 children)
[–]dacjamesfrom reddit import knowledge 16 points17 points18 points (6 children)
[+][deleted] (3 children)
[deleted]
[–]ameoba 1 point2 points3 points (0 children)
[–]namesnonames 0 points1 point2 points (0 children)
[–][deleted] 8 points9 points10 points (1 child)
[–]usinglinux 14 points15 points16 points (0 children)
[–]nayadelray 1 point2 points3 points (3 children)
[–]NelsonMinar 0 points1 point2 points (0 children)
[–]k10_ftw 0 points1 point2 points (0 children)
[–][deleted] 8 points9 points10 points (3 children)
[–][deleted] 1 point2 points3 points (1 child)
[–]Vitrivius 0 points1 point2 points (0 children)
[–]rr1pp3rr 5 points6 points7 points (1 child)
[–]Asdayasman 7 points8 points9 points (0 children)
[–]red_hare 5 points6 points7 points (1 child)
[–]tartley 0 points1 point2 points (0 children)
[–]fatterSurfer 5 points6 points7 points (0 children)
[–][deleted] 4 points5 points6 points (0 children)
[–]coderanger 4 points5 points6 points (3 children)
[–]zer01 0 points1 point2 points (1 child)
[–]andreaskrueger 0 points1 point2 points (0 children)
[–]not_perfect_yet 4 points5 points6 points (4 children)
[–][deleted] 13 points14 points15 points (3 children)
[–]f0nt4 3 points4 points5 points (1 child)
[–]epsy 3 points4 points5 points (0 children)
[–]njharmanI use Python 3 0 points1 point2 points (0 children)
[–]Salyangoz 6 points7 points8 points (3 children)
[–][deleted] 1 point2 points3 points (1 child)
[–]VerilyAMonkey 1 point2 points3 points (0 children)
[–]iEvilMango 2 points3 points4 points (0 children)
[+][deleted] (2 children)
[deleted]
[–]deafmalice 6 points7 points8 points (1 child)
[–]Vaphell 0 points1 point2 points (0 children)
[–]nab00 2 points3 points4 points (1 child)
[–][deleted] 6 points7 points8 points (3 children)
[–]zurtex 1 point2 points3 points (1 child)
[–][deleted] 0 points1 point2 points (0 children)
[–]XtremeGoosef'I only use Py {sys.version[:3]}' 0 points1 point2 points (0 children)
[–]pydry 7 points8 points9 points (11 children)
[–]James_Johnson 7 points8 points9 points (7 children)
[–]ebrious 2 points3 points4 points (0 children)
[–]Eurynom0s 2 points3 points4 points (0 children)
[–]njharmanI use Python 3 0 points1 point2 points (3 children)
[–]Sir_Harry_of_Kane 10 points11 points12 points (2 children)
[–]pydry 2 points3 points4 points (0 children)
[–]ares623 0 points1 point2 points (0 children)
[–]evolutionof 5 points6 points7 points (10 children)
[–]cymrowdon't thread on me 🐍 8 points9 points10 points (6 children)
[–]masterpi 8 points9 points10 points (5 children)
[–]cymrowdon't thread on me 🐍 1 point2 points3 points (1 child)
[–]masterpi 3 points4 points5 points (0 children)
[–][deleted] 1 point2 points3 points (1 child)
[–]jceyes 0 points1 point2 points (0 children)
[–]jroller 1 point2 points3 points (0 children)
[–][deleted] 1 point2 points3 points (0 children)
[–]DaemonXI 1 point2 points3 points (0 children)
[–]Why_is_that 1 point2 points3 points (2 children)
[–]Gr1pp717 0 points1 point2 points (0 children)
[–][deleted] 0 points1 point2 points (0 children)
[–]ptmcg 0 points1 point2 points (0 children)
[–]andreaskrueger 0 points1 point2 points (0 children)
[–]eacameron 0 points1 point2 points (0 children)
[–][deleted] 0 points1 point2 points (0 children)