[Python-ideas] The "in"-statement

31 views
Skip to first unread message

Markus Unterwaditzer

unread,
Nov 5, 2012, 2:28:41 PM11/5/12
to python...@python.org
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
_______________________________________________
Python-ideas mailing list
Python...@python.org
http://mail.python.org/mailman/listinfo/python-ideas

Bruce Leban

unread,
Nov 5, 2012, 2:47:12 PM11/5/12
to Markus Unterwaditzer, python...@python.org
On Mon, Nov 5, 2012 at 11:28 AM, Markus Unterwaditzer <mar...@unterwaditzer.net> wrote:
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

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

Serhiy Storchaka

unread,
Nov 5, 2012, 2:49:20 PM11/5/12
to python...@python.org
On 05.11.12 21:28, Markus Unterwaditzer wrote:
> I thought it would be neat if i could do::
>
> in obj:
> first_attr = "value"
> second_attr = "value2"

vars(obj).update(
first_attr="value",
second_attr="value2",
)

Or obj.__dict__.update.

Mike Graham

unread,
Nov 5, 2012, 3:29:06 PM11/5/12
to Serhiy Storchaka, Python-Ideas
On Mon, Nov 5, 2012 at 2:49 PM, Serhiy Storchaka <stor...@gmail.com> wrote:
> On 05.11.12 21:28, Markus Unterwaditzer wrote:
>>
>> I thought it would be neat if i could do::
>>
>> in obj:
>> first_attr = "value"
>> second_attr = "value2"
>
>
> vars(obj).update(
> first_attr="value",
> second_attr="value2",
> )
>
> Or obj.__dict__.update.

Tinkering with the object's attribute dict directly using either of
these is extremely error-prone because it does not work for many
objects and because it circumvents the descriptor protocol.

Mike

Masklinn

unread,
Nov 5, 2012, 3:44:26 PM11/5/12
to python-ideas

On 2012-11-05, at 20:47 , Bruce Leban wrote:

> On Mon, Nov 5, 2012 at 11:28 AM, Markus Unterwaditzer <
> mar...@unterwaditzer.net> wrote:
>
>> 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
>>
>
> 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?

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`.

Terry Reedy

unread,
Nov 5, 2012, 4:48:42 PM11/5/12
to python...@python.org
On 11/5/2012 2:28 PM, Markus Unterwaditzer wrote:
> 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"

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

Joshua Landau

unread,
Nov 5, 2012, 5:05:33 PM11/5/12
to Bruce Leban, python-ideas
On 5 November 2012 19:47, Bruce Leban <br...@leapyear.org> wrote:
On Mon, Nov 5, 2012 at 11:28 AM, Markus Unterwaditzer <mar...@unterwaditzer.net> wrote:
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

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?
 
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:

def multi_setattr(obj, **kwargs):
    for k in kwargs:
        setattr(obj, k, kwargs[k]) 

multi_setattr(obj,
    first_attr = "value",
    second_attr = "value2")

TYVM for this, I'd never have thought of it. 

Steven D'Aprano

unread,
Nov 5, 2012, 5:36:56 PM11/5/12
to python...@python.org
On 06/11/12 06:28, Markus Unterwaditzer wrote:

> 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.


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-statement-for-attribute-assignments



--
Steven

alex23

unread,
Nov 5, 2012, 10:53:44 PM11/5/12
to python...@python.org
On Nov 6, 5:39 am, Markus Unterwaditzer <mar...@unterwaditzer.net>
wrote:
> I thought it would be neat if i could do::
>     in obj:
>         first_attr = "value"
>         second_attr = "value2"

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?

Devin Jeanpierre

unread,
Nov 6, 2012, 2:55:17 AM11/6/12
to mikeg...@gmail.com, Serhiy Storchaka, Python-Ideas
On Mon, Nov 5, 2012 at 3:29 PM, Mike Graham <mikeg...@gmail.com> wrote:
> On Mon, Nov 5, 2012 at 2:49 PM, Serhiy Storchaka <stor...@gmail.com> wrote:
>> On 05.11.12 21:28, Markus Unterwaditzer wrote:
>>>
>>> I thought it would be neat if i could do::
>>>
>>> in obj:
>>> first_attr = "value"
>>> second_attr = "value2"
>>
>>
>> vars(obj).update(
>> first_attr="value",
>> second_attr="value2",
>> )
>>
>> Or obj.__dict__.update.
>
> Tinkering with the object's attribute dict directly using either of
> these is extremely error-prone because it does not work for many
> objects and because it circumvents the descriptor protocol.

def update_vars(obj, **kwargs):
for k, v in kwargs.iteritems():
setattr(obj, k, v)

update_vars(obj,
a=b,
c=d)

-- Devin

Masklinn

unread,
Nov 6, 2012, 3:49:36 AM11/6/12
to python-ideas

On 2012-11-05, at 23:36 , Steven D'Aprano wrote:

> On 06/11/12 06:28, Markus Unterwaditzer wrote:
>
>> 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.
>
>
> 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.

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.

Joao S. O. Bueno

unread,
Nov 6, 2012, 5:18:11 AM11/6/12
to Masklinn, python-ideas
On 6 November 2012 06:49, Masklinn <mask...@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
-><-

Calvin Spealman

unread,
Nov 6, 2012, 5:17:43 PM11/6/12
to Markus Unterwaditzer, python...@python.org
On Mon, Nov 5, 2012 at 2:28 PM, Markus Unterwaditzer <mar...@unterwaditzer.net> wrote:
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

in obj_1:
    in obj_2:
        a = b

Tell me what this does, then.
 
Just a vague idea. Tell me what you think.

-- Markus
_______________________________________________
Python-ideas mailing list
Python...@python.org
http://mail.python.org/mailman/listinfo/python-ideas



--
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

Joao S. O. Bueno

unread,
Nov 6, 2012, 9:00:12 PM11/6/12
to ironf...@gmail.com, python...@python.org
On 6 November 2012 20:17, Calvin Spealman <ironf...@gmail.com> wrote:
>
> in obj_1:
> in obj_2:
> a = b
>
> Tell me what this does, then.
>
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
-><-

Chris Angelico

unread,
Nov 7, 2012, 2:19:10 AM11/7/12
to python-ideas
On Wed, Nov 7, 2012 at 1:00 PM, Joao S. O. Bueno <jsb...@python.org.br> wrote:
> 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.

TBH, there's no reason not to implement that with today's Python. The
specifications, like RFC 2795, do not preclude implementations
involving multiple universes and/or subatomic monkeys.

ChrisA
Reply all
Reply to author
Forward
0 new messages