2017-02-15 14:08:40 -05:00
|
|
|
PEP: 542
|
|
|
|
Title: Dot Notation Assignment In Function Header
|
|
|
|
Version: $Revision$
|
|
|
|
Last-Modified: $Date$
|
|
|
|
Author: Markus Meskanen <markusmeskanen@gmail.com>
|
2019-03-15 18:56:22 -04:00
|
|
|
Status: Rejected
|
2017-02-15 14:08:40 -05:00
|
|
|
Type: Standards Track
|
|
|
|
Content-Type: text/x-rst
|
2021-02-09 11:54:26 -05:00
|
|
|
Created: 10-Feb-2017
|
2019-03-15 18:56:22 -04:00
|
|
|
Resolution: https://mail.python.org/pipermail/python-dev/2019-March/156695.html
|
2017-02-15 14:08:40 -05:00
|
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
2021-02-03 09:06:23 -05:00
|
|
|
# Or assign to instance attribute
|
2017-02-15 14:08:40 -05:00
|
|
|
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
|
|
|
|
==============
|
|
|
|
|
2023-09-01 15:19:39 -04:00
|
|
|
The ``__name__`` would follow the principles of a normal function::
|
2017-02-15 14:08:40 -05:00
|
|
|
|
|
|
|
class MyClass:
|
|
|
|
def my_function1(self):
|
|
|
|
...
|
|
|
|
|
|
|
|
def MyClass.my_function2(self):
|
|
|
|
...
|
|
|
|
|
|
|
|
assert my_function1.__name__ == 'my_function1'
|
|
|
|
assert my_function2.__name__ == 'my_function2'
|
|
|
|
|
2023-09-01 15:19:39 -04:00
|
|
|
The grammar would use ``dotted_name`` to support chaining of attributes::
|
2017-02-15 14:08:40 -05:00
|
|
|
|
|
|
|
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.
|