[Python-ideas] Add kwargs to built-in function object

Brandon Mintern bmintern at gmail.com
Thu May 22 09:21:23 CEST 2008


I would like to propose to change the built-in function "object" to
have the following syntax:

object(**kwargs)
Return a new featureless object. object is a base for all new style
classes. It has the methods that are common to all instances of new
style classes.

If kwargs is given, the returned object's __dict__ will be kwargs (or
something to that effect).


An example:

a = object(one=1, two=2)
a.one # returns 1
a.two # returns 2


The justification:

On several occasions I have needed a collection of attributes to
represent a single item. When this happens, there are really three
options:

1. Use a tuple. This works well for temporarily re-packaging items in
a loop or for quick-and-dirty code, but it rapidly becomes unreadable
and hard to maintain. It is not long before you forget what order the
attributes are in, and at first glance, it is not clear what kind of
object is being indexed.

2. Use a dict. This is an improvement over tuples on readability, but
they can be a pain to build and overly-cumbersome to access later. I
understand that dicts are used all over the place in Python, but I
still think of them (in the general case) as a map of keys to values
where the dict represents a collection, not an object.

3. Use a class. This requires coming up with a name for the class and
then writing the class (admittedly, this should be easy). Afterwards,
this is the most convenient, readable method for representing the
data, but since it requires non-trivial effort up front, this method
may be avoided until it's truly apparent that it is necessary.


A real-world example:

Let's say that I want to have a map of employee SSNs to employee data.
I am going to be manipulating this information in various ways, but
not really in any ways that justify the use of class methods. At any
rate, let's build this data from a file where each line is

SSN  First  Last  Salary

with the items being whitespace-delimited. The code, then, will be:

employees = {}
for ssn, first, last, salary in (line.split() for line in open(employee_file)):
    employees[ssn] = (ssn, first, last, salary) # tuple method
    employees[ssn] = {"ssn": ssn, "first": first, "last": last,
"salary": salary} # dict method
    employees[ssn] = Employee(ssn, first, last, salary) # assumes
class with proper constructor

# first name of employee with SSN
employees[SSN][1] # tuple method -- quite unreadable
employees[SSN]["first"] # dict method -- more readable but sub-optimal
employees[SSN].first # class method -- readable and simple


Now, because of the advantages the class method offers in terms of
readability, I have written a convenience class that makes using it
easier:

class Record:
   """
   A class intended to provide a simple interface for creating objects
   with named fields. That is, instead of returning a tuple and indexing
   it or writing a unique class, you can simply do something like:
   a = Record(x=1, y=2)
   a.x # 1
   a.y # 2
   a   # Record(x=1, y=2)
   """
   def __init__ (self, **kwargs):
       self.__dict__.update(kwargs)

   def __repr__ (self):
       return "Record(%s)" \
              % ", ".join("%s=%s" \
                          % field for field in self.__dict__.iteritems())

Now, the line in the for loop above becomes

    employees[ssn] = Record(ssn=ssn, first=first, last=last, salary=salary)

and I have completely avoided the need to define a unique class. Note
that as the number of fields increases, this becomes easier to use
inline than the dict method, at the same time that it avoids the
upfront costs of having to build a new class for every distinct type
of object in the program.

It turns out that other people find such a method useful as well.
According to Catherine Devlin on the centralOH Python list, it is
recipe 4.18 from the Python Cookbook (2nd ed.). Several others from
the mailing list stated that they had created similar solutions
themselves.

Thus, my suggestion is to simply build such functionality directly
into the language. While scanning the built-in functions page (I don't
use any, all, or enumerate nearly enough), I noticed the object()
function, and since its purpose is to return a featureless object, it
seems to fit the bill quite well. Adding my suggested functionality
should break nothing (since the kwargs would be optional) and would
allow people to stop baking their own solutions to this common
problem, while getting the speed bonus of a C implementation (if it
helps).

Thus, the code above becomes

for...
    employees[ssn] = object(ssn=ssn, first=first, last=last, salary=salary)

employees[SSN].first


Does anyone else think this might be a good idea for Python 2.6/3K?

Thanks,
Brandon



More information about the Python-ideas mailing list