[Python-ideas] Allowing def to assign to anything

Steven D'Aprano steve at pearwood.info
Mon Oct 26 09:45:39 EDT 2015


On Mon, Oct 26, 2015 at 02:02:00AM -0400, Alexander Walters wrote:

> In my code, I write a lot of dispatch dictionaries (for lack of a switch 
> statement, but I will not hold my breath for that).  In trying to make 
> writing these dictionaries less annoying, I tend to use many lambdas.  I 
> can let you guess at what problems that has resulted in.  Of course, the 
> preferred way to write such dictionaries is by using a regular function, 
> and adding that function to a dictionary.  This isn't exactly a problem 
> - it works, and works well, but it is annoying to write, and leaves 
> artifacts of those functions in module scope.  I propose a little bit of 
> sugar to make this a little less annoying.

In this case, leaving "artifacts" in the module scope is a feature. If 
your function is simple enough to express in a simple expression, then a 
lambda may be the right solution. But if it requires a full block, then 
chances are that it's too complex for it to be obviously correct, which 
means you should test it. Giving the function a name and module scope 
supports testing.

But if you really want to get rid of it:

del the_function

after adding it to the dispatch table.

Or, stick them in their own namespace. For a package, that might mean 
moving the dispatch table and its associated functions into its own 
module. Or, put them in a class:

class Switch:
    def cheese(x):
        ...
    def spam(x):
        ...
    def eggs(x):
        ...

dispatch = {}
dispatch.update(Switch.__dict__)

result = dispatch[key](arg)


Or one could write a class decorator (or a metaclass) to post-process
the class and returns whatever you like. If I were doing this a lot, I 
would invest the time in building a nice switch construct, before 
looking for new syntax.


> If `def` is allowed to assign to anything (anything that is legal at the 
> left hand side of an = in that scope), annoying artifacts go away.  The 
> syntax I propose should be backwards compatible.


Assign to *anything*? 

a, b, c = 1, 2, 3

def a, b, c(x, y):
    ...


I don't see that, at least, working.


> ```
> dispatch = {}
> 
> def dispatch['foo'](bar):
>     return bar * bar
> ```
> 
> Does this make anything possible that is impossible now?  No.  But it 
> does make the intent of the module author clear - the function is only 
> ever intended to live inside that dict, or list, or other structure.  

It's not clear to me. To me, it looks like you've badly mistyped a 
function annotation. If you hadn't explained what you wanted, I wouldn't 
have a clue what "def dispatch['foo'](bar)" meant.


-- 
Steve


More information about the Python-ideas mailing list