Welcome, guest | Sign In | My Account | Store | Cart

This recipe is based on http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/157572.

Calling parameters() inside a function will return that function's parameters as a dictionary. The dictionary does not include varargs, since *varargs items do not have a "name" that can be used as a key. However, *varkw is added to the dictionary, as an update.

There are three optional parameters that can be used to filter the information returned.

Python, 32 lines
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
def parameters(only=None, exclude=None, ignore='self'):
    """Returns a dictionary of the calling functions 
       parameter names and values.

       The optional arguments can be used to filter the result:

           only           use this to only return parameters 
                          from this list of names.

           exclude        use this to return every parameter 
                          *except* those included in this list
                          of names.

           ignore         use this inside methods to ignore 
                          the calling object's name. For 
                          convenience, it ignores 'self' 
                          by default.

    """
    import inspect
    args, varargs, varkw, defaults = \
        inspect.getargvalues(inspect.stack()[1][0])
    if only is None:
        only = args[:]
        if varkw:
            only.extend(defaults[varkw].keys())
            defaults.update(defaults[varkw])
    if exclude is None:
        exclude = []
    exclude.append(ignore)
    return dict([(attrname, defaults[attrname])
        for attrname in only if attrname not in exclude])

parameters() has several applications, including debugging and introspection. The calling functions parameters _can_ be found using vars() or locals(), so long as no-assignments-occur in the function body before the attempt. parameters() doesn't suffer from this restriction. The parameters can also be accessed via inspection (which is how parameters() works), parameters() just simplifies this while providing extra filtering capabilities.

A possible use case:

<pre> def setattrs(obj, dictionary): obj.__dict__.update(dictionary)

class C: def __init__(self, a, b, c=3, **kwargs): setattrs(self, parameters())

def exclude_ab(self, a, b, c, d):
    e = "e"
    # locals|vars now contains 'e', parameters doesn't
    setattrs(self, parameters(exclude=['a', 'b']))

def only_ab(self, a, b, c, d):
    setattrs(self, parameters(['a', 'b']))

c = C(1,2,d=4) print "c.__dict__ =", c.__dict__ c.exclude_ab(10,20,30,40) print "c.__dict__ =", c.__dict__ c.only_ab(100,200,300,400) print "c.__dict__ =", c.__dict__ </pre>

outputs...

c.__dict__ = {'a': 1, 'c': 3, 'b': 2, 'd': 4}

c.__dict__ = {'a': 1, 'c': 30, 'b': 2, 'd': 40}

c.__dict__ = {'a': 100, 'c': 30, 'b': 200, 'd': 40}

3 comments

Sean Ross (author) 20 years, 9 months ago  # | flag

A more magical version. # based on http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/157572

def __update__(include=[], exclude=[]):

import inspect

args, varargs, varkw, defaults = inspect.getargvalues(inspect.stack()[1][0])

self = defaults[args[0]]

if not include:

    include = args[1:] # skip 'self'

    if varkw:

        include.extend(defaults[varkw].keys())

        defaults.update(defaults[varkw])

for attrname in include:

    if attrname not in exclude:

        setattr(self, attrname, defaults[attrname])

useage

class c:

def __init__(self, a, b, c=3, **kwargs):

    __update__()

I think the name __update__ works here for two reasons:

  1. The leading and trailing double underscores let users know that there's something special happening, and

  2. what this method is doing is updating the dictionary of an instance with another dictionary made up of key/value pairs from __init__'s parameter list, i.e., something like this is going on:

    self.__dict__.update(initparamsdict)

So, since what we're doing is updating a dictionary, in a special way, and the method to do that is called 'update', it seems like '__update__' would be a reasonable name. Other naming suggestions include 'selfupdate()' or 'self_set()' [Alex Martelli - Python Cookbook p.106].

Sean Ross (author) 20 years, 9 months ago  # | flag

Sometimes you could just use vars(). Sometimes, when you want to be quick and dirty, and when you're not using arguments or *keywords, you can use the built in vars(), instead of params():

class c:

def __init__(self, a, b, c=3):

    self.__dict__.update(vars())

You just have to use it before you bind any other variables inside __init__(), and you need to be aware that each of your instances will have an attribute 'self' that is bound to that instance. e.g.

x = c(1,2)

x.self

<__main__.c instance at 0x014F9100\>

>>> x

<__main__.c instance at 0x014F9100\>

It's up to you.

Sean Ross (author) 19 years, 11 months ago  # | flag

nevermind. Now that I've had time to think about it, I don't care for __update__ (too magical)

Created by Sean Ross on Thu, 22 May 2003 (PSF)
Python recipes (4591)
Sean Ross's recipes (8)

Required Modules

Other Information and Tasks