
This is my first post on this mailinglist and i haven't lurked a long time yet, so please be gentle. While mocking objects, i got annoyed by the following code pattern i had to use when modifying multiple attributes on a single object:: obj.first_attr = "value" obj.second_attr = "value2" some_other = "lel" I thought it would be neat if i could do:: in obj: first_attr = "value" second_attr = "value2" some_other = "lel" # indenting this would cause it to appear as an attribute of obj Just a vague idea. Tell me what you think. -- Markus

On Mon, Nov 5, 2012 at 11:28 AM, Markus Unterwaditzer < markus@unterwaditzer.net> wrote:
Hard to read, error-prone and ill-defined. Does it create new attributes or only change existing ones? What about identifiers on right hand sides? What would third_attr = lambda: first_attr do? And this is easy enough: def multi_setattr(obj, **kwargs): for k in kwargs: setattr(obj, k, kwargs[k]) multi_setattr(obj, first_attr = "value", second_attr = "value2") --- Bruce

On 2012-11-05, at 20:47 , Bruce Leban wrote:
Even well-defined, it sounds like a shortcut creating more issues than it solves. Javascript has something which sounds very, very similar in `with` and apart from being hell on performances and having very broken semantics[0] its one and only non-hacky use case is for `eval` (because javascript's eval doesn't have `locals` and `globals` parameters). [0] `with` uses the object it is provided as an internal scope, which means this: with (a) { b = 3; } will result in `a.b` being set to 3 if `a` already has a `b` attribute, otherwise it may clobber an existing `b` in a higher lexical scope, and if none exists it will just create a brand new global `b`.

On 5 November 2012 19:47, Bruce Leban <bruce@leapyear.org> wrote:
My solution has always been: .third_attr = lambda: .first_attr .fourth_attr = not_attr Although a single "." is hard for some [weaklings; pah!] to see. It has exactly one use-case in my opinion: def m(self, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z): in self: .a, .b, .c, .d, .e, .f, .g, .h, .i, .j, .k, .l, .m, .n, .o, .p, .q, .r, .s, .t, .u, .v, .w, .x, .y, .z = \ a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z ....not that having an excuse to do this is a good thing... And this is easy enough:
TYVM for this, I'd never have thought of it.

On 11/5/2012 2:28 PM, Markus Unterwaditzer wrote:
o = obj # solves most of the 'problem' of retyping 'obj' over and over o.first_attr = 'aval' o.sec = o.third(1, o.fourth) If the original is obj.first = first obj.second = second as in common in __init__, then your solution in obj: first = first second = second requires disambiguation by, I presume, position. New syntax must add something that is not trivial to do now. -- Terry Jan Reedy

On 06/11/12 06:28, Markus Unterwaditzer wrote:
This is Pascal's old "with" block. It works well for static languages like Pascal, where the compiler can tell ahead of time which names belong to what, but less well for dynamic languages like Python. Non-trivial examples of this design feature will be ambiguous and error-prone. There's even a FAQ about it: http://docs.python.org/2/faq/design.html#why-doesn-t-python-have-a-with-stat... -- Steven

