19

I would be interested in knowing what the StackOverflow community thinks are the important language features (idioms) of Python. Features that would define a programmer as Pythonic.

Python (pythonic) idiom - "code expression" that is natural or characteristic to the language Python.

Plus, Which idioms should all Python programmers learn early on?

Thanks in advance

Related:

Community
  • 1
  • 1
John Burley
  • 1,208
  • 2
  • 14
  • 22
  • Look here: http://stackoverflow.com/questions/566865/python-am-i-missing-something – EBGreen Feb 19 '09 at 21:35
  • I'm confused by the line: "Python (pythonic) idiom - "code expression" that is natural or characteristic to the language Python" Is this a definition of "Idiom" or "Pythonic"? Why is it here? What does it mean? – S.Lott Feb 19 '09 at 21:38
  • Yes, well I'm out of close votes for the day. :) – EBGreen Feb 19 '09 at 21:39
  • Also http://lmgtfy.com/?q=pythonic – S.Lott Feb 19 '09 at 21:43
  • I just modified the question, does this help make this an unique question, "early on" is a central part of my inquire – John Burley Feb 19 '09 at 21:43
  • The question's (a) been asked more than once on stack overflow. And (b) is answered through a basic Google search. Unless have you something more specific, it doesn't sound like asking the same question again adding "early on" leads to anything new or different. – S.Lott Feb 19 '09 at 21:46
  • lol - is everyone else out of close votes? – Kenan Banks Feb 19 '09 at 21:47
  • This is good question! I reviewed 100s of questions, not the answers and felt this worth while. I will look at your suggestings – John Burley Feb 19 '09 at 21:49
  • Seem like this question is getting a positive volume of answers and responses. – John Burley Feb 19 '09 at 21:52

12 Answers12

25

Python is a language that can be described as:

"rules you can fit in the palm of your hand with a huge bag of hooks".

Nearly everything in python follows the same simple standards. Everything is accessible, changeable, and tweakable. There are very few language level elements.

Take for example, the len(data) builtin function. len(data) works by simply checking for a data.__len__() method, and then calls it and returns the value. That way, len() can work on any object that implements a __len__() method.


Start by learning about the types and basic syntax:

  1. Dynamic Strongly Typed Languages
  2. bool, int, float, string, list, tuple, dict, set
  3. statements, indenting, "everything is an object"
  4. basic function definitions

Then move on to learning about how python works:

  1. imports and modules (really simple)
  2. the python path (sys.path)
  3. the dir() function
  4. __builtins__

Once you have an understanding of how to fit pieces together, go back and cover some of the more advanced language features:

  1. iterators
  2. overrides like __len__ (there are tons of these)
  3. list comprehensions and generators
  4. classes and objects (again, really simple once you know a couple rules)
  5. python inheritance rules

And once you have a comfort level with these items (with a focus on what makes them pythonic), look at more specific items:

  1. Threading in python (note the Global Interpreter Lock)
  2. context managers
  3. database access
  4. file IO
  5. sockets
  6. etc...

And never forget 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!
Ben Blank
  • 54,908
  • 28
  • 127
  • 156
gahooa
  • 131,293
  • 12
  • 98
  • 101
9

This page covers all the major python idioms: http://python.net/~goodger/projects/pycon/2007/idiomatic/handout.html

CTT
  • 16,901
  • 6
  • 41
  • 37
7

An important idiom in Python is docstrings.

Every object has a __doc__ attribute that can be used to get help on that object. You can set the __doc__ attribute on modules, classes, methods, and functions like this:

# this is m.py
""" module docstring """

class c:
    """class docstring"""
    def m(self):
        """method docstring"""
        pass

def f(a):
    """function f docstring"""
    return

Now, when you type help(m), help(m.f) etc. it will print the docstring as a help message.

Because it's just part of normal object introspection this can be used by documention generating systems like epydoc or used for testing purposes by unittest.

It can also be put to more unconventional (i.e. non-idiomatic) uses such as grammars in Dparser.

Where it gets even more interesting to me is that, even though doc is a read-only attribute on most objects, you can use them anywhere like this:

x = 5
""" pseudo docstring for x """

