I think it is only surprising because it is not something that is familiar. It's not like python python doesn't already have other assignment with different behaviors, for instance:
a = "hello world"
a = 6
print(a) -> 6
def x(self, value):
self._internal *= value
def __init__(self, x)
self._internal = x
a = Foo(4)
a.x = 6
print(a.x) -> 24
This is surprising, but it doesn't mean properties are not useful. Same thing for generic use of descriptors. Most overloaded operators could have surprising behavior:
a = Bar()
b = Bar()
type(a) -> str
print(a) -> I eat all your kittens.
It means that if you use code you should understand what it is doing, or at least what side effects it has.
A few interesting things I thought to do with this behavior are:
- True consts, if at say the module level you create instances of a class that define ___setattr__ and __setself__ (or __assign__, I just went for symmetry), and they both passed or raised a value error, then your consts would always be consts.
- Expression templates, avoiding chained operations that may all be loops to differ to one more efficient loop
- More natural syntax for coroutine sendto, or I guess any pipe or proxy like object
- like the above context variables could make use of this
- disk backed variables, on assignment things get synced to disk.
- (copy/assign) like construction, this would be really useful to the pybind11 community. Allow you to take the properties of another instance of something without actually changing what you are pointing to like below:
def __init__(self, a, b,):
self.a = a
self.b = b
def __setself__(self, other):
self.a = other.a
self.b = other.b
def __init__(self, foo):
self.foo = foo
one, two = Foo(5,6), Foo(8,9)
bar, baz = Bar(one), Bar(one)
one = two # copy like assignment
bar.foo.a == 8 && bar.foo.b == 9 && baz.foo.a == 8 && baz.foo.b == 9
Some of these can already be done through method calls on things now, but that doesn't always "read" as well, and ends up looking very java like to me. I am also sure that given the opportunity people more creative than I can come up with all sorts of uses, similar to @classmethod or @static make good use of descriptors.
If this had existed from the start or early on, it would be perfectly natural to read and use, but for now it would be somewhat shocking (in so far as it gets actually used) and I think that is the biggest minus.