In this proposal, I introduce a novel syntax aimed at simplifying multiple attribute access and assignment within objects.
TLDR
How about if we allow this?
some_obj.(a, b, c) = 1, 2, 3
some_obj.(a, b, c) = some_obj.(b, c, a)
Rather than requiring this.
some_obj.a, some_obj.b, some_obj.c = 1, 2, 3
some_obj.a, some_obj.b, some_obj.c = (
some_obj.b, some_obj.c, some_obj.a
)
Motivation
Class definitions often entail verbose patterns for initializing instance attributes, as exemplified below:
class MyClass:
def __init__(self, foo, bar, baz, qux):
self.foo = foo
self.bar = bar
self.baz = baz
self.qux = qux
# Or equivalently
class MyClass:
def __init__(self, foo, bar, baz, qux):
self.foo, self.bar, self.baz, self.qux = foo, bar, baz, qux
Both versions require repeated typing of self.
, a mundane task. There could be several approaches to relieve this verbosity, but itās not easy to design a feature that achieves that without bringing more evils. For example, one can think about simply allowing the omission of self.
in the definition of __init__
special method, but this would sacrifice explicitness and create confusion
If we adopt the proposed syntax that I will describe shortly, it would make the code easier to type, more concise, and improve readability. And there wonāt be much sacrifice in the simplicity of the language, I presume.
Please also, note that the proposed syntax is not only for improving the situation described above, but for more general cases. The example should only be considered as a motivational one. The propose syntax needs not be only used in class definitions. Also, I propose defining both accessing and assignment, not just assignment, will provide more consistency.
Syntax
Multiple attribute assignment
The left-hand side of an assignment statement can be extended to support multiple attributes with fewer keystrokes, using a proposed syntax as follows:
class MyClass:
def __init__(self, foo, bar, baz, qux):
self.(foo, bar, baz, qux) = foo, bar, baz, qux
my = MyClass(1, 2, 3, 4)
# Now, my.foo == 1 and my.bar == 2
# and my.baz == 3 and my.qux == 4
my.(bar, baz) = 5, 6
# Now, my.foo == 1 and my.bar == 5
# and my.baz == 3 and my.qux == 6
Multiple attribute access
Similarly, accessing multiple attributes of an object can be streamlined into a single expression, which evaluates to a tuple of the accessed values:
# continuing from the previous snippet
print(my.(foo, bar, baz)) # Outputs: (1, 5, 3)
a, b = "Apple".(lower(), upper())
print(a, b) # Outputs: apple APPLE
Nesting
Nesting is supported but needs not be encouraged
The proposed syntax does not prevent you from nested attribute access and assignment, allowing for complex expressions involving objects with deep attribute hierarchies. Note that Python already allows arbitrarily deep LHS variable nesting e.g. (a, (b, (c, (d,e)))) = (1, (2, (3, (4, 5))))
.
Arbitrarily deep LHS variable nesting should not be encouraged to keep the code clean, but it does not mean we have to prevent it at the grammar level and I believe we allow this in Python since there is utility in allowing it. Nesting is supported in this proposal to provide a consistent user experience, but it does not always read to easier-to-read code.
class Node:
def __init__(self, value):
self.value = value
root = Node(4)
root.left = Node(2)
root.(left.(left, right), right) = (Node(1), Node(3)), Node(5)
# Accessing nested attributes
print(root.(left.(left.value, right.value), right.value))
# Outputs: ((1, 3), 5)
Interpretation
In the most usual cases, the interpretation should be straightforward.
my.(bar, baz) = (5, 6)
# Is equivalent to
my.bar, my.baz = 5, 6
Edge case
However, there is one syntactic form, I can imagine, that allows more than one way of interpretation.
class YourClass:
...
YourClass().(foo, bar) = 1, 2
# [Option 1]
YourClass().foo = 1
YourClass().bar = 2
# [Option 2]
tmp = YourClass()
tmp.foo, tmp.bar = 1, 2
del tmp
# NOTE: In actual implementation, creation and deletion
# of the new variable should not be necessary.
The code above is actually quite meaningless as it will not bind the new instance(s) to any new variable and not many people wonāt need to write the same pattern in practice. However, it should still be handled for completeness.
This proposal suggests Option 2 as the correct interpretation YourClass().(foo, bar) = 1, 2
should cause creation of only one YourClass instance, not two.
Comment
This proposal seeks to introduce a more succinct and readable syntax for handling multiple attribute access and assignment. I believe it will affect the majority of existing Python programmers and will enhance their productivity in class design and many other tasks. Additionally, learning this new syntax should not require extensive teaching resources as it is not hard to guess its interpretation in most cases.
I understand that such a modification to the language is a significant undertaking that requires careful consideration of its impact on the existing codebase, developer tools, and the broader programming community. Also, there are more details that need to be discussed. It would be much appreciated if you could provide feedback and suggestions.