Copying a multiple values of a dict to another with a lot easier syntax

m and n are lists or dicts or enumerates or classes or anything it can be assigned like following: instead of : m.a=n.a; m.b=n.b; m.c=n.c; ... I suggest: a,b,c of m to n ; I thought of this while writing something in javascript since I love pyhton above everything I can type (even more than native language sentences) I wanted to post this idea to here It is my first idea while coding ... In javascript, I was assinging a boundingBoxRect values to a div it was going like this: adiv=document.createElement("div") adiv.style.x=comp.x; adiv.style.y=comp.y; adiv.style.height=comp.height; adiv.style.widht=comp.width; I thought it is super waste of time instead of : x,y,height,width of comp to adiv; English is not my native language and as I said its my first idea while coding. Thank you.

Hi You quite rightly noted that m.a = n.a m.b = m.b m.c = m.c is repetitive. Larger such examples cry out for refactoring. Such can already be done in Python. How about for key in 'a', 'b', 'c': setattr(m, key, getattr(n, key)) If you're doing this a lot, how about a helper function: transfer_attrs(tgt, src, keys) Here's the help messages for the builtin commands setattr and getattr. They're a bit like item access for a dictionary. setattr(obj, name, value, /) Sets the named attribute on the given object to the specified value. setattr(x, 'y', v) is equivalent to ``x.y = v'' getattr(...) getattr(object, name[, default]) -> value Get a named attribute from an object; getattr(x, 'y') is equivalent to x.y. When a default argument is given, it is returned when the attribute doesn't exist; without it, an exception is raised in that case. -- Jonathan

