From 38a49f70d8c59af57e28ec1710f9e71bdadf2d43 Mon Sep 17 00:00:00 2001 From: Markus Meskanen Date: Wed, 15 Feb 2017 21:08:40 +0200 Subject: [PATCH] PEP-542: Dot Notation Assignment In Function Header (#205) * PEP-542 initial commit * Fixes and improvements based on pre-feedback * Fix typo --- pep-0542.txt | 161 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 161 insertions(+) create mode 100644 pep-0542.txt diff --git a/pep-0542.txt b/pep-0542.txt new file mode 100644 index 000000000..61628b6b1 --- /dev/null +++ b/pep-0542.txt @@ -0,0 +1,161 @@ +PEP: 542 +Title: Dot Notation Assignment In Function Header +Version: $Revision$ +Last-Modified: $Date$ +Author: Markus Meskanen +Status: Draft +Type: Standards Track +Content-Type: text/x-rst +Created: 10-February-2017 + + +Abstract +======== + +Function definitions only allow simple function names to be used, +even though functions are assignable first class objects. + +This PEP proposes adding support for assigning a function to +a class or instance attribute directly in the function +definition's header by using the dot notation to separate +the object from the function's name. + +Although a similar feature, this PEP does not address general +assignment to anything that supports assignment, such as dict keys +and list indexes. + +Rationale +========= + +Currently if a function needs to be assigned to a class or instance +attribute, it requires an additional assignment statement to be made:: + + class MyClass: + ... + + my_instance = MyClass() + + def my_function(self): + ... + + # Assign to class attribute + MyClass.my_function = my_function + + # Or assign to instance attribtue + my_instance.my_function = my_function + +While this isn't usually an inconvenience, using dot notation to +assign directly in the function's header would greatly simplify this:: + + class MyClass: + ... + + my_instance = MyClass() + + # Assign to class attribute + def MyClass.my_function(self): + ... + + # Or assign to instance attribute + def my_instance.my_function(self): + ... + +There are multiple reasons to use this functionality over +a standard class method, for example when the class is referenced +inside the function's header (such as with decorators and typing). +This is also useful when an instance requires a callback attribute:: + + class Menu: + def __init__(self, items=None, select_callback=None): + self.items = items if items is not None else [] + self.select_callback = select_callback + + my_menu = Menu([item1, item2]) + + def my_menu.select_callback(item_index, menu): + print(menu.items[item_index]) + +As opposed to:: + + my_menu = Menu([item1, item2]) + + def select_callback(item_index, menu): + print(menu.items[item_index]) + my_menu.select_callback = select_callback + +Or defining them in an "unnatural" order:: + + def select_callback(item_index, menu): + print(menu.items[item_index]) + + my_menu = Menu([item1, item2], select_callback) + +It reads better than the "unnatural" way, since you already know at +the time of the function definition what it's goig to be used for. +It also saves one line of code while removing visual complexity. + +The feature would also avoid leaving the function's name into +the global namespace:: + + eggs = 'something' + + def Spam.eggs(self): + ... + + def Cheese.eggs(self): + ... + + assert eggs == 'something' + +Ideally this would be just syntastic sugar:: + + def x.y(): + ... + + # Equals to + + def y(): + ... + x.y = y + +Similar to how decorators are syntastic sugar:: + + @decorate + def f(): + ... + + # Equals to + + def f(): + ... + f = decorate(f) + +Implementation +============== + +The `__name__` would follow the principles of a normal function:: + + class MyClass: + def my_function1(self): + ... + + def MyClass.my_function2(self): + ... + + assert my_function1.__name__ == 'my_function1' + assert my_function2.__name__ == 'my_function2' + +The grammar would use `dotted_name` to support chaining of attributes:: + + def Person.name.fset(self, value): + self._name = value + +Backwards Compatibility +======================= + +This PEP is fully backwards compatible. + +Copyright +========= + +This document has been placed in the public domain.