What are the lesser-known but useful features of the Python programming language?
- Try to limit answers to Python core.
- One feature per answer.
- Give an example and short description of the feature, not just a link to documentation.
- Label the feature using a title as the first line.
Quick links to answers:
- Argument Unpacking
- Braces
- Chaining Comparison Operators
- Decorators
- Default Argument Gotchas / Dangers of Mutable Default arguments
- Descriptors
- Dictionary default
.get
value - Docstring Tests
- Ellipsis Slicing Syntax
- Enumeration
- For/else
- Function as iter() argument
- Generator expressions
import this
- In Place Value Swapping
- List stepping
__missing__
items- Multi-line Regex
- Named string formatting
- Nested list/generator comprehensions
- New types at runtime
.pth
files- ROT13 Encoding
- Regex Debugging
- Sending to Generators
- Tab Completion in Interactive Interpreter
- Ternary Expression
try/except/else
- Unpacking+
print()
function with
statement
191 Answers 191
Chaining comparison operators:
>>> x = 5
>>> 1 < x < 10
True
>>> 10 < x < 20
False
>>> x < 10 < x*10 < 100
True
>>> 10 > x <= 9
True
>>> 5 == x > 4
True
In case you're thinking it's doing 1 < x
, which comes out as True
, and then comparing True < 10
, which is also True
, then no, that's really not what happens (see the last example.) It's really translating into 1 < x and x < 10
, and x < 10 and 10 < x * 10 and x*10 < 100
, but with less typing and each term is only evaluated once.
-
1Of course. It was just an example of mixing different operators.Thomas Wouters– Thomas Wouters09/22/2008 15:53:59Commented Sep 22, 2008 at 15:53
-
19This applies to other comparison operators as well, which is why people are sometimes surprised why code like (5 in [5] is True) is False (but it's unpythonic to explicitly test against booleans like that to begin with).Miles– Miles03/02/2009 18:35:36Commented Mar 2, 2009 at 18:35
-
1Not that I know of. Perl 6 does have this feature, though :)ephemient– ephemient01/13/2010 22:56:39Commented Jan 13, 2010 at 22:56
-
19Good but watch out for equal prcedence, like 'in' and '='. 'A in B == C in D' means '(A in B) and (B == C) and (C in D)' which might be unexpected.Charles Merriam– Charles Merriam02/10/2010 10:28:22Commented Feb 10, 2010 at 10:28
-
15Azafe: Lisp's comparisons naturally work this way. It's not a special case because there's no other (reasonable) way to interpret
(< 1 x 10)
. You can even apply them to single arguments, like(= 10)
: cs.cmu.edu/Groups/AI/html/hyperspec/HyperSpec/Body/…Ken– Ken05/26/2010 20:31:30Commented May 26, 2010 at 20:31
Get the python regex parse tree to debug your regex.
Regular expressions are a great feature of python, but debugging them can be a pain, and it's all too easy to get a regex wrong.
Fortunately, python can print the regex parse tree, by passing the undocumented, experimental, hidden flag re.DEBUG
(actually, 128) to re.compile
.
>>> re.compile("^\[font(?:=(?P<size>[-+][0-9]{1,2}))?\](.*?)[/font]",
re.DEBUG)
at at_beginning
literal 91
literal 102
literal 111
literal 110
literal 116
max_repeat 0 1
subpattern None
literal 61
subpattern 1
in
literal 45
literal 43
max_repeat 1 2
in
range (48, 57)
literal 93
subpattern 2
min_repeat 0 65535
any None
in
literal 47
literal 102
literal 111
literal 110
literal 116
Once you understand the syntax, you can spot your errors. There we can see that I forgot to escape the []
in [/font]
.
Of course you can combine it with whatever flags you want, like commented regexes:
>>> re.compile("""
^ # start of a line
\[font # the font tag
(?:=(?P<size> # optional [font=+size]
[-+][0-9]{1,2} # size specification
))?
\] # end of tag
(.*?) # text between the tags
\[/font\] # end of the tag
""", re.DEBUG|re.VERBOSE|re.DOTALL)
-
3Except parsing HTML using regular expression is slow and painful. Even the built-in 'html' parser module doesn't use regexes to get the work done. And if the html module doesn't please you, there is plenty of XML/HTML parser modules that does the job without having to reinvent the wheel.BatchyX– BatchyX03/26/2010 21:59:44Commented Mar 26, 2010 at 21:59
-
A link to documentation on the output syntax would be great.Personman– Personman04/15/2010 16:13:40Commented Apr 15, 2010 at 16:13
-
1This should be an official part of Python, not experimental... RegEx is always tricky and being able to trace what's happening is really helpful.Cahit– Cahit07/14/2010 23:27:00Commented Jul 14, 2010 at 23:27
enumerate
Wrap an iterable with enumerate and it will yield the item along with its index.
For example:
>>> a = ['a', 'b', 'c', 'd', 'e']
>>> for index, item in enumerate(a): print index, item
...
0 a
1 b
2 c
3 d
4 e
>>>
References:
-
45And all this time I was coding this way: for i in range(len(a)): ... and then using a[i] to get the current item.Fernando Martin– Fernando Martin06/22/2009 16:35:14Commented Jun 22, 2009 at 16:35
-
4@Berry Tsakala: To my knowledge, it has not been deprecated.JAB– JAB07/27/2009 17:36:58Commented Jul 27, 2009 at 17:36
-
1Great feature, +1. @Draemon: this is actually covered in the Python tutorial that comes installed with Python (there's a section on various looping constructs), so I'm always surprised that this is so little known.Edan Maor– Edan Maor10/18/2009 09:03:25Commented Oct 18, 2009 at 9:03
-
15enumerate can start from arbitrary index, not necessary 0. Example: 'for i, item in enumerate(list, start=1): print i, item' will start enumeration from 1, not 0.dmitry_romanov– dmitry_romanov08/22/2011 11:00:04Commented Aug 22, 2011 at 11:00
-
3Not deprecated in Py3K docs.python.org/py3k/library/…Léo Germond– Léo Germond09/16/2011 07:53:27Commented Sep 16, 2011 at 7:53
Creating generators objects
If you write
x=(n for n in foo if bar(n))
you can get out the generator and assign it to x. Now it means you can do
for n in x:
The advantage of this is that you don't need intermediate storage, which you would need if you did
x = [n for n in foo if bar(n)]
In some cases this can lead to significant speed up.
You can append many if statements to the end of the generator, basically replicating nested for loops:
>>> n = ((a,b) for a in range(0,2) for b in range(4,6))
>>> for i in n:
... print i
(0, 4)
(0, 5)
(1, 4)
(1, 5)
-
You could also use a nested list comprehension for that, yes?shapr– shapr05/05/2009 16:53:53Commented May 5, 2009 at 16:53
-
54Of particular note is the memory overhead savings. Values are computed on-demand, so you never have the entire result of the list comprehension in memory. This is particularly desirable if you later iterate over only part of the list comprehension.saffsd– saffsd05/17/2009 02:41:39Commented May 17, 2009 at 2:41
-
19This is not particularly "hidden" imo, but also worth noting is the fact that you could not rewind a generator object, whereas you can reiterate over a list any number of times.susmits– susmits04/15/2010 16:26:47Commented Apr 15, 2010 at 16:26
-
13The "no rewind" feature of generators can cause some confusion. Specifically, if you print a generator's contents for debugging, then use it later to process the data, it doesn't work. The data is produced, consumed by print(), then is not available for the normal processing. This doesn't apply to list comprehensions, since they're completely stored in memory.johntellsall– johntellsall05/28/2010 16:01:53Commented May 28, 2010 at 16:01
-
4Similar (dup?) answer: stackoverflow.com/questions/101268/hidden-features-of-python/… Note, however, that the answer I linked here mentions a REALLY GOOD presentation about the power of generators. You really should check it out.Denilson Sá Maia– Denilson Sá Maia08/04/2010 20:21:33Commented Aug 4, 2010 at 20:21
iter() can take a callable argument
For instance:
def seek_next_line(f):
for c in iter(lambda: f.read(1),'\n'):
pass
The iter(callable, until_value)
function repeatedly calls callable
and yields its result until until_value
is returned.
-
As a newbie to python, can you please explain why the
lambda
keyword is necessary here?SiegeX– SiegeX08/12/2011 20:29:29Commented Aug 12, 2011 at 20:29 -
@SiegeX without the lambda, f.read(1) would be evaluated (returning a string) before being passed to the iter function. Instead, the lambda creates an anonymous function and passes that to iter.jmilloy– jmilloy12/31/2011 16:43:43Commented Dec 31, 2011 at 16:43
Be careful with mutable default arguments
>>> def foo(x=[]):
... x.append(1)
... print x
...
>>> foo()
[1]
>>> foo()
[1, 1]
>>> foo()
[1, 1, 1]
Instead, you should use a sentinel value denoting "not given" and replace with the mutable you'd like as default:
>>> def foo(x=None):
... if x is None:
... x = []
... x.append(1)
... print x
>>> foo()
[1]
>>> foo()
[1]
-
39That's definitely one of the more nasty hidden features. I've run into it from time to time.Torsten Marek– Torsten Marek09/23/2008 17:42:57Commented Sep 23, 2008 at 17:42
-
77I found this a lot easier to understand when I learned that the default arguments live in a tuple that's an attribute of the function, e.g.
foo.func_defaults
. Which, being a tuple, is immutable.Robert Rossney– Robert Rossney11/05/2009 20:43:03Commented Nov 5, 2009 at 20:43 -
2@grayger: As the def statement is executed its arguments are evaluated by the interpreter. This creates (or rebinds) a name to a code object (the suite of the function). However, the default arguments are instantiated as objects at the time of definition. This is true of any time of defaulted object, but only significant (exposing visible semantics) when the object is mutable. There's no way of re-binding that default argument name in the function's closure although it can obviously be over-ridden for any call or the whole function can be re-defined).Jim Dennis– Jim Dennis06/24/2010 04:20:40Commented Jun 24, 2010 at 4:20
-
3@Robert of course the arguments tuple might be immutable, but the objects it point to are not necessarily immutable.poolie– poolie07/22/2010 14:59:48Commented Jul 22, 2010 at 14:59
-
16One quick hack to make your initialization a little shorter: x = x or []. You can use that instead of the 2 line if statement.dave mankoff– dave mankoff08/27/2010 02:58:37Commented Aug 27, 2010 at 2:58
Sending values into generator functions. For example having this function:
def mygen():
"""Yield 5 until something else is passed back via send()"""
a = 5
while True:
f = (yield a) #yield a and possibly get f in return
if f is not None:
a = f #store the new value
You can:
>>> g = mygen()
>>> g.next()
5
>>> g.next()
5
>>> g.send(7) #we send this back to the generator
7
>>> g.next() #now it will yield 7 until we send something else
7
-
Agreed. Let's treat this as a nasty example of a hidden feature of Python :)Rafał Dowgird– Rafał Dowgird09/19/2008 13:41:48Commented Sep 19, 2008 at 13:41
-
89In other languages, I believe this magical device is called a "variable".finnw– finnw05/05/2009 17:49:46Commented May 5, 2009 at 17:49
-
5coroutines should be coroutines and genenerator should be themselves too, without mixing. Mega-great link and talk and examples about this here: dabeaz.com/coroutinesu0b34a0f6ae– u0b34a0f6ae08/23/2009 21:39:09Commented Aug 23, 2009 at 21:39
-
31@finnw: the example implements something that's similar to a variable. However, the feature could be used in many other ways ... unlike a variable. It should also be obvious that similar semantics can be implemented using objects (a class implemting Python's call method, in particular).Jim Dennis– Jim Dennis06/24/2010 04:07:17Commented Jun 24, 2010 at 4:07
-
4This is too trivial an example for people who've never seen (and probably won't understand) co-routines. The example that implements the running average without risk of sum variable overflow is a good one.Prashant Kumar– Prashant Kumar06/11/2011 06:16:01Commented Jun 11, 2011 at 6:16
If you don't like using whitespace to denote scopes, you can use the C-style {} by issuing:
from __future__ import braces
-
122
-
37>>> from __future__ import braces File "<stdin>", line 1 SyntaxError: not a chance :PBenjamin W. Smith– Benjamin W. Smith09/22/2008 19:55:07Commented Sep 22, 2008 at 19:55
-
40
-
335I think that we may have a syntactical mistake here, shouldn't that be "from __past__ import braces"?Bill K– Bill K04/29/2009 21:26:28Commented Apr 29, 2009 at 21:26
-
47from __cruft__ import bracesPhillip B Oldham– Phillip B Oldham06/18/2009 07:16:24Commented Jun 18, 2009 at 7:16
The step argument in slice operators. For example:
a = [1,2,3,4,5]
>>> a[::2] # iterate over the whole list in 2-increments
[1,3,5]
The special case x[::-1]
is a useful idiom for 'x reversed'.
>>> a[::-1]
[5,4,3,2,1]
-
31much clearer, in my opinion, is the reversed() function. >>> list(reversed(range(4))) [3, 2, 1, 0]Christian Oudard– Christian Oudard01/02/2009 18:35:33Commented Jan 2, 2009 at 18:35
-
3then how to write "this i a string"[::-1] in a better way? reversed doesnt seem to helpBerry Tsakala– Berry Tsakala06/21/2009 20:56:00Commented Jun 21, 2009 at 20:56
-
24The problem with reversed() is that it returns an iterator, so if you want to preserve the type of the reversed sequence (tuple, string, list, unicode, user types...), you need an additional step to convert it back.Rafał Dowgird– Rafał Dowgird06/24/2009 14:08:57Commented Jun 24, 2009 at 14:08
-
6def reverse_string(string): return string[::-1]pi.– pi.02/03/2010 09:42:11Commented Feb 3, 2010 at 9:42
-
4@pi I think if one knows enough to define reverse_string as you have then one can leave the [::-1] in your code and be comfortable with its meaning and the feeling it is appropriate.physicsmichael– physicsmichael05/28/2010 06:17:18Commented May 28, 2010 at 6:17
Decorators
Decorators allow to wrap a function or method in another function that can add functionality, modify arguments or results, etc. You write decorators one line above the function definition, beginning with an "at" sign (@).
Example shows a print_args
decorator that prints the decorated function's arguments before calling it:
>>> def print_args(function):
>>> def wrapper(*args, **kwargs):
>>> print 'Arguments:', args, kwargs
>>> return function(*args, **kwargs)
>>> return wrapper
>>> @print_args
>>> def write(text):
>>> print text
>>> write('foo')
Arguments: ('foo',) {}
foo
-
54When defining decorators, I'd recommend decorating the decorator with @decorator. It creates a decorator that preserves a functions signature when doing introspection on it. More info here: phyast.pitt.edu/~micheles/python/documentation.htmlsirwart– sirwart09/22/2008 15:53:45Commented Sep 22, 2008 at 15:53
-
45
-
50Well, it's not present in most simple Python tutorials, and I stumbled upon it a long time after I started using Python. That is what I would call a hidden feature, just about the same as other top posts here.Dzinx– Dzinx10/03/2008 06:51:14Commented Oct 3, 2008 at 6:51
-
16vetler, the questions asks for "lesser-known but useful features of the Python programming language." How do you measure 'lesser-known but useful features'? I mean how are any of these responses hidden features?Johnd– Johnd05/23/2009 21:14:51Commented May 23, 2009 at 21:14
-
4@vetler Most of the thing here are hardly "hidden".Humphrey Bogart– Humphrey Bogart04/06/2010 15:33:09Commented Apr 6, 2010 at 15:33
The for...else syntax (see http://docs.python.org/ref/for.html )
for i in foo:
if i == 0:
break
else:
print("i was never 0")
The "else" block will be normally executed at the end of the for loop, unless the break is called.
The above code could be emulated as follows:
found = False
for i in foo:
if i == 0:
found = True
break
if not found:
print("i was never 0")
-
219I think the for/else syntax is awkward. It "feels" as if the else clause should be executed if the body of the loop is never executed.codeape– codeape10/10/2008 06:44:45Commented Oct 10, 2008 at 6:44
-
14ah. Never saw that one! But I must say it is a bit of a misnomer. Who would expect the else block to execute only if break never does? I agree with codeape: It looks like else is entered for empty foos.Daren Thomas– Daren Thomas10/13/2008 17:31:42Commented Oct 13, 2008 at 17:31
-
52seems like the keyword should be finally, not elseJiaaro– Jiaaro06/25/2009 16:31:53Commented Jun 25, 2009 at 16:31
-
21Except finally is already used in a way where that suite is always executed.Roger Pate– Roger Pate06/27/2009 22:34:57Commented Jun 27, 2009 at 22:34
-
7Should definately not be 'else'. Maybe 'then' or something, and then 'else' for when the loop was never executed.Tor Valamo– Tor Valamo01/10/2010 16:26:43Commented Jan 10, 2010 at 16:26
From 2.5 onwards dicts have a special method __missing__
that is invoked for missing items:
>>> class MyDict(dict):
... def __missing__(self, key):
... self[key] = rv = []
... return rv
...
>>> m = MyDict()
>>> m["foo"].append(1)
>>> m["foo"].append(2)
>>> dict(m)
{'foo': [1, 2]}
There is also a dict subclass in collections
called defaultdict
that does pretty much the same but calls a function without arguments for not existing items:
>>> from collections import defaultdict
>>> m = defaultdict(list)
>>> m["foo"].append(1)
>>> m["foo"].append(2)
>>> dict(m)
{'foo': [1, 2]}
I recommend converting such dicts to regular dicts before passing them to functions that don't expect such subclasses. A lot of code uses d[a_key]
and catches KeyErrors to check if an item exists which would add a new item to the dict.
-
10I prefer using setdefault. m={} ; m.setdefault('foo',1)grayger– grayger12/03/2009 03:03:28Commented Dec 3, 2009 at 3:03
-
22@grayger meant this
m={}; m.setdefault('foo', []).append(1)
.Cristian Ciupitu– Cristian Ciupitu05/28/2010 18:53:00Commented May 28, 2010 at 18:53 -
1There are however cases where passing the defaultdict is very handy. The function may for example iter over the value and it works for undefined keys without extra code, as the default is an empty list.Marian– Marian05/29/2010 02:22:37Commented May 29, 2010 at 2:22
-
3defaultdict is better in some circumstances than setdefault, since it doesn't create the default object unless the key is missing. setdefault creates it whether it's missing or not. If your default object is expensive to create this can be a performance hit - I got a decent speedup out of one program simply by changing all setdefault calls.Whatang– Whatang02/12/2011 17:56:35Commented Feb 12, 2011 at 17:56
-
2
defaultdict
is also more powerful than thesetdefault
method in other cases. For example, for a counter—dd = collections.defaultdict(int) ... dd[k] += 1
vsd.setdefault(k, 0) += 1
.Mike Graham– Mike Graham04/10/2011 21:56:52Commented Apr 10, 2011 at 21:56
In-place value swapping
>>> a = 10
>>> b = 5
>>> a, b
(10, 5)
>>> a, b = b, a
>>> a, b
(5, 10)
The right-hand side of the assignment is an expression that creates a new tuple. The left-hand side of the assignment immediately unpacks that (unreferenced) tuple to the names a
and b
.
After the assignment, the new tuple is unreferenced and marked for garbage collection, and the values bound to a
and b
have been swapped.
As noted in the Python tutorial section on data structures,
Note that multiple assignment is really just a combination of tuple packing and sequence unpacking.
-
1Does this use more real memory than the traditional way? I would guess do since you are creating a tuple, instead of just one swap variableNathan– Nathan06/14/2010 14:24:19Commented Jun 14, 2010 at 14:24
-
75It doesn't use more memory. It uses less.. I just wrote it both ways, and de-compiled the bytecode.. the compiler optimizes, as you'd hope it would. dis results showed it's setting up the vars, and then ROT_TWOing. ROT_TWO means 'swap the two top-most stack vars'... Pretty snazzy, actually.royal– royal07/13/2010 22:41:40Commented Jul 13, 2010 at 22:41
-
5You also inadvertently point out another nice feature of Python, which is that you can implicitly make a tuple of items just by separating them by commas.asmeurer– asmeurer12/28/2010 05:12:47Commented Dec 28, 2010 at 5:12
-
3Dana the Sane: assignment in Python is a statement, not an expression, so that expression would be invalid if = had higher priority (i.e. it was interpreted as a, (b = b), a).hbn– hbn01/23/2011 21:27:03Commented Jan 23, 2011 at 21:27
-
5This is the least hidden feature I've read here. Nice, but explicitly described in every Python tutorial.Thiago Chaves– Thiago Chaves05/25/2011 16:56:22Commented May 25, 2011 at 16:56
Readable regular expressions
In Python you can split a regular expression over multiple lines, name your matches and insert comments.
Example verbose syntax (from Dive into Python):
>>> pattern = """
... ^ # beginning of string
... M{0,4} # thousands - 0 to 4 M's
... (CM|CD|D?C{0,3}) # hundreds - 900 (CM), 400 (CD), 0-300 (0 to 3 C's),
... # or 500-800 (D, followed by 0 to 3 C's)
... (XC|XL|L?X{0,3}) # tens - 90 (XC), 40 (XL), 0-30 (0 to 3 X's),
... # or 50-80 (L, followed by 0 to 3 X's)
... (IX|IV|V?I{0,3}) # ones - 9 (IX), 4 (IV), 0-3 (0 to 3 I's),
... # or 5-8 (V, followed by 0 to 3 I's)
... $ # end of string
... """
>>> re.search(pattern, 'M', re.VERBOSE)
Example naming matches (from Regular Expression HOWTO)
>>> p = re.compile(r'(?P<word>\b\w+\b)')
>>> m = p.search( '(((( Lots of punctuation )))' )
>>> m.group('word')
'Lots'
You can also verbosely write a regex without using re.VERBOSE
thanks to string literal concatenation.
>>> pattern = (
... "^" # beginning of string
... "M{0,4}" # thousands - 0 to 4 M's
... "(CM|CD|D?C{0,3})" # hundreds - 900 (CM), 400 (CD), 0-300 (0 to 3 C's),
... # or 500-800 (D, followed by 0 to 3 C's)
... "(XC|XL|L?X{0,3})" # tens - 90 (XC), 40 (XL), 0-30 (0 to 3 X's),
... # or 50-80 (L, followed by 0 to 3 X's)
... "(IX|IV|V?I{0,3})" # ones - 9 (IX), 4 (IV), 0-3 (0 to 3 I's),
... # or 5-8 (V, followed by 0 to 3 I's)
... "$" # end of string
... )
>>> print pattern
"^M{0,4}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$"
-
7I don't know if I'd really consider that a Python feature, most RE engines have a verbose option.user1114– user111409/21/2008 20:44:21Commented Sep 21, 2008 at 20:44
-
18Yes, but because you can't do it in grep or in most editors, a lot of people don't know it's there. The fact that other languages have an equivalent feature doesn't make it not a useful and little known feature of pythonMark Baker– Mark Baker10/17/2008 09:08:12Commented Oct 17, 2008 at 9:08
-
7In a large project with lots of optimized regular expressions (read: optimized for machine but not human beings), I bit the bullet and converted all of them to verbose syntax. Now, introducing new developers to projects is much easier. From now on we enforce verbose REs on every project.Berk D. Demir– Berk D. Demir03/22/2009 13:18:25Commented Mar 22, 2009 at 13:18
-
I'd rather just say: hundreds = "(CM|CD|D?C{0,3})" # 900 (CM), 400 (CD), etc. The language already has a way to give things names, a way to add comments, and a way to combine strings. Why use special library syntax here for things the language already does perfectly well? It seems to go directly against Perlis' Epigram 9.Ken– Ken05/05/2009 18:19:55Commented May 5, 2009 at 18:19
-
3@Ken: a regex may not always be directly in the source, it could be read from settings or a config file. Allowing comments or just additional whitespace (for readability) can be a great help.Roger Pate– Roger Pate06/27/2009 22:30:35Commented Jun 27, 2009 at 22:30
Function argument unpacking
You can unpack a list or a dictionary as function arguments using *
and **
.
For example:
def draw_point(x, y):
# do some magic
point_foo = (3, 4)
point_bar = {'y': 3, 'x': 2}
draw_point(*point_foo)
draw_point(**point_bar)
Very useful shortcut since lists, tuples and dicts are widely used as containers.
-
27* is also known as the splat operatorGabriel– Gabriel07/15/2010 07:03:15Commented Jul 15, 2010 at 7:03
-
3I like this feature, but pylint doesn't sadly.Stephen Paulger– Stephen Paulger03/25/2011 14:46:30Commented Mar 25, 2011 at 14:46
-
5pylint's advice is not a law. The other way, apply(callable, arg_seq, arg_map), is deprecated since 2.3.Yann Vernier– Yann Vernier05/04/2011 11:50:01Commented May 4, 2011 at 11:50
-
1pylint's advice may not be law, but it's damn good advice. Debugging code that over-indulges in stuff like this is pure hell. As the original poster notes, this is a useful shortcut.Andrew– Andrew11/21/2011 19:40:50Commented Nov 21, 2011 at 19:40
-
2I saw this being used in code once and wondered what it did. Unfortunately it's hard to google for "Python **"Fraser Graham– Fraser Graham01/13/2012 23:33:42Commented Jan 13, 2012 at 23:33
ROT13 is a valid encoding for source code, when you use the right coding declaration at the top of the code file:
#!/usr/bin/env python
# -*- coding: rot13 -*-
cevag "Uryyb fgnpxbiresybj!".rapbqr("rot13")
-
10Great! Notice how byte strings are taken literally, but unicode strings are decoded: try
cevag h"Uryyb fgnpxbiresybj!"
u0b34a0f6ae– u0b34a0f6ae10/04/2009 01:12:29Commented Oct 4, 2009 at 1:12 -
12unfortunately it is removed from py3kmykhal– mykhal12/19/2009 18:33:59Commented Dec 19, 2009 at 18:33
-
9This is good for bypassing antivirus.L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳– L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳05/13/2010 20:37:35Commented May 13, 2010 at 20:37
-
96That has nothing to do with the encoding, it is just Python written in Welsh. :-POlivier Verdier– Olivier Verdier07/14/2010 09:45:33Commented Jul 14, 2010 at 9:45
-
33Ph'nglui mglw'nafh Cthulhu R'lyeh wgah'nagl fhtagn!Manuel Ferreria– Manuel Ferreria08/26/2010 22:08:26Commented Aug 26, 2010 at 22:08
Creating new types in a fully dynamic manner
>>> NewType = type("NewType", (object,), {"x": "hello"})
>>> n = NewType()
>>> n.x
"hello"
which is exactly the same as
>>> class NewType(object):
>>> x = "hello"
>>> n = NewType()
>>> n.x
"hello"
Probably not the most useful thing, but nice to know.
Edit: Fixed name of new type, should be NewType
to be the exact same thing as with class
statement.
Edit: Adjusted the title to more accurately describe the feature.
-
8This has a lot of potential for usefulness, e.g., JIT ORMsMark Cidade– Mark Cidade09/22/2008 18:44:44Commented Sep 22, 2008 at 18:44
-
8I use it to generate HTML-Form classes based on a dynamic input. Very nice!pi.– pi.03/18/2009 16:00:13Commented Mar 18, 2009 at 16:00
-
15Note: all classes are created at runtime. So you can use the 'class' statement within a conditional, or within a function (very useful for creating families of classes or classes that act as closures). The improvement that 'type' brings is the ability to neatly define a dynamically generated set of attributes (or bases).spookylukey– spookylukey01/01/2010 14:02:02Commented Jan 1, 2010 at 14:02
-
1You can also create anonymous types with a blank string like: type('', (object,), {'x': 'blah'})jmhmccr– jmhmccr06/16/2011 23:49:51Commented Jun 16, 2011 at 23:49
-
3Could be very useful for code injections.Avihu Turzion– Avihu Turzion07/18/2011 08:49:57Commented Jul 18, 2011 at 8:49
Context managers and the "with
" Statement
Introduced in PEP 343, a context manager is an object that acts as a run-time context for a suite of statements.
Since the feature makes use of new keywords, it is introduced gradually: it is available in Python 2.5 via the __future__
directive. Python 2.6 and above (including Python 3) has it available by default.
I have used the "with" statement a lot because I think it's a very useful construct, here is a quick demo:
from __future__ import with_statement
with open('foo.txt', 'w') as f:
f.write('hello!')
What's happening here behind the scenes, is that the "with" statement calls the special __enter__
and __exit__
methods on the file object. Exception details are also passed to __exit__
if any exception was raised from the with statement body, allowing for exception handling to happen there.
What this does for you in this particular case is that it guarantees that the file is closed when execution falls out of scope of the with
suite, regardless if that occurs normally or whether an exception was thrown. It is basically a way of abstracting away common exception-handling code.
Other common use cases for this include locking with threads and database transactions.
-
3I wouldn't approve a code review which imported anything from future. The features are more cute than useful, and usually they just end up confusing Python newcomers.a paid nerd– a paid nerd05/11/2009 04:36:17Commented May 11, 2009 at 4:36
-
6Yes, such "cute" features as nested scopes and generators are better left to those who know what they're doing. And anyone who wants to be compatible with future versions of Python. For nested scopes and generators, "future versions" of Python means 2.2 and 2.5, respectively. For the with statement, "future versions" of Python means 2.6.Chris B.– Chris B.06/17/2009 18:33:01Commented Jun 17, 2009 at 18:33
-
10This may go without saying, but with python v2.6+, you no longer need to import from future. with is now a first class keyword.fitzgeraldsteele– fitzgeraldsteele11/23/2009 14:28:03Commented Nov 23, 2009 at 14:28
-
25In 2.7 you can have multiple
withs
:)with open('filea') as filea and open('fileb') as fileb: ...
Austin Richardson– Austin Richardson07/14/2010 21:50:59Commented Jul 14, 2010 at 21:50 -
5@Austin i could not get that syntax to work on 2.7. this however did work:
with open('filea') as filea, open('fileb') as fileb: ...
wim– wim07/14/2011 05:29:11Commented Jul 14, 2011 at 5:29
Dictionaries have a get() method
Dictionaries have a 'get()' method. If you do d['key'] and key isn't there, you get an exception. If you do d.get('key'), you get back None if 'key' isn't there. You can add a second argument to get that item back instead of None, eg: d.get('key', 0).
It's great for things like adding up numbers:
sum[value] = sum.get(value, 0) + 1
-
39also, checkout the setdefault method.Daren Thomas– Daren Thomas10/13/2008 17:29:27Commented Oct 13, 2008 at 17:29
-
27also, checkout collections.defaultdict class.jfs– jfs11/23/2008 10:35:07Commented Nov 23, 2008 at 10:35
-
8If you are using Python 2.7 or later, or 3.1 or later, check out the Counter class in the collections module. docs.python.org/library/collections.html#collections.CounterElias Zamaria– Elias Zamaria10/12/2010 01:33:57Commented Oct 12, 2010 at 1:33
-
Oh man, this whole time I've been doing
get(key, None)
. Had no idea thatNone
was provided by default.Jordan Reiter– Jordan Reiter10/19/2011 16:41:02Commented Oct 19, 2011 at 16:41
Descriptors
They're the magic behind a whole bunch of core Python features.
When you use dotted access to look up a member (eg, x.y), Python first looks for the member in the instance dictionary. If it's not found, it looks for it in the class dictionary. If it finds it in the class dictionary, and the object implements the descriptor protocol, instead of just returning it, Python executes it. A descriptor is any class that implements the __get__
, __set__
, or __delete__
methods.
Here's how you'd implement your own (read-only) version of property using descriptors:
class Property(object):
def __init__(self, fget):
self.fget = fget
def __get__(self, obj, type):
if obj is None:
return self
return self.fget(obj)
and you'd use it just like the built-in property():
class MyClass(object):
@Property
def foo(self):
return "Foo!"
Descriptors are used in Python to implement properties, bound methods, static methods, class methods and slots, amongst other things. Understanding them makes it easy to see why a lot of things that previously looked like Python 'quirks' are the way they are.
Raymond Hettinger has an excellent tutorial that does a much better job of describing them than I do.
-
This is a duplicate of decorators, isn't it!? (stackoverflow.com/questions/101268/… )gecco– gecco10/20/2011 19:18:07Commented Oct 20, 2011 at 19:18
-
2no, decorators and descriptors are totally different things, though in the example code, i'm creating a descriptor decorator. :)Nick Johnson– Nick Johnson10/20/2011 23:11:49Commented Oct 20, 2011 at 23:11
-
1The other way to do this is with a lambda:
foo = property(lambda self: self.__foo)
Pete Peterson– Pete Peterson11/02/2011 02:50:16Commented Nov 2, 2011 at 2:50 -
1@PetePeterson Yes, but
property
itself is implemented with descriptors, which was the point of my post.Nick Johnson– Nick Johnson11/02/2011 03:40:49Commented Nov 2, 2011 at 3:40
Conditional Assignment
x = 3 if (y == 1) else 2
It does exactly what it sounds like: "assign 3 to x if y is 1, otherwise assign 2 to x". Note that the parens are not necessary, but I like them for readability. You can also chain it if you have something more complicated:
x = 3 if (y == 1) else 2 if (y == -1) else 1
Though at a certain point, it goes a little too far.
Note that you can use if ... else in any expression. For example:
(func1 if y == 1 else func2)(arg1, arg2)
Here func1 will be called if y is 1 and func2, otherwise. In both cases the corresponding function will be called with arguments arg1 and arg2.
Analogously, the following is also valid:
x = (class1 if y == 1 else class2)(arg1, arg2)
where class1 and class2 are two classes.
-
29The assignment is not the special part. You could just as easily do something like: return 3 if (y == 1) else 2.Brian– Brian11/09/2008 05:39:47Commented Nov 9, 2008 at 5:39
-
25That alternate way is the first time I've seen obfuscated Python.Craig McQueen– Craig McQueen06/09/2009 04:18:48Commented Jun 9, 2009 at 4:18
-
3Kylebrooks: It doesn't in that case, boolean operators short circuit. It will only evaluate 2 if bool(3) == False.RoadieRich– RoadieRich07/12/2009 00:23:03Commented Jul 12, 2009 at 0:23
-
15this backwards-style coding confusing me. something like
x = ((y == 1) ? 3 : 2)
makes more sense to mempen– mpen10/20/2009 07:12:02Commented Oct 20, 2009 at 7:12 -
13I feel just the opposite of @Mark, C-style ternary operators have always confused me, is the right side or the middle what gets evaluated on a false condition? I much prefer Python's ternary syntax.Jeffrey Harris– Jeffrey Harris12/03/2009 16:51:54Commented Dec 3, 2009 at 16:51
Doctest: documentation and unit-testing at the same time.
Example extracted from the Python documentation:
def factorial(n):
"""Return the factorial of n, an exact integer >= 0.
If the result is small enough to fit in an int, return an int.
Else return a long.
>>> [factorial(n) for n in range(6)]
[1, 1, 2, 6, 24, 120]
>>> factorial(-1)
Traceback (most recent call last):
...
ValueError: n must be >= 0
Factorials of floats are OK, but the float must be an exact integer:
"""
import math
if not n >= 0:
raise ValueError("n must be >= 0")
if math.floor(n) != n:
raise ValueError("n must be exact integer")
if n+1 == n: # catch a value like 1e300
raise OverflowError("n too large")
result = 1
factor = 2
while factor <= n:
result *= factor
factor += 1
return result
def _test():
import doctest
doctest.testmod()
if __name__ == "__main__":
_test()
-
6Doctests are certainly cool, but I really dislike all the cruft you have to type to test that something should raise an exceptionTM.– TM.03/10/2009 22:55:08Commented Mar 10, 2009 at 22:55
-
60Doctests are overrated and pollute the documentation. How often do you test a standalone function without any setUp() ?a paid nerd– a paid nerd05/11/2009 04:34:10Commented May 11, 2009 at 4:34
-
2who says you can't have setup in a doctest? write a function that generates the context and returns
locals()
then in your doctest dolocals().update(setUp())
=DJiaaro– Jiaaro12/02/2009 17:27:14Commented Dec 2, 2009 at 17:27 -
12If a standalone function requires a setUp, chances are high that it should be decoupled from some unrelated stuff or put into a class. Class doctest namespace can then be re-used in class method doctests, so it's a bit like setUp, only DRY and readable.Andy Mikhailenko– Andy Mikhailenko04/17/2010 14:38:47Commented Apr 17, 2010 at 14:38
-
4"How often do you test a standalone function" - lots. I find doctests often emerge naturally from the design process when I am deciding on facades.Gregg Lind– Gregg Lind02/11/2011 04:45:07Commented Feb 11, 2011 at 4:45
Named formatting
% -formatting takes a dictionary (also applies %i/%s etc. validation).
>>> print "The %(foo)s is %(bar)i." % {'foo': 'answer', 'bar':42}
The answer is 42.
>>> foo, bar = 'question', 123
>>> print "The %(foo)s is %(bar)i." % locals()
The question is 123.
And since locals() is also a dictionary, you can simply pass that as a dict and have % -substitions from your local variables. I think this is frowned upon, but simplifies things..
New Style Formatting
>>> print("The {foo} is {bar}".format(foo='answer', bar=42))
-
60Will be phased out and eventually replaced with string's format() method.Constantin– Constantin10/05/2008 09:41:04Commented Oct 5, 2008 at 9:41
-
3Named formatting is very useful for translators as they tend to just see the format string without the variable names for contextpixelbeat– pixelbeat10/12/2008 22:45:00Commented Oct 12, 2008 at 22:45
-
2Appears to work in python 3.0.1 (needed to add parenttheses around print call).Pasi Savolainen– Pasi Savolainen07/01/2009 11:32:41Commented Jul 1, 2009 at 11:32
-
9a hash, huh? I see where you came from.shylent– shylent11/14/2009 13:45:54Commented Nov 14, 2009 at 13:45
-
11%s formatting will not be phased out. str.format() is certainly more pythonic, however is actually 10x's slower for simple string replacement. My belief is %s formatting is still best practice.Kenneth Reitz– Kenneth Reitz07/14/2010 12:34:07Commented Jul 14, 2010 at 12:34
To add more python modules (espcially 3rd party ones), most people seem to use PYTHONPATH environment variables or they add symlinks or directories in their site-packages directories. Another way, is to use *.pth files. Here's the official python doc's explanation:
"The most convenient way [to modify python's search path] is to add a path configuration file to a directory that's already on Python's path, usually to the .../site-packages/ directory. Path configuration files have an extension of .pth, and each line must contain a single path that will be appended to sys.path. (Because the new paths are appended to sys.path, modules in the added directories will not override standard modules. This means you can't use this mechanism for installing fixed versions of standard modules.)"
-
1I never made the connection between that .pth file in the site-packages directory from setuptools and this idea. awesome.dave paola– dave paola07/14/2010 02:07:08Commented Jul 14, 2010 at 2:07
Exception else clause:
try:
put_4000000000_volts_through_it(parrot)
except Voom:
print "'E's pining!"
else:
print "This parrot is no more!"
finally:
end_sketch()
The use of the else clause is better than adding additional code to the try clause because it avoids accidentally catching an exception that wasn’t raised by the code being protected by the try ... except statement.
-
8+1 this is awesome. If the try block executes without entering any exception blocks, then the else block is entered. And then of course, the finally block is executedinspectorG4dget– inspectorG4dget09/22/2010 04:49:39Commented Sep 22, 2010 at 4:49
-
It would make more sense to use continue, but I guess it's already taken ;)Paweł Prażak– Paweł Prażak12/16/2010 17:58:51Commented Dec 16, 2010 at 17:58
-
Note that on older versions of Python2 you can't have both else: and finally: clauses for the same try: blockKevin Horn– Kevin Horn05/26/2011 22:49:27Commented May 26, 2011 at 22:49
-
@Paweł Prażak: I don't think it would. As continue and break refer to loops and this is a single conditional statement.Isaac Nequittepas– Isaac Nequittepas09/20/2011 14:42:22Commented Sep 20, 2011 at 14:42
-
1@Paweł Prażak, as Kevin Horn mentioned, this syntax was introduced after the initial release of Python and adding new reserved keywords to existing language is always problematic. That's why an existing keyword is usually reused (c.f. "auto" in recent C++ standard).Constantin– Constantin10/07/2011 10:28:01Commented Oct 7, 2011 at 10:28
Re-raising exceptions:
# Python 2 syntax
try:
some_operation()
except SomeError, e:
if is_fatal(e):
raise
handle_nonfatal(e)
# Python 3 syntax
try:
some_operation()
except SomeError as e:
if is_fatal(e):
raise
handle_nonfatal(e)
The 'raise' statement with no arguments inside an error handler tells Python to re-raise the exception with the original traceback intact, allowing you to say "oh, sorry, sorry, I didn't mean to catch that, sorry, sorry."
If you wish to print, store or fiddle with the original traceback, you can get it with sys.exc_info(), and printing it like Python would is done with the 'traceback' module.
-
Sorry but this is a well known and common feature of almost all languages.Lucas S.– Lucas S.09/19/2008 14:04:05Commented Sep 19, 2008 at 14:04
-
6Note the italicized text. Some people will do
raise e
instead, which doesn't preserve the original traceback.habnabit– habnabit01/27/2009 03:14:55Commented Jan 27, 2009 at 3:14 -
12Maybe more magical,
exc_info = sys.exc_info(); raise exc_info[0], exc_info[1], exc_info[2]
is equivalent to this, but you can change those values around (e.g., change the exception type or message)ianb– ianb05/05/2009 20:27:22Commented May 5, 2009 at 20:27 -
3@Lucas S. Well, I didn't know it, and I'm glad it's written here.Bite code– Bite code06/23/2010 12:32:33Commented Jun 23, 2010 at 12:32
-
i may be showing my youth here, but i have always used the python 3 syntax in python 2.7 with no issuewim– wim07/14/2011 05:49:56Commented Jul 14, 2011 at 5:49
Main messages :)
import this
# btw look at this module's source :)
The Zen of Python, by Tim Peters
Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess. There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than right now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!
-
1Any idea why the source was cyphered that way? Was it just for fun, or was there some other reason?MiniQuark– MiniQuark12/14/2008 20:32:57Commented Dec 14, 2008 at 20:32
-
42the way the source is written goes against the zen!hasen– hasen01/01/2009 05:39:26Commented Jan 1, 2009 at 5:39
-
8svn.python.org/view/python/trunk/Lib/this.py?view=markuperikprice– erikprice06/24/2009 19:41:15Commented Jun 24, 2009 at 19:41
-
2I've updated my /usr/lib/python2.6/this.py replacing the old code with this
print s.translate("".join(chr(64<i<91 and 65+(i-52)%26 or 96<i<123 and 97+(i-84)%26 or i) for i in range(256)))
and it looks much better now!! :-Dfortran– fortran06/25/2009 13:12:53Commented Jun 25, 2009 at 13:12 -
2@MiniQuark: quick history lesson: wefearchange.org/2010/06/import-this-and-zen-of-python.htmluser21037– user2103707/14/2010 00:51:49Commented Jul 14, 2010 at 0:51
Interactive Interpreter Tab Completion
try:
import readline
except ImportError:
print "Unable to load readline module."
else:
import rlcompleter
readline.parse_and_bind("tab: complete")
>>> class myclass:
... def function(self):
... print "my function"
...
>>> class_instance = myclass()
>>> class_instance.<TAB>
class_instance.__class__ class_instance.__module__
class_instance.__doc__ class_instance.function
>>> class_instance.f<TAB>unction()
You will also have to set a PYTHONSTARTUP environment variable.
-
2This is a very useful feature. So much so I've a simple script to enable it (plus a couple of other introspection enhancements): pixelbeat.org/scripts/inpypixelbeat– pixelbeat10/12/2008 22:49:49Commented Oct 12, 2008 at 22:49
-
43IPython gives you this plus tons of other neat stuffakaihola– akaihola01/10/2009 03:47:30Commented Jan 10, 2009 at 3:47
-
This would have been more useful at pdb prompt than the regular python prompt (as IPython serves that purpose anyway). However, this doesn't seem to work at the pdb prompt, probably because pdb binds its own for tab (which is less useful). I tried calling parse_and_bind() at the pdb prompt, but it still didn't work. The alternative of getting pdb prompt with IPython is more work so I tend to not use it.haridsv– haridsv04/01/2010 22:46:15Commented Apr 1, 2010 at 22:46
-
2@haridsv --
easy_install ipdb
-- then you can useimport ipdb; ipdb.set_trace()
Doug Harris– Doug Harris05/20/2010 22:03:21Commented May 20, 2010 at 22:03 -
1On osx [and i imagine other systems which use libedit] you have to do
readline.parse_and_bind ("bind ^I rl_complete")
Foo Bah– Foo Bah02/10/2011 15:20:08Commented Feb 10, 2011 at 15:20
Nested list comprehensions and generator expressions:
[(i,j) for i in range(3) for j in range(i) ]
((i,j) for i in range(4) for j in range(i) )
These can replace huge chunks of nested-loop code.
-
"for j in range(i)" - is this a typo? Normally you'd want fixed ranges for i and j. If you're accessing a 2d array, you'd miss out on half your elements.Peter Gibson– Peter Gibson03/29/2009 02:27:40Commented Mar 29, 2009 at 2:27
-
I'm not accessing any arrays in this example. The only purpose of this code is to show that the expressions from the inner ranges can access those from the outer ones. The by-product is a list of pairs (x,y) such that 4>x>y>0.Rafał Dowgird– Rafał Dowgird03/30/2009 08:23:44Commented Mar 30, 2009 at 8:23
-
2sorta like double integration in calculus, or double summation.Yoo– Yoo09/29/2009 20:57:58Commented Sep 29, 2009 at 20:57
-
22Key point to remember here (which took me a long time to realize) is that the order of the
for
statements are to be written in the order you'd expect them to be written in a standard for-loop, from the outside inwards.sykloid– sykloid01/26/2010 11:17:35Commented Jan 26, 2010 at 11:17 -
2To add on to sykora's comment: imagine you're starting with a stack of
for
s andif
s withyield x
inside. To convert that to a generator expression, movex
first, delete all the colons (and theyield
), and surround the whole thing in parentheses. To make a list comprehension instead, replace the outer parens with square brackets.Ken Arnold– Ken Arnold06/14/2011 01:30:28Commented Jun 14, 2011 at 1:30
Operator overloading for the set
builtin:
>>> a = set([1,2,3,4])
>>> b = set([3,4,5,6])
>>> a | b # Union
{1, 2, 3, 4, 5, 6}
>>> a & b # Intersection
{3, 4}
>>> a < b # Subset
False
>>> a - b # Difference
{1, 2}
>>> a ^ b # Symmetric Difference
{1, 2, 5, 6}
More detail from the standard library reference: Set Types
-
In the tutorial, partly docs.python.org/tutorial/datastructures.html#setsXTL– XTL02/16/2012 07:58:35Commented Feb 16, 2012 at 7:58