and documentation tools like epydoc can pick them up and format them properly (as opposed to a normal comment which stays inside the code formatting.

Van Gale
  • 43,536
  • 9
  • 71
  • 81
6

Decorators get my vote. Where else can you write something like:

def trace(num_args=0):
  def wrapper(func):
    def new_f(*a,**k):
      print_args = ''
      if num_args > 0:
        print_args = str.join(',', [str(x) for x in a[0:num_args]])
      print('entering %s(%s)' %(f.__name__,print_args))
      rc = f(*a,**k)
      if rc is not None:
        print('exiting %s(%s)=%s' %(f.__name__,str(rc)))
      else:
        print('exiting %s(%s)' %(f.__name__))
      return rc
    return new_f
  return wrapper

@trace(1)
def factorial(n):
  if n < 2:
    return 1
  return n * factorial(n-1)
factorial(5)

and get output like:

entering factorial(5)
entering factorial(4)
entering factorial(3)
entering factorial(2)
entering factorial(1)
entering factorial(0)
exiting factorial(0)=1
exiting factorial(1)=1
exiting factorial(2)=2
exiting factorial(3)=6
exiting factorial(4)=24
exiting factorial(5)=120
D.Shawley
  • 58,213
  • 10
  • 98
  • 113
4

Everything connected to list usage.
Comprehensions, generators, etc.

rob
  • 36,896
  • 2
  • 55
  • 65
4

Personally, I really like Python syntax defining code blocks by using indentation, and not by the words "BEGIN" and "END" (as in Microsoft's Basic and Visual Basic - I don't like these) or by using left- and right-braces (as in C, C++, Java, Perl - I like these).

This really surprised me because, although indentation has always been very important to me, I didn't make to much "noise" about it - I lived with it, and it is considered a skill to be able to read other peoples, "spaghetti" code. Furthermore, I never heard another programmer suggest making indentation a part of a language. Until Python! I only wish I had realized this idea first.

To me, it is as if Python's syntax forces you to write good, readable code.

Okay, I'll get off my soap-box. ;-)

John Ewing
  • 51
  • 2
3

From a more advanced viewpoint, understanding how dictionaries are used internally by Python. Classes, functions, modules, references are all just properties on a dictionary. Once this is understood it's easy to understand how to monkey patch and use the powerful __gettattr__, __setattr__, and __call__ methods.

Van Gale
  • 43,536
  • 9
  • 71
  • 81
3

Here's one that can help. What's the difference between:

[ foo(x) for x in range(0, 5) ][0]

and

( foo(x) for x in range(0, 5) ).next()

answer: in the second example, foo is called only once. This may be important if foo has a side effect, or if the iterable being used to construct the list is large.

SingleNegationElimination
  • 151,563
  • 33
  • 264
  • 304
  • if `foo()` has a side effect i don't think you should be using it like this but it is important to note that a list comprehension creates a list and a generator expression creates the value on the fly when it's being iterated (Can be iterated only once but uses virtually no memory). – alexpinho98 Jun 05 '13 at 17:09
2

Two things that struck me as especially Pythonic were dynamic typing and the various flavors of lists used in Python, particularly tuples.

Python's list obsession could be said to be LISP-y, but it's got its own unique flavor. A line like:

return HandEvaluator.StraightFlush, (PokerCard.longFaces[index + 4], 
  PokerCard.longSuits[flushSuit]), []

or even

return False, False, False

just looks like Python and nothing else. (Technically, you'd see the latter in Lua as well, but Lua is pretty Pythonic in general.)

Yes - that Jake.
  • 16,725
  • 14
  • 70
  • 96
2

Using string substitutions:

name = "Joe"
age = 12
print "My name is %s, I am %s" % (name, age)

When I'm not programming in python, that simple use is what I miss most.

Oliver Kiel
  • 291
  • 1
  • 2
  • 5
1

I think that tutorials online and books only talk about doing things, not doing things in the best way. Along with the python syntax i think that speed in some cases is important.

Python provides a way to benchmark functions, actually two!!

One way is to use the profile module, like so:

import profile

def foo(x, y, z):
    return x**y % z # Just an example.

profile.run('foo(5, 6, 3)')

Another way to do this is to use the timeit module, like this:

import timeit

def foo(x, y, z):
    return x**y % z # Can also be 'pow(x, y, z)' which is way faster.

timeit.timeit('foo(5, 6, 3)', 'from __main__ import *', number = 100) 
# timeit.timeit(testcode, setupcode, number = number_of_iterations)
alexpinho98
  • 909
  • 8
  • 14
1

Another thing you cannot start early enough is probably testing. Here especially doctests are a great way of testing your code by explaining it at the same time.

doctests are simple text file containing an interactive interpreter session plus text like this:

Let's instantiate our class::

>>> a=Something(text="yes")
>>> a.text
yes

Now call this method and check the results::

>>> a.canify()
>>> a.text
yes, I can

If e.g. a.text returns something different the test will fail.

doctests can be inside docstrings or standalone textfiles and are executed by using the doctests module. Of course the more known unit tests are also available.

MrTopf
  • 4,813
  • 2
  • 24
  • 19