2

So, after a brief discussion on #python about why not to use locals, I was pondering about what would be a better way without the repetitive nature (i.e. not DRY) of dict(foo=foo,bar=bar) (or the same using the literal syntax ({})).

Ideally, a PEP could be submitted (or one already exists) that mirrors this ecmascript harmony proposal. (I want to promote emphasis on the DRY aspect that it conveys).

So, do you have any solutions? Should I submit a PEP?

Community
  • 1
  • 1
forivall
  • 8,242
  • 1
  • 28
  • 56
  • Good question - although, not properly suitable for Stack Overflow as this is really an invitation to a discussion. This would do better on the Python mailing lists. – Sean Vieira Feb 22 '13 at 03:37
  • And, less I be remiss - here is the info about the available [Python mailing lists](http://python.org/community/lists/). – Sean Vieira Feb 22 '13 at 03:47
  • Yeah, SO's just a little more accessible as far as web content goes -- you don't have to fumble through the archives just to find the answer when the search result comes up. Thanks, I'll definitely ask this on the mailinglist. – forivall Feb 22 '13 at 06:50
  • @forivall I'd be curious what came of the discussion if you took this to the mailing lists. Any links? – Ryne Everett Oct 15 '14 at 05:55
  • @RyneEverett Never did. Sorry. I'm working mostly with nodejs these days anyways, so I don't have much motivation to try again. – forivall Oct 15 '14 at 17:45
  • Sigh. pep-0498 doesn't solve this.... on second though, it might be doable with a hack :) – forivall Sep 12 '15 at 20:45

3 Answers3

0

My currently proposed solution to this is the following pattern. Please tell me if this is just as bad of a practice as using locals().

class _Context:
    foo = 'bar'
render(request, 'example.html', vars(_Context))

One caveat is that this might be a little iffy with python3 because it will use new-style classes with an immutable dictproxy, and I'd need to see how it would interact with the given templating library. Works fine with a simple '{foo}'.format(**_Context.__dict__).

It is a definite improvement over locals(), since it's fairly explicit, and it doesn't leak other parts of the local scope. However, it does leak '__module__' and '__doc__' with old style classes and a bunch of other stuff with new-style classes.

forivall
  • 8,242
  • 1
  • 28
  • 56
0

Here's my solution. There might be better ways to structure this, but it works!

Setup (Python 2 and 3):

class ContextDictBase(type):
    @staticmethod
    def __newnew(cls, name, bases, attrs):
        attrs.pop('__module__', None)
        return attrs
    def __new__(cls, name, bases, attrs):
        ContextDictBase.__new__ = staticmethod(ContextDictBase.__newnew)
        return super(ContextDictBase, cls).__new__(cls, name, bases, attrs)

Python 2:

class ContextDict(object):
    __metaclass__ = ContextDictBase

Python 3:

class ContextDict(object, metaclass=ContextDictBase):
    pass

And then to use it:

class context(ContextDict):
    a = 1
    b = 2

>>> context
{'a': 1, 'b': 2}
forivall
  • 8,242
  • 1
  • 28
  • 56
0

And a variation on the metaclass/attrs solution:

def make_dict(name, bases, attrs):
    attrs.pop('__module__')
    attrs.pop('__metaclass__', None)  # not needed in python3
    return attrs

Python 2:

class Context:
    __metaclass__ = make_dict

Python 3:

class Context(metaclass=make_dict):
    a = 1
    b = 2

Really, this question has just turned into my sandbox for playing with metaclasses

forivall
  • 8,242
  • 1
  • 28
  • 56