Why use "locals()"

S

Sean DiZazzo

I have never used a call to "locals()" in my code. Can you show me a
use case where it is valuable and Pythonic?

~Sean
 
S

Steven D'Aprano

I have never used a call to "locals()" in my code. Can you show me a
use case where it is valuable and Pythonic?

grep is your friend:



$ grep "locals()" /usr/lib/python2.5/*.py
/usr/lib/python2.5/decimal.py: for name, val in locals().items():
/usr/lib/python2.5/doctest.py: return __import__(module, globals(), locals(), ["*"])
/usr/lib/python2.5/profile.py: p.runctx('f(m)', globals(), locals())
/usr/lib/python2.5/pydoc.py: docloc = '<br><a href="%(docloc)s">Module Docs</a>' % locals()
/usr/lib/python2.5/smtpd.py: mod = __import__(classname[:lastdot], globals(), locals(), [""])
 
S

Sean DiZazzo

I have never used a call to "locals()" in my code.  Can you show me a
use case where it is valuable and Pythonic?

grep is your friend:

$ grep "locals()" /usr/lib/python2.5/*.py
/usr/lib/python2.5/decimal.py:        for name, val in locals().items():
/usr/lib/python2.5/doctest.py:        return __import__(module, globals(), locals(), ["*"])
/usr/lib/python2.5/profile.py:        p.runctx('f(m)', globals(), locals())
/usr/lib/python2.5/pydoc.py:            docloc = '<br><a href="%(docloc)s">Module Docs</a>' % locals()
/usr/lib/python2.5/smtpd.py:        mod = __import__(classname[:lastdot], globals(), locals(), [""])

That is not a use case. I still don't understand!

PS. I know how to use grep.

~Sean
 
S

Steven D'Aprano

I have never used a call to "locals()" in my code.  Can you show me a
use case where it is valuable and Pythonic?

grep is your friend:

$ grep "locals()" /usr/lib/python2.5/*.py
/usr/lib/python2.5/decimal.py:        for name, val in
locals().items(): /usr/lib/python2.5/doctest.py:        return
__import__(module, globals(), locals(), ["*"])
/usr/lib/python2.5/profile.py:        p.runctx('f(m)', globals(),
locals()) /usr/lib/python2.5/pydoc.py:            docloc = '<br><a
href="%(docloc)s">Module Docs</a>' % locals()
/usr/lib/python2.5/smtpd.py:        mod =
__import__(classname[:lastdot], globals(), locals(), [""])

That is not a use case. I still don't understand!

Look at the source code to find out what they're doing with the
information they extract from locals(), and why.

For instance, profile should be obvious -- debuggers and profilers often
need to see the values of local names.

pydoc is using the fairly common idiom of injecting the values of
variables into a string. Personally, I don't see why it uses this idiom:

docloc = 'something'
docloc = '%(docloc)s' % locals()

instead of this:

docloc = 'something'
docloc = '%s' % docloc

but for more complicated cases, the first idiom is much simpler.

decimal seems to be using locals() to avoid this anti-pattern:


def __init__(self, a, b, c, d, e, f, g, h):
self.a = a
self.b = b
self.c = c
self.d = d
# blah blah blah
self.h = h

and replacing it with:

def __init__(self, a, b, c, d, e, f, g, h):
for name, val in locals().items():
setattr(self, name, val)
del self.self


Another use-case: if you have a tool that documents Python code
automatically, it needs a way to automatically view the values of local
names.


PS. I know how to use grep.

I'm sure you do. But you didn't think of using grep, which is why I made
the suggestion that grepping the standard library is a good tool to use
to search for Pythonic examples of code.

It's not foolproof, e.g. the unittest module is more Java-onic than
Pythonic, but it's a good start.
 
G

Gabriel Genellina

I have never used a call to "locals()" in my code. Can you show me a
use case where it is valuable and Pythonic?

def print_item(item):
description = textwrap.fill(item.description, 40)
short = item.description.split('\n', 1)[0]
code = str(item.id).zfill(6)
print "%(code)s %(short)s\n%(description)s\n" % locals()

Transferring arguments:

def foo(some, long, list, of, arguments):
additional = 5
return other(**locals())

Defining properties:

class ColourThing(object):
@apply
def rgb():
def fset(self, rgb):
self.r, self.g, self.b = rgb
def fget(self):
return (self.r, self.g, self.b)
return property(**locals())

(example taken from this recent thread
http://groups.google.com/group/comp.lang.python/browse_thread/thread/449eb9b835a472e7/
see also this recipe http://code.activestate.com/recipes/576742/ )
 
S

Sean DiZazzo

I have never used a call to "locals()" in my code.  Can you show me a
use case where it is valuable and Pythonic?

def print_item(item):
     description = textwrap.fill(item.description, 40)
     short = item.description.split('\n', 1)[0]
     code = str(item.id).zfill(6)
     print "%(code)s %(short)s\n%(description)s\n" % locals()

I see the use of that, but according to Zen, "Explicit is better than
implicit."
Transferring arguments:

def foo(some, long, list, of, arguments):
     additional = 5
     return other(**locals())

Why not?:

def foo(**kwargs):
kwargs["additional"] = 5
return other(**kwargs)
Defining properties:

class ColourThing(object):
     @apply
     def rgb():
         def fset(self, rgb):
             self.r, self.g, self.b = rgb
         def fget(self):
             return (self.r, self.g, self.b)
         return property(**locals())

So really it's just a short hand. But it's against the Zen! Explicit
not Implicit! I'm not convinced....then again, I didn't look at the
source code of the standard libraries.

~Sean
 
S

Sean DiZazzo

On Sun, 13 Sep 2009 20:06:51 -0700, Sean DiZazzo wrote:
I have never used a call to "locals()" in my code.  Can you show me a
use case where it is valuable and Pythonic?
grep is your friend:
$ grep "locals()" /usr/lib/python2.5/*.py
/usr/lib/python2.5/decimal.py:        for name, val in
locals().items(): /usr/lib/python2.5/doctest.py:        return
__import__(module, globals(), locals(), ["*"])
/usr/lib/python2.5/profile.py:        p.runctx('f(m)', globals(),
locals()) /usr/lib/python2.5/pydoc.py:            docloc = '<br><a
href="%(docloc)s">Module Docs</a>' % locals()
/usr/lib/python2.5/smtpd.py:        mod =
__import__(classname[:lastdot], globals(), locals(), [""])
That is not a use case. I still don't understand!

Look at the source code to find out what they're doing with the
information they extract from locals(), and why.

For instance, profile should be obvious -- debuggers and profilers often
need to see the values of local names.

pydoc is using the fairly common idiom of injecting the values of
variables into a string. Personally, I don't see why it uses this idiom:

    docloc = 'something'
    docloc = '%(docloc)s' % locals()

instead of this:

    docloc = 'something'
    docloc = '%s' % docloc

but for more complicated cases, the first idiom is much simpler.

decimal seems to be using locals() to avoid this anti-pattern:

def __init__(self, a, b, c, d, e, f, g, h):
    self.a = a
    self.b = b
    self.c = c
    self.d = d
    # blah blah blah
    self.h = h

and replacing it with:

def __init__(self, a, b, c, d, e, f, g, h):
    for name, val in locals().items():
        setattr(self, name, val)
    del self.self

Another use-case: if you have a tool that documents Python code
automatically, it needs a way to automatically view the values of local
names.
PS.  I know how to use grep.

I'm sure you do. But you didn't think of using grep, which is why I made
the suggestion that grepping the standard library is a good tool to use
to search for Pythonic examples of code.

It's not foolproof, e.g. the unittest module is more Java-onic than
Pythonic, but it's a good start.

Thanks for your explanation Steven. I see how it can be valuable, but
it seems to always break the second rule of Zen. I don't really want
to get into the code of debuggers, but I guess I can see how they
might have no other way to know what local variables have been set.

~Sean
 
C

Carl Banks

def print_item(item):
     description = textwrap.fill(item.description, 40)
     short = item.description.split('\n', 1)[0]
     code = str(item.id).zfill(6)
     print "%(code)s %(short)s\n%(description)s\n" % locals()

I see the use of that, but according to Zen, "Explicit is better than
implicit."


Transferring arguments:
def foo(some, long, list, of, arguments):
     additional = 5
     return other(**locals())

Why not?:

def foo(**kwargs):
    kwargs["additional"] = 5
    return other(**kwargs)
Defining properties:
class ColourThing(object):
     @apply
     def rgb():
         def fset(self, rgb):
             self.r, self.g, self.b = rgb
         def fget(self):
             return (self.r, self.g, self.b)
         return property(**locals())

So really it's just a short hand.  But it's against the Zen! Explicit
not Implicit!  I'm not convinced....then again, I didn't look at the
source code of the standard libraries.

ISTM that any use of locals() is going to be labeled "implicit" by
you, which is not unfair, since it pretty much is implicit compared to
using local variables directly.

If being implicit is alone enough to make anything unPythonic, then
the answer to your question is No, locals() is never Pythonic.

If you are willing to open your mind to the possibility that some
Pythonic things don't adhere to every Zen, then I would suggest that
Gabrielle's examples are perfectly Pythonic shortcuts. But if you
don't want to use them, you don't have to, nobody is forcing you.


Carl Banks
 
S

Sean DiZazzo

If you are willing to open your mind to the possibility that some
Pythonic things don't adhere to every Zen, then I would suggest that
Gabrielle's examples are perfectly Pythonic shortcuts.  But if you
don't want to use them, you don't have to, nobody is forcing you.

It's a pretty small domain, but I see the use (and the Pythonicity).

Thanks all for your advice.

~Sean
 
C

Chris Colbert

Given that python is devoid of types: "Is the variable 'a' an int or a
float at runtime?", explicit can only be taken so far.

Personally, I use locals() when I work with Django.
 
S

Sion Arrowsmith

Sean DiZazzo said:
def print_item(item):
     description = textwrap.fill(item.description, 40)
     short = item.description.split('\n', 1)[0]
     code = str(item.id).zfill(6)
     print "%(code)s %(short)s\n%(description)s\n" % locals()

I see the use of that, but according to Zen, "Explicit is better than
implicit."

I'm having trouble imaginging what a "more explicit" version would be.

I use this idiom a lot for code generation, finding it much more
readable than:

"%s %s\n%s\n" % (code, short, description)

or even:

code + ' ' + short + '\n' + description + '\n'

What I'm not clear about is under what circumstances locals() does
not produce the same result as vars() .
 
G

Gabriel Genellina

En Tue, 15 Sep 2009 11:18:35 -0300, Sion Arrowsmith
Sean DiZazzo <[email protected]> wrote:
What I'm not clear about is under what circumstances locals() does
not produce the same result as vars() .

py> help(vars)
Help on built-in function vars in module __builtin__:

vars(...)
vars([object]) -> dictionary

Without arguments, equivalent to locals().
With an argument, equivalent to object.__dict__.
 
C

Carl Banks

En Tue, 15 Sep 2009 11:18:35 -0300, Sion Arrowsmith  
What I'm not clear about is under what circumstances locals() does
not produce the same result as vars() .

py> help(vars)
Help on built-in function vars in module __builtin__:

vars(...)
     vars([object]) -> dictionary

     Without arguments, equivalent to locals().
     With an argument, equivalent to object.__dict__.

Now *this* I would say is unPythonic: it's basically another obvious
way to do something with no additional benefits.

It'd be more useful (and less of a misnomer) if it would return an
object really repesenting the variable visibility at the current
scope, something like "globals().copy().update(locals())", while
taking care of edge cases like undeclared locals.


Carl Banks
 
S

Sion Arrowsmith

Gabriel Genellina said:
What I'm not clear about is under what circumstances locals() does
not produce the same result as vars() .

py> help(vars)
Help on built-in function vars in module __builtin__:

vars(...)
vars([object]) -> dictionary

Without arguments, equivalent to locals().
With an argument, equivalent to object.__dict__.

Meh, that's what I get for trying to make sense of
http://docs.python.org/library/functions.html#vars
-- which implies the above, but isn't explicit about
it -- rather than using help. In particular, the docs
for locals talk about the inclusion of free variables
in functions, which is absent for vars, which might
imply that there is a difference.
 
S

steve

I have never used a call to "locals()" in my code. Can you show me a
use case where it is valuable and Pythonic?
You've received other answers, but just purely from the 'zen' perspective, there
is a nice clean yin/yan symmetry about globals() Vs locals() after all...

Namespaces are one honking great idea -- let's do more of those!

I am sure someone can come up with an example of where having this very
distinction is useful ...I am too lazy to dream up one myself right now.

cheers,
- steve
 
T

Terry Reedy

Sion said:
Gabriel Genellina said:
What I'm not clear about is under what circumstances locals() does
not produce the same result as vars() .
py> help(vars)
Help on built-in function vars in module __builtin__:

vars(...)
vars([object]) -> dictionary

Without arguments, equivalent to locals().
With an argument, equivalent to object.__dict__.

Meh, that's what I get for trying to make sense of
http://docs.python.org/library/functions.html#vars
-- which implies the above, but isn't explicit about
it -- rather than using help. In particular, the docs
for locals talk about the inclusion of free variables
in functions, which is absent for vars, which might
imply that there is a difference.

I believe the 'free var' stuff is a doc error, so I filed
http://bugs.python.org/issue6925
Doc for locals and vars

tjr
 
S

Simon Forman

Thanks for your explanation Steven.  I see how it can be valuable, but
it seems to always break the second rule of Zen.  I don't really want
to get into the code of debuggers, but I guess I can see how they
might have no other way to know what local variables have been set.

~Sean


The zeroth "rule" of zen is "don't take the rules so seriously".
"They're really more like guidelines anyway."

Regards,
~simon
 
S

Sean DiZazzo

The zeroth "rule" of zen is "don't take the rules so seriously".
"They're really more like guidelines anyway."

Regards,
~simon

Yeah. I think I was just a bit randy at that moment. I realized that
the (*args,**kwargs) idiom is very similar and I use it all the
time.

~Sean
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,197
Messages
2,571,038
Members
47,633
Latest member
BriannaLyk

Latest Threads

Top