py3k concerns. An example

Matimus mccredie at gmail.com
Fri Apr 18 17:09:20 EDT 2008


On Apr 18, 8:58 am, Aaron Watters <aaron.watt... at gmail.com> wrote:
> Why is the migration to py3k a concern?
> For example I have libraries which use string%dictionary
> substitution where the dictionary is actually an object
> which emulates a dictionary.  The __getitem__ for
> the object can be very expensive and is only called when
> needed by the string substitution.
>
> In py3k string%dictionary is going away.  Why?
> I have no idea.
>
> The replacement is a string.format(...) method
> which supports dictionary calling.
>     string.format(**dictionary)
> But dictionary
> calling doesn't support dictionary emulation.
> So in the example below the substitution works
> but the call fails.
>
> === code
>
> class fdict(dict):
>     def __getitem__(self, item):
>         return "got("+item+")"
>
> def fn(**d):
>     print d["boogie"]
>
> if __name__=="__main__":
>     fd = fdict()
>     print "attempting string substitution with fake dictionary"
>     print
>     print "hello there %(boogie)s" % fd # <-- works
>     print
>     print "now attempting function call with fake dictionary"
>     print
>     fn(**fd) # <-- fails
>
> === output
>
> % python2.6 dtest.py
> attempting string substitution with fake dictionary
>
> hello there got(boogie)
>
> now attempting function call with fake dictionary
>
> Traceback (most recent call last):
>   File "dtest.py", line 17, in <module>
>     fn(**fd)
>   File "dtest.py", line 7, in fn
>     print d["boogie"]
> KeyError: 'boogie'
>
> ==== end of output
>
> Consequently there is no simple way to translate
> my code, I think.  I suspect you will find this kind of subtle
> issue in many places.  Or worse, you won't find it
> until after your program has been installed
> in production.
>
> It's a damn shame because
> if string%dict was just left in it wouldn't be an issue.
>
> Also, if making f(**d) support dict emulation
> has any negative  performance implications
> then I don't want it please.
>
> sigh.  -- Aaron Watters
>
> ===http://www.xfeedme.com/nucular/pydistro.py/go?FREETEXT=crack+open

The reason it doesn't work is that you are unpacking the dictionary
with **, and you have done nothing to define any keys or define a
length. I would describe the way you are using dict as a hack, and not
part of any standard feature. You make a good point that it breaks
your code, but at the same time the format facility gives you the
ability to do something similar but in a standard way. You simply
define a class with a __format__ method and pass that in instead of
your dict.


class MyClass:
  def __format__(self, spec):
     return "got({0})".format(spec)

c = MyClass()
print ("hey everybody {0:some words}".format(c))
print ("lets try this {0:more words} {0:even more words}".format(c))

should produce:

hey everybody got(some words)
lets try this got(more words) got(even more words)

My point is that instead of exploiting the string formatting of
dictionaries feature to create a custom format specifier, you actually
get to define your own format specifiers, something which is much more
powerful.

And actually, you can do this too... which is even simpler and allows
you to use your a portion of your existing solution:

class fdict(dict):
    def __getitem__(self, item):
        return "got("+item+")"

fd = fdict()
print ("hello there {0[boogie]} hello there {0[george])".format(fd))

Which should result in:

hello there got(boogie) hello there got(george)

* Keep in mind that I have not tested any of this code, there may be
bugs. I don't have Py3k or 2.6 installed locally.

I think this is a good trade-off.

Adding to that... don't worry about py3k. Nobody is forcing you to
switch. In fact, you are encouraged not to until you are comfortable.
Py3k won't _break_ your code. You wrote the code for Python 2.x use it
in 2.x. Python 2.x probably has a good 5-10 years remaining.

Matt



More information about the Python-list mailing list