On 2012-11-05, at 23:36 , Steven D'Aprano wrote:
A possible alternative (though I'm not sure how integration in Python would work, syntactically) which might be a better fit for dynamically typed languages would be Smalltalk's "message cascading" with allowances for assignment. Using `|` as the cascading operator (as Smalltalk's ";" is already used in Python) for the example, obj| first_attr = "value" | second_attr = "value2" | some_method() | some_other_method(2) this would essentially desugar to: obj.first_attr = "value" obj.second_attr = "value2" obj.some_method() obj.some_other_method(2) but as a single expression, and returning the value of the last call. I see most of the value of cascading in the "chaining" of method calls which can't be chained, but extending it to attribute access (get/set) could be neat-ish. Of course this might also need a new self/yourself attribute on ``object`` to top up the cascade.

On 6 November 2012 06:49, Masklinn <masklinn@masklinn.net> wrote:
Using `|` as the cascading operator (as Smalltalk's ";" is already used in Python) for the example,
Just for the record, so is "|" btw, I am -1 for the whole idea - this is trivial to implement through various 2-3 lines snippets, as shown along the thread - makes any case beyond the absolute trivial impossible to write, and complicates readability. I would suggest people liking the idea to get a programming editor with a "copy word above" feature or plug-in instead. js -><-

On Nov 6, 5:39 am, Markus Unterwaditzer <mar...@unterwaditzer.net> wrote:
My concern is that it would promote its own code flow at the expense of readability. It's great for simple assignment, but doesn't allow for anything else: in obj: first_attr = function1() temp_var_not_an_attr = function2(first_attr) second_attr = function2(temp_var_not_an_attr) And what is the expected behaviour for something like: first_attr = "FOO" in obj: first_attr = "BAR" second_attr = first_attr Is obj.second_attr "FOO" or "BAR"? How do I distinguish between outer & inner scope labels?

On Mon, Nov 5, 2012 at 2:28 PM, Markus Unterwaditzer < markus@unterwaditzer.net> wrote:
in obj_1: in obj_2: a = b Tell me what this does, then.
-- Read my blog! I depend on your acceptance of my opinion! I am interesting! http://techblog.ironfroggy.com/ Follow me if you're into that sort of thing: http://www.twitter.com/ironfroggy

On 6 November 2012 20:17, Calvin Spealman <ironfroggy@gmail.com> wrote:
I think it is quite clear the snippet above should be equivalent to: from itertools import product from os import fork for combination in product(obj1, obj2): pid = fork() if pid == 0: setattr(combination[0], "a", getattr(combination[1], "b") ) break ------- Actually near equivalent - it would be more proper if we had a fork variant where each subproccess would run in a different parallel universe. Maybe when Python 5 be overhauled to be optimized for quantum computing we can get close enough. js -><-

On Mon, Nov 5, 2012 at 11:28 AM, Markus Unterwaditzer < markus@unterwaditzer.net> wrote:
Hard to read, error-prone and ill-defined. Does it create new attributes or only change existing ones? What about identifiers on right hand sides? What would third_attr = lambda: first_attr do? And this is easy enough: def multi_setattr(obj, **kwargs): for k in kwargs: setattr(obj, k, kwargs[k]) multi_setattr(obj, first_attr = "value", second_attr = "value2") --- Bruce

On 2012-11-05, at 20:47 , Bruce Leban wrote:
Even well-defined, it sounds like a shortcut creating more issues than it solves. Javascript has something which sounds very, very similar in `with` and apart from being hell on performances and having very broken semantics[0] its one and only non-hacky use case is for `eval` (because javascript's eval doesn't have `locals` and `globals` parameters). [0] `with` uses the object it is provided as an internal scope, which means this: with (a) { b = 3; } will result in `a.b` being set to 3 if `a` already has a `b` attribute, otherwise it may clobber an existing `b` in a higher lexical scope, and if none exists it will just create a brand new global `b`.

On 5 November 2012 19:47, Bruce Leban <bruce@leapyear.org> wrote:
My solution has always been: .third_attr = lambda: .first_attr .fourth_attr = not_attr Although a single "." is hard for some [weaklings; pah!] to see. It has exactly one use-case in my opinion: def m(self, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z): in self: .a, .b, .c, .d, .e, .f, .g, .h, .i, .j, .k, .l, .m, .n, .o, .p, .q, .r, .s, .t, .u, .v, .w, .x, .y, .z = \ a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z ....not that having an excuse to do this is a good thing... And this is easy enough:
TYVM for this, I'd never have thought of it.

On 11/5/2012 2:28 PM, Markus Unterwaditzer wrote:
o = obj # solves most of the 'problem' of retyping 'obj' over and over o.first_attr = 'aval' o.sec = o.third(1, o.fourth) If the original is obj.first = first obj.second = second as in common in __init__, then your solution in obj: first = first second = second requires disambiguation by, I presume, position. New syntax must add something that is not trivial to do now. -- Terry Jan Reedy

On 06/11/12 06:28, Markus Unterwaditzer wrote:
This is Pascal's old "with" block. It works well for static languages like Pascal, where the compiler can tell ahead of time which names belong to what, but less well for dynamic languages like Python. Non-trivial examples of this design feature will be ambiguous and error-prone. There's even a FAQ about it: http://docs.python.org/2/faq/design.html#why-doesn-t-python-have-a-with-stat... -- Steven

On 2012-11-05, at 23:36 , Steven D'Aprano wrote:
A possible alternative (though I'm not sure how integration in Python would work, syntactically) which might be a better fit for dynamically typed languages would be Smalltalk's "message cascading" with allowances for assignment. Using `|` as the cascading operator (as Smalltalk's ";" is already used in Python) for the example, obj| first_attr = "value" | second_attr = "value2" | some_method() | some_other_method(2) this would essentially desugar to: obj.first_attr = "value" obj.second_attr = "value2" obj.some_method() obj.some_other_method(2) but as a single expression, and returning the value of the last call. I see most of the value of cascading in the "chaining" of method calls which can't be chained, but extending it to attribute access (get/set) could be neat-ish. Of course this might also need a new self/yourself attribute on ``object`` to top up the cascade.

On 6 November 2012 06:49, Masklinn <masklinn@masklinn.net> wrote:
Using `|` as the cascading operator (as Smalltalk's ";" is already used in Python) for the example,
Just for the record, so is "|" btw, I am -1 for the whole idea - this is trivial to implement through various 2-3 lines snippets, as shown along the thread - makes any case beyond the absolute trivial impossible to write, and complicates readability. I would suggest people liking the idea to get a programming editor with a "copy word above" feature or plug-in instead. js -><-

On Nov 6, 5:39 am, Markus Unterwaditzer <mar...@unterwaditzer.net> wrote:
My concern is that it would promote its own code flow at the expense of readability. It's great for simple assignment, but doesn't allow for anything else: in obj: first_attr = function1() temp_var_not_an_attr = function2(first_attr) second_attr = function2(temp_var_not_an_attr) And what is the expected behaviour for something like: first_attr = "FOO" in obj: first_attr = "BAR" second_attr = first_attr Is obj.second_attr "FOO" or "BAR"? How do I distinguish between outer & inner scope labels?

On Mon, Nov 5, 2012 at 2:28 PM, Markus Unterwaditzer < markus@unterwaditzer.net> wrote:
in obj_1: in obj_2: a = b Tell me what this does, then.
-- Read my blog! I depend on your acceptance of my opinion! I am interesting! http://techblog.ironfroggy.com/ Follow me if you're into that sort of thing: http://www.twitter.com/ironfroggy

On 6 November 2012 20:17, Calvin Spealman <ironfroggy@gmail.com> wrote:
I think it is quite clear the snippet above should be equivalent to: from itertools import product from os import fork for combination in product(obj1, obj2): pid = fork() if pid == 0: setattr(combination[0], "a", getattr(combination[1], "b") ) break ------- Actually near equivalent - it would be more proper if we had a fork variant where each subproccess would run in a different parallel universe. Maybe when Python 5 be overhauled to be optimized for quantum computing we can get close enough. js -><-
participants (13)
-
alex23
-
Bruce Leban
-
Calvin Spealman
-
Chris Angelico
-
Devin Jeanpierre
-
Joao S. O. Bueno
-
Joshua Landau
-
Markus Unterwaditzer
-
Masklinn
-
Mike Graham
-
Serhiy Storchaka
-
Steven D'Aprano
-
Terry Reedy