Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python syntax for namedtuple

I see that the Python syntax for a namedtuple is:

Point = namedtuple('Point', ['x', 'y'])

Why isn't it simpler like so:

Point = namedtuple(['x','y'])

Its less verbose,

like image 287
user2399453 Avatar asked May 17 '15 00:05

user2399453


4 Answers

In general, objects don't know what variables they are assigned to:

# Create three variables referring to an OrderedPair class

tmp = namedtuple('OrderedPair', ['x','y'])  # create a new class with metadata
Point = tmp                                 # assign the class to a variable
Coordinate = tmp                            # assign the class to another var

That's a problem for named tuples. We have to pass in the class name to the namedtuple() factory function so that the class can be given a useful name, docstring, and __repr__ all of which have the class name inside it.

These reason it seems strange to you is that normal function and class definitions are handled differently. Python has special syntax for def and class that not only creates functions and classes, but it assigns their metadata (name and docstring) and assigns the result to a variable.

Consider what def does:

def square(x):
    'Return a value times itself'
    return x * x

The keyword def takes care of several things for you (notice that the word "square" will be used twice):

tmp = lambda x: x*x                         # create a function object
tmp.__name__ = 'square'                     # assign its metadata
tmp.__doc__ = 'Return a value times itself'
square = tmp                                # assign the function to a variable

The same is also true for classes. The class keyword takes care of multiple actions that would otherwise repeat the class name:

class Dog(object):
    def bark(self):
        return 'Woof!'

The underlying steps repeat the class name (notice that the word "Dog" is used twice):

Dog = type('Dog', (object,), {'bark': lambda self: 'Woof'})

Named tuples don't have the advantage of a special keyword like def or class so it has to do the first to steps itself. The final step of assigning to a variable belongs to you. If you think about it, the named tuple way is the norm in Python while def and class are the exception:

 survey_results = open('survey_results')      # is this really a duplication?
 company_db = sqlite3.connect('company.db')   # is this really a duplication?
 www_python_org = urllib.urlopen('http://www.python.org')
 radius = property(radius)

You are not the first to notice this. PEP 359 that suggested we add a new keyword, make, that could allow any callable to gain the auto-assignment capabilities of def, class, and import.

make <callable> <name> <tuple>:
    <block>

would be translated into the assignment:

<name> = <callable>("<name>", <tuple>, <namespace>)

In the end, Guido didn't like the "make" proposal because it caused more problems than it solved (after all, it only saves you from making a single variable assignment).

Hope that helps you see why the class name is written twice. It isn't really duplication. The string form of the class name is used to assign metadata when the object is created, and the separate variable assignment just gives you a way to refer to that object. While they are usually the same name, they don't have to be :-)

like image 115
Raymond Hettinger Avatar answered Sep 19 '22 19:09

Raymond Hettinger


namedtuple is a factory, returning a class. Consider only expression:

namedtuple(['x','y'])

What would be the name of class returned by this expression?

like image 40
m.wasowski Avatar answered Sep 23 '22 19:09

m.wasowski


The class should have a name and know it. And it doesn't see the variable you assign it to, so it can't use that. Plus you could call it something else or even nothing at all:

c = namedtuple('Point', ['x', 'y'])
do_something_with_this(namedtuple('Point', ['x', 'y']))

Speaking of simpler syntax, you can also write it like this:

namedtuple('Point', 'x y')
like image 25
Stefan Pochmann Avatar answered Sep 19 '22 19:09

Stefan Pochmann


Because namedtuple is a function that returns a class. To do that, it is actually rendering a string template and calling eval. To build the string, it needs all the arguments beforehand.

You need to include the relevant context as arguments to namedtuple for that to happen. If you don't provide the class name argument, it would need to guess. Programming languages don't like to guess.

With the rules of the Python language, the namedtuple function within this expression..

>>> Point = namedtuple(['x','y'])

..doesn't have access to variable name (Point) that the result is stored in once the expression has been executed. It only has access to the elements of the list provided as its argument (and variables that have been defined earlier).

like image 29
Tim McNamara Avatar answered Sep 20 '22 19:09

Tim McNamara