gedizgursu@gmail.com wrote:
How about something like… setattrs(adiv.style, getattrs(comp, 'x y height width') where `getattrs` returns a dict and `setattrs` accepts a mapping? That could be done now without adding any new features to the language. These functions could be added to the standard library somewhere if they should become official things.

Steve Jorgensen wrote:
Those might not be the best names for those functions, but continuing with those for now, here's an example implementation: from functools import reduce import re def getattrs(obj, *names): names = reduce(_concat_attr_names, names, []) return {name: getattr(obj, name) for name in names} def setattrs(obj, mapping): for name, value in mapping.items(): setattr(obj, name, value) def _concat_attr_names(x, y): return x + re.split(r'\s+', y) class Thing: def __init__(self, color=None, size=None, shape=None): self.color = color self.size = size self.shape = shape def __repr__(self): return ( f'Thing({repr(self.color)}, {repr(self.size)},' f' {repr(self.shape)})') thing_a = Thing('red', 'large', 'round') thing_b = Thing('blue') setattrs(thing_b, getattrs(thing_a, 'size shape')) print(repr(thing_b)) # -> 'Thing('blue', 'large', 'round')

On Oct 21, 2019, at 07:44, gedizgursu@gmail.com wrote:
m and n are lists or dicts or enumerates or classes or anything it can be assigned like following:
Assigning attributes is different from assigning items to a collection like a list or dict. That’s why there are separate syntaxes, and separate protocols for it. I realize that in JavaScript that’s not true; collections are just objects with their items as attributes, so `a.b` means the same thing as `a['b']`. But that’s confusing more often than it’s helpful, and I don’t think anyone wants to bring it to Python, or any other languages.
You can do this with a two-liner function: copy_attrs(m, n, 'a', 'b', 'c') … which you implement like this; def copy_items(src, dst, keys): for key in keys: dst[key] = src[key] def copy_attrs(src, dst, *attrs): for attr in attrs: setattr(dst, attr, getattr(src, attr)) Or, if you want to check that all of the source attributes exist and raise before writing anything to dst: values = [src[key] for key in keys] for (key, value) in zip(keys, values): dst[key] = value Or maybe instead of *attrs you want to take a single string and split() it, similar to the way namedtuple does. The functions are simple to write, and probably wouldn’t be used often, and there are variations that you’d probably want sometimes one way and sometimes the other. So I don’t think this needs to be in the stdlib, much less needs custom syntax. But I could be wrong. If you disagree, you can: * Try to argue for good use cases that would come up frequently. * Search the stdlib, popular projects on PyPI, in your own codebase, etc. to come up with examples that would be more readable with this new feature. * Search places like python-list and StackOverflow to see if people are asking for this feature (or, even better, if people are confused but would be asking for this feature if they knew what they wanted). * Package it up and publish on PyPI and come back later with stats showing lots of people downloading and using it. As a side note: Python statements don’t end in semicolons like JavaScript. It’s usually legal to put one there (it means you’re adding an extra null statement after each statement, which is wasteful but otherwise has no effect that will usually break anything). But you shouldn’t do it. More generally, don’t try to write Python as if it were JavaScript. They have different idioms for a lot of things, and trying to treat them the same means you end up writing Python code that isn’t very good Python and JS code that isn’t very good JS.
Another way people have tried to solve this problem is with a BASIC-style `with` (which has nothing to do with Python’s `with`): with adiv.style: .y = comp.y .height = comp.height I don’t think that’s really helpful here, because you have two different objects you want to shortcut, not just one. But you might want to look into past proposals to add a similar feature to Python, to see if any of them did come up with something that would be helpful to you.

On 2019-10-21 10:44, gedizgursu@gmail.com wrote:
Interesting. I also saw this type of redundancy in my code. Instead of making a function, like `copy_attrs()` I changed my APIs to accept over-specified attributes. Instead, I would write m = n ... or simply use `n` where `m` was expected. Yes, `n` would have more attributes than needed, but that is solved by ensuring the receiver can gracefully reject the extra attributes; I decorate pedantic functions that complain about extra parameters. In your other example, I would write: adiv=document.createElement("div") adiv.style = comp There is the problem of unfortunate namespace overlap; where the destination expects some attribute X and the source has an attribute of the same name, X, but the value is wrong. But this is not a large problem: You can plan your attribute names on a program-wide scale so that the same attribute name means the same thing across your whole program, and different attribute names mean different things across your whole program. This does not require too much forward planning, rather more refactoring as you rename parameters to match, or differ, as needed. This is what the ES6 structuring/destructuring is promoting. Consider a function that uses `adiv`: drawBox = (adiv) => { const {x, y, height, width} = adiv.style; } the extra attributes of `comp` are ignored; specific attribute copying is not required.

I believe you made a mess. For all attribute getting needs, I think operator.attrgetter should suffice. No need to implement it yourself. For attribute setting needs, maybe we can add an equivalent operator.attrsetter. I can see myself using it from time to time. Easy solution, solves the problem, makes sense, we can even implement an itemsetter much like itemgetter for completeness, as the implementation will probably be easy and well understood. What do you say? -- Bar Harel On Tue, Oct 22, 2019, 3:25 AM Kyle Lahnakoski <klahnakoski@mozilla.com> wrote:

Hi You quite rightly noted that m.a = n.a m.b = m.b m.c = m.c is repetitive. Larger such examples cry out for refactoring. Such can already be done in Python. How about for key in 'a', 'b', 'c': setattr(m, key, getattr(n, key)) If you're doing this a lot, how about a helper function: transfer_attrs(tgt, src, keys) Here's the help messages for the builtin commands setattr and getattr. They're a bit like item access for a dictionary. setattr(obj, name, value, /) Sets the named attribute on the given object to the specified value. setattr(x, 'y', v) is equivalent to ``x.y = v'' getattr(...) getattr(object, name[, default]) -> value Get a named attribute from an object; getattr(x, 'y') is equivalent to x.y. When a default argument is given, it is returned when the attribute doesn't exist; without it, an exception is raised in that case. -- Jonathan

gedizgursu@gmail.com wrote:
How about something like… setattrs(adiv.style, getattrs(comp, 'x y height width') where `getattrs` returns a dict and `setattrs` accepts a mapping? That could be done now without adding any new features to the language. These functions could be added to the standard library somewhere if they should become official things.

Steve Jorgensen wrote:
Those might not be the best names for those functions, but continuing with those for now, here's an example implementation: from functools import reduce import re def getattrs(obj, *names): names = reduce(_concat_attr_names, names, []) return {name: getattr(obj, name) for name in names} def setattrs(obj, mapping): for name, value in mapping.items(): setattr(obj, name, value) def _concat_attr_names(x, y): return x + re.split(r'\s+', y) class Thing: def __init__(self, color=None, size=None, shape=None): self.color = color self.size = size self.shape = shape def __repr__(self): return ( f'Thing({repr(self.color)}, {repr(self.size)},' f' {repr(self.shape)})') thing_a = Thing('red', 'large', 'round') thing_b = Thing('blue') setattrs(thing_b, getattrs(thing_a, 'size shape')) print(repr(thing_b)) # -> 'Thing('blue', 'large', 'round')

On Oct 21, 2019, at 07:44, gedizgursu@gmail.com wrote:
m and n are lists or dicts or enumerates or classes or anything it can be assigned like following:
Assigning attributes is different from assigning items to a collection like a list or dict. That’s why there are separate syntaxes, and separate protocols for it. I realize that in JavaScript that’s not true; collections are just objects with their items as attributes, so `a.b` means the same thing as `a['b']`. But that’s confusing more often than it’s helpful, and I don’t think anyone wants to bring it to Python, or any other languages.
You can do this with a two-liner function: copy_attrs(m, n, 'a', 'b', 'c') … which you implement like this; def copy_items(src, dst, keys): for key in keys: dst[key] = src[key] def copy_attrs(src, dst, *attrs): for attr in attrs: setattr(dst, attr, getattr(src, attr)) Or, if you want to check that all of the source attributes exist and raise before writing anything to dst: values = [src[key] for key in keys] for (key, value) in zip(keys, values): dst[key] = value Or maybe instead of *attrs you want to take a single string and split() it, similar to the way namedtuple does. The functions are simple to write, and probably wouldn’t be used often, and there are variations that you’d probably want sometimes one way and sometimes the other. So I don’t think this needs to be in the stdlib, much less needs custom syntax. But I could be wrong. If you disagree, you can: * Try to argue for good use cases that would come up frequently. * Search the stdlib, popular projects on PyPI, in your own codebase, etc. to come up with examples that would be more readable with this new feature. * Search places like python-list and StackOverflow to see if people are asking for this feature (or, even better, if people are confused but would be asking for this feature if they knew what they wanted). * Package it up and publish on PyPI and come back later with stats showing lots of people downloading and using it. As a side note: Python statements don’t end in semicolons like JavaScript. It’s usually legal to put one there (it means you’re adding an extra null statement after each statement, which is wasteful but otherwise has no effect that will usually break anything). But you shouldn’t do it. More generally, don’t try to write Python as if it were JavaScript. They have different idioms for a lot of things, and trying to treat them the same means you end up writing Python code that isn’t very good Python and JS code that isn’t very good JS.
Another way people have tried to solve this problem is with a BASIC-style `with` (which has nothing to do with Python’s `with`): with adiv.style: .y = comp.y .height = comp.height I don’t think that’s really helpful here, because you have two different objects you want to shortcut, not just one. But you might want to look into past proposals to add a similar feature to Python, to see if any of them did come up with something that would be helpful to you.

On 2019-10-21 10:44, gedizgursu@gmail.com wrote:
Interesting. I also saw this type of redundancy in my code. Instead of making a function, like `copy_attrs()` I changed my APIs to accept over-specified attributes. Instead, I would write m = n ... or simply use `n` where `m` was expected. Yes, `n` would have more attributes than needed, but that is solved by ensuring the receiver can gracefully reject the extra attributes; I decorate pedantic functions that complain about extra parameters. In your other example, I would write: adiv=document.createElement("div") adiv.style = comp There is the problem of unfortunate namespace overlap; where the destination expects some attribute X and the source has an attribute of the same name, X, but the value is wrong. But this is not a large problem: You can plan your attribute names on a program-wide scale so that the same attribute name means the same thing across your whole program, and different attribute names mean different things across your whole program. This does not require too much forward planning, rather more refactoring as you rename parameters to match, or differ, as needed. This is what the ES6 structuring/destructuring is promoting. Consider a function that uses `adiv`: drawBox = (adiv) => { const {x, y, height, width} = adiv.style; } the extra attributes of `comp` are ignored; specific attribute copying is not required.

I believe you made a mess. For all attribute getting needs, I think operator.attrgetter should suffice. No need to implement it yourself. For attribute setting needs, maybe we can add an equivalent operator.attrsetter. I can see myself using it from time to time. Easy solution, solves the problem, makes sense, we can even implement an itemsetter much like itemgetter for completeness, as the implementation will probably be easy and well understood. What do you say? -- Bar Harel On Tue, Oct 22, 2019, 3:25 AM Kyle Lahnakoski <klahnakoski@mozilla.com> wrote:
participants (7)
-
Andrew Barnert
-
Bar Harel
-
Batuhan Taskaya
-
gedizgursu@gmail.com
-
Jonathan Fine
-
Kyle Lahnakoski
-
Steve Jorgensen