On Thu, Aug 05, 2021 at 09:39:44AM +0100, Sam Frances wrote:
Following on from PEP 634, it would be good to be able to have Erlang / Elixir-style pattern matching in function headers.
This was recently discussed here: https://mail.python.org/archives/list/python-ideas@python.org/message/ROYZNX...
def fib(0): return 0
def fib(1): return 1
def fib(n): return fib(n-1) + fib(n-2)
I think that there is something rather disturbing about writing a function definition with a constant literal as parameter. It looks wrong and I'm sure it's going to confuse beginners. Let us remember that Python's execution model is not the same as Erlang or Elixir. In Python, when you write: def fib(a): ... def fib(b): ... that is not a single compile-time declaration, it is a pair of run-time statements. In pseudo-code: # create a function, bind it to the name "fib" fib = make_function( ... ) # create a new function, bind it to the same name, # garbage collecting the first function fib = make_function( ... ) So we would need a radical and major change in the execution model of Python to turn your example into a single function using pattern- matching multiple-dispatch. If we did allow the use of literals as parameters, what would happen if we ran some other code in between the cases of the function? def fib(0): return 0 print("suprise!") def fib(1): return 1 We would, apparently, have two distinct modes: - sometimes re-defining a function replaces the previous binding; - but other times, it extends the function with a new case. What are the rules for each? The nice thing about Python is that we (mostly) have a very predictable, consistent execution model. Syntax is not generally context-dependent, so you can usually interpret the meaning of code by considering it in isolation, rather than by tracking the context. (With a few simple modifiers, such as `global`.) For example: def func(arg): ... creates a function object named "func", and binds it to the name "func" in the local namespace. That applies whether the def statement is inside a class, nested inside another function, in the top-level module, inside a for-loop or if-statement, etc. Because of that consistent behaviour, if we want to use generic functions, we use the singledispatch decorator. This has the advantage of making it explicit and obvious that we're doing generic functions.
def allow_entry({"name": "Bob"}): return "Bob is not allowed in ever!"
I don't know how to interpret that syntax. Does that mean `allow_entry` takes a single argument, which much be a dictionary with a single key, 'name'? result = allow_entry({'name': 'Bob'}) assert result = "Bob is not allowed in ever!" If that's not what you mean, then how would I write a function that *actually does* literally match the dict `{'name': 'Bob'}`? -- Steve