Re: [Python-ideas] PEP: Dict addition and subtraction
On Fri, Mar 8, 2019 at 11:25 AM João Matos wrote: > I've just read your PEP 585 draft and have some questions. > When you say > " > > Like the merge operator and list concatenation, the difference operator > requires both operands to be dicts, while the augmented version allows any > iterable of keys. > > >>> d - {'spam', 'parrot'} > Traceback (most recent call last): > ... > TypeError: cannot take the difference of dict and set > > >>> d -= {'spam', 'parrot'} > >>> print(d) > {'eggs': 2, 'cheese': 'cheddar'} > > >>> d -= [('spam', 999)] > >>> print(d) > {'spam': 999, 'eggs': 2, 'cheese': 'cheddar', 'aardvark': 'Ethel'} > > > " > > The option d -= {'spam', 'parrot'} where parrot does not exist in the d > dict, will raise an exception (eg. KeyNotFound) or be silent? > > The option d -= [('spam', 999)] should remove the pair from the dict, > correct? But the print that follows still shows it there. It's a mistake or > am I missing something? > My understanding is that: - (Q1) Attempting to discard a key not in the target of the augmented assignment would *not *raise a KeyError (or any Exception for that matter). This is analogous to how the - operator works on sets and is consistent with the pure python implementation towards the bottom of the PEP. - (Q2) This one got me as well while implementing the proposal in cpython, but there is a difference in what "part" of the RHS the operators "care about" if the RHS isn't a dict. The += operator expects 2-tuples and will treat them as (key, value) pairs. The -= operator doesn't attempt to unpack the RHS's elements as += does and expects keys. So d -= [('spam', 999)] treated the tuple as a *key *and attempted to discard it. IOW, d = { 'spam': 999, ('spam', 999): True } d -= [('spam', 999)] Would discard the *key* ('spam', 999) and corresponding value True. Which highlights a possibly surprising incongruence between the operators: d = {} update = [(1,1), (2,2), (3,3)] d += update d -= update assert d == {} # will raise, as d still has 3 items Similarly, d = {} update = {1:1, 2:2, 3:3} d += update.items() d -= update.items() assert d == {} # will raise, for the same reason d -= update.keys() assert d == {} # would pass without issue That being said I (personally) wouldn't consider it a deal-breaker and still would very much appreciate of the added functionality (regardless of the choice of operator). - Jim ___ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
Re: [Python-ideas] Attribute-Getter Syntax Proposal
On Sat, Mar 09, 2019 at 05:19:50PM +1300, Greg Ewing wrote: > If we were going to add a syntax for abbreviating lambdas, I would > rather see something more generally useful, e.g. > >x -> x.method() > > as an abbrevation for > >lambda x: x.method() Cocnut does this! https://coconut.readthedocs.io/en/latest/DOCS.html#lambdas It allows any arbitrary expression and parameter list, rather than being limited to a single special case: lambda x, y=None, *args, **kw: spam(x)+y.eggs()-len(args)+kw['foo'] (x, y=None, *args, **kw) -> spam(x)+y.eggs()-len(args)+kw['foo'] # Saves an entire three columns! *wink* (I believe this is similar to Haskell's syntax.) Given that we have lambda though, and many people don't like anonymous functions, I doubt there's enough advantage to justify adding new syntax. I prefer the look of -> to lambda, but given that we have lambda already I wouldn't want to waste that nice looking arrow operator on something we already can do. I'd rather see it saved for something more interesting, like a hypothetical cascading (fluent) method call syntax, or pattern matching. -- Steven ___ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
Re: [Python-ideas] Attribute-Getter Syntax Proposal
If we were going to add a syntax for abbreviating lambdas, I would rather see something more generally useful, e.g. x -> x.method() as an abbrevation for lambda x: x.method() -- Greg ___ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
Re: [Python-ideas] Attribute-Getter Syntax Proposal
On Fri, Mar 08, 2019 at 03:43:10PM -0800, Chris Barker - NOAA Federal via Python-ideas wrote: > > > > Rather than using map in this way, I would recommend a list comprehension: > > Exactly! I really don’t get why folks want to use map() so much when > the comprehension syntax is often cleaner and easier. It was added for > a reason :-) Comprehensions are great for avoiding the need to write verbose lambdas before calling map: map(lambda x: x + 1, numbers) (x + 1 for x in numbers) but you typically only save a few characters, and you don't even save that when the function already exists: map(str.upper, strings) (s.upper() for s in strings) So horses for courses. In my opinion, map() looks nicer when you are calling a pre-existing named function, and comprehensions look nicer when you have an expression involving operators which would otherwise require a lambda. -- Steven ___ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
Re: [Python-ideas] Preallocated tuples and dicts for function calls
On Fri, Mar 08, 2019 at 10:16:02PM +0100, Martin Bammer wrote: > Hi, > > what about the idea that the interpreter preallocates and > preinitializes the tuples and dicts for function calls where possible > when loading a module? That's an implementation detail. CPython may or may not use tuples and dicts to call functions, but I don't think that's specified by the language. So we're talking about a potential optimization of one interpreter, not a language change. If the idea survives cursory discussion here, the Python-Dev mailing list is probably a better place to discuss it further. > Before calling a function then the interpreter would just need to update > the items which are dynamic and then call the function. As Greg points out, that would be unsafe when using threads. Let's say you have two threads, A and B, and both call function spam(). A wants to call spam(1, 2) and B wants to call spam(3, 4). Because of the unpredictable order that threaded code runs, we might have: A sets the argument tuple to (1, 2) B sets the argument tuple to (2, 3) B calls spam() A calls spam() # Oops! and mysterious, difficult to reproduce errors occur. It may be possible to solve this with locks, but that would probably slow code down horribly. [...] > Without the optimization the interpreter would need to: > > - create new tuple (allocate memory) > - write constant into first tuple index. > - create dict (allocate memory) > - add key+value > - add key+value > - call function Sure, and that happens at runtime, just before the function is called. But the same series of allocations would have to occur under your idea too, it would just happen when the module loads. And then the pre- allocated tuples and dicts would hang around forever, wasting memory. Even if it turns out that the function never actually gets called: for x in sequence: if condition(x): # always returns False! function(...) the compiler will have pre-allocated the memory to call it. So I suspect this is going to be very memory hungry. Trading off memory for speed might be worthwhile, but it is a trade-off that will make certain things worse rather than better. > If this idea is possible to implement I assume the function calls would > receive a great speed improvment. Well, it might decrease the overhead of calling a function, but that's usually only a small proportion of the total time to make function calls. So it might not help as much as you expect, except in the case where you have lots and lots of function calls each of which do only a tiny amount of work. But that has to be balanced against the slowdown that occurs when the module loads, when the same memory allocations (but not deallocations) would occur. Starting up Python is already pretty slow compared to other languages, this would probably make it worse. Even if it became a nett win for some applications, for others it would likely be a nett loss. My guess is that it would probably hurt the cases which are already uncomfortably slow, while benefitting the cases that don't need much optimization. But that's just a guess, and not an especially educated guess at that. -- Steven ___ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
Re: [Python-ideas] PEP: Dict addition and subtraction
Guido van Rossum wrote: I guess everybody's high school math(s) class was different. I don't ever recall seeing + and * for boolean OR/AND; we used ∧ and ∨. Boolean algebra was only touched on briefly in my high school years. I can't remember exactly what notation was used, but it definitely wasn't ∧ and ∨ -- I didn't encounter those until much later. However, I've definitely seen texts on boolean alegbra in relation to logic circuits that write 'A and B' as 'AB', and 'A or B' as 'A + B'. (And also use an overbar for negation instead of the mathematical ¬). Maybe it depends on whether you're a mathematician or an engineer? The multiplication-addition notation seems a lot more readable when you have a complicated boolean expression, so I can imagine it being favoured by pragmatic engineering type people. -- Greg ___ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
Re: [Python-ideas] Preallocated tuples and dicts for function calls
Martin Bammer wrote: what about the idea that the interpreter preallocates and preinitializes the tuples and dicts for function calls where possible when loading a module? This would not be thread-safe. Locking would be needed around uses of the preallocated objects, and that might take away some or all of the gain. It would also introduce unexpected interactions between threads. -- Greg ___ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
Re: [Python-ideas] Attribute-Getter Syntax Proposal
I'm really old ... I remember thinking how clever attrgetter() was when it was after to Python 2.4. On Fri, Mar 8, 2019, 7:51 PM David Mertz wrote: > You could use the time machine: > https://docs.python.org/3/library/operator.html > > On Fri, Mar 8, 2019, 11:57 AM Samuel Li wrote: > >> Don't know if this has been suggested before. Instead of writing >> something like >> >> >>> map(lambda x: x.upper(), ['a', 'b', 'c']) >> >> I suggest this syntax: >> >>> map(.upper(), ['a', 'b', 'c']) >> >> This would also work for attributes: >> >>> map(.real, [1j, 2, 3+4j]) >> >> Internally, this would require translating >> >> .attribute -> lambda x: x.attribute >> >> and >> >> .method(*args, **kwargs) -> lambda x: x.method(*args, **kwargs) >> >> This translation should only take place where a "normal" attribute lookup >> makes no sense (throws a SyntaxError); i.e. foo.bar works as before, >> foo(.bar) would previously throw a SyntaxError, so the new syntax applies >> and the .bar is interpreted as an attrgetter. >> >> This is of course only a cosmetic improvement over operator.attrgetter >> and operator.methodcaller, but I think it's nice enough to warrant >> consideration. >> >> If you like this idea or think it's utter garbage, feel free to discuss. >> ___ >> Python-ideas mailing list >> Python-ideas@python.org >> https://mail.python.org/mailman/listinfo/python-ideas >> Code of Conduct: http://python.org/psf/codeofconduct/ >> > ___ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
Re: [Python-ideas] Attribute-Getter Syntax Proposal
You could use the time machine: https://docs.python.org/3/library/operator.html On Fri, Mar 8, 2019, 11:57 AM Samuel Li wrote: > Don't know if this has been suggested before. Instead of writing something > like > > >>> map(lambda x: x.upper(), ['a', 'b', 'c']) > > I suggest this syntax: > >>> map(.upper(), ['a', 'b', 'c']) > > This would also work for attributes: > >>> map(.real, [1j, 2, 3+4j]) > > Internally, this would require translating > > .attribute -> lambda x: x.attribute > > and > > .method(*args, **kwargs) -> lambda x: x.method(*args, **kwargs) > > This translation should only take place where a "normal" attribute lookup > makes no sense (throws a SyntaxError); i.e. foo.bar works as before, > foo(.bar) would previously throw a SyntaxError, so the new syntax applies > and the .bar is interpreted as an attrgetter. > > This is of course only a cosmetic improvement over operator.attrgetter and > operator.methodcaller, but I think it's nice enough to warrant > consideration. > > If you like this idea or think it's utter garbage, feel free to discuss. > ___ > Python-ideas mailing list > Python-ideas@python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > ___ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
Re: [Python-ideas] Left arrow and right arrow operators
francismb wrote: It is may be how now it is, but means that it needs to be always like this? Yes, as long as you care about not breaking existing code. While you may be in the habit of always leaving a space between '<' and '-', others may have different styles. Do you really want to tell them that all their code is now wrong? -- Greg ___ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
Re: [Python-ideas] PEP: Dict addition and subtraction
On Fri, Mar 8, 2019 at 3:33 PM Greg Ewing wrote: > Guido van Rossum wrote: > > I guess this explains the behavior of removing results <= 0; it makes > > sense as multiset subtraction, since in a multiset a negative count > > makes little sense. (Though the name Counter certainly doesn't seem to > > imply multiset.) > > It doesn't even behave consistently as a multiset, since c[k] -= n > is happy to let the value go negative. > > > For sets, > > union and intersection are distributive over each other. > > > Note that this is *not* the case for + and * when used with > > (mathematical) numbers... So in a sense, SETL (which uses + and * > > for union and intersection got the operators wrong. > > But in another sense, it didn't. In Boolean algebra, "and" and "or" > (which also distribute over each other) are often written using the > same notations as multiplication and addition. There's no rule in > mathematics saying that these notations must be distributive in one > direction but not the other. > I guess everybody's high school math(s) class was different. I don't ever recall seeing + and * for boolean OR/AND; we used ∧ and ∨. I learned | and & for set operations only after I learned programming; I think it was in PL/1. But of course it stuck because of C bitwise operators (which are also boolean OR/AND and set operations). This table suggests there's a lot of variety in how these operators are spelled: https://en.wikipedia.org/wiki/List_of_logic_symbols -- --Guido van Rossum (python.org/~guido) ___ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
Re: [Python-ideas] Attribute-Getter Syntax Proposal
Samuel Li wrote: .attribute -> lambda x: x.attribute .method(*args, **kwargs) -> lambda x: x.method(*args, **kwargs) Leading dots can be hard to spot when reading code. Also, I'm not convinced that use cases for this are frequent enough to warrant new syntax. Something akin to this can already be done in simple cases: map(string.upper, some_list) Anything more complicated, such as passing arguments, is probably better expressed with a comprehension. -- Greg ___ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
Re: [Python-ideas] Attribute-Getter Syntax Proposal
> > Rather than using map in this way, I would recommend a list comprehension: Exactly! I really don’t get why folks want to use map() so much when the comprehension syntax is often cleaner and easier. It was added for a reason :-) -CHB ___ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
Re: [Python-ideas] PEP: Dict addition and subtraction
Guido van Rossum wrote: I guess this explains the behavior of removing results <= 0; it makes sense as multiset subtraction, since in a multiset a negative count makes little sense. (Though the name Counter certainly doesn't seem to imply multiset.) It doesn't even behave consistently as a multiset, since c[k] -= n is happy to let the value go negative. For sets, union and intersection are distributive over each other. Note that this is *not* the case for + and * when used with (mathematical) numbers... So in a sense, SETL (which uses + and * > for union and intersection got the operators wrong. But in another sense, it didn't. In Boolean algebra, "and" and "or" (which also distribute over each other) are often written using the same notations as multiplication and addition. There's no rule in mathematics saying that these notations must be distributive in one direction but not the other. -- Greg ___ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
Re: [Python-ideas] Attribute-Getter Syntax Proposal
I just realized it doesn't work properly if the method takes some arguments, so you would actually have to use two different magic objects or something like that, but I guess the point is clear. Am 08.03.2019 um 23:08 schrieb Benedikt Werner: This was actually quite interesting to code, thanks for the idea Jonathan! You can even support "magic.upper()" and "magic.real" at the same time as well as "magic[0]": class MagicClass: NO_ARG = object() @staticmethod def __getattribute__(attr): def method(x=MagicClass.NO_ARG): if x is MagicClass.NO_ARG: return lambda x: getattr(x, attr)() return getattr(x, attr) return method @staticmethod def __getitem__(attr): return lambda x: x[attr] magic = MagicClass() print(list(map(magic.upper(), ["abc", "def"]))) # ['ABC', 'DEF'] print(list(map(magic.real, [1j, 2, 3+4j]))) # [0.0, 2, 3.0] print(list(map(magic[0], ["abc", "def"]))) # ['a', 'd'] You could also use None instead of that NO_ARG thingy, because you most likely won't want to get any attributes of None objects, but that wouldn't produce proper errors incase you do anyways. With metaclasses you propably could also make it work directly on the class without the need of a magic instance. Benedikt Am 08.03.2019 um 19:07 schrieb Jonathan Fine: Hi Samuel Interesting idea, and certainly addresses a real problem, if you find yourself creating lots of lambda expressions. But in my first opinion, not so useful that it merits adding to the syntax of Python. (Even if I never use it, it puts an extra burden on me when scanning Python code. Something that used to look like a syntax error is now valid. That's more work for me.) However, you can already achieve something similar, and perhaps more expressive. It is possible to define an object 'magic' such that fn = magic.upper fn = lambda x: x.upper() are effectively equivalent. And this can be done now. No need for a PEP and a new version of Python. And available for those who have to use some fixed already existing Python versions. I hope you'd be interesting in coding this up yourself. I'd have a limited amount of time to help you, but it would put you on a good learning curve, for fundamentals of the Python object model. ___ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
Re: [Python-ideas] Attribute-Getter Syntax Proposal
On Sat, Mar 9, 2019 at 9:09 AM Benedikt Werner <1benediktwer...@gmail.com> wrote: > > This was actually quite interesting to code, thanks for the idea Jonathan! > > You can even support "magic.upper()" and "magic.real" at the same time > as well as "magic[0]": > > class MagicClass: > NO_ARG = object() > > @staticmethod > def __getattribute__(attr): > def method(x=MagicClass.NO_ARG): > if x is MagicClass.NO_ARG: > return lambda x: getattr(x, attr)() > return getattr(x, attr) > return method > > @staticmethod > def __getitem__(attr): > return lambda x: x[attr] > > magic = MagicClass() > > print(list(map(magic.upper(), ["abc", "def"]))) # ['ABC', 'DEF'] > print(list(map(magic.real, [1j, 2, 3+4j]))) # [0.0, 2, 3.0] > print(list(map(magic[0], ["abc", "def"]))) # ['a', 'd'] > > You could also use None instead of that NO_ARG thingy, because you most > likely won't want to get any attributes of None objects, but that > wouldn't produce proper errors incase you do anyways. > > With metaclasses you propably could also make it work directly on the > class without the need of a magic instance. Rather than using map in this way, I would recommend a list comprehension: print([x.upper() for x in ["abc", "def"]]) print([x.real for x in [1j, 2, 3+4j]]) print([x[0] for x in ["abc", "def"]]) No magic needed. ChrisA ___ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
Re: [Python-ideas] Attribute-Getter Syntax Proposal
This was actually quite interesting to code, thanks for the idea Jonathan! You can even support "magic.upper()" and "magic.real" at the same time as well as "magic[0]": class MagicClass: NO_ARG = object() @staticmethod def __getattribute__(attr): def method(x=MagicClass.NO_ARG): if x is MagicClass.NO_ARG: return lambda x: getattr(x, attr)() return getattr(x, attr) return method @staticmethod def __getitem__(attr): return lambda x: x[attr] magic = MagicClass() print(list(map(magic.upper(), ["abc", "def"]))) # ['ABC', 'DEF'] print(list(map(magic.real, [1j, 2, 3+4j]))) # [0.0, 2, 3.0] print(list(map(magic[0], ["abc", "def"]))) # ['a', 'd'] You could also use None instead of that NO_ARG thingy, because you most likely won't want to get any attributes of None objects, but that wouldn't produce proper errors incase you do anyways. With metaclasses you propably could also make it work directly on the class without the need of a magic instance. Benedikt Am 08.03.2019 um 19:07 schrieb Jonathan Fine: Hi Samuel Interesting idea, and certainly addresses a real problem, if you find yourself creating lots of lambda expressions. But in my first opinion, not so useful that it merits adding to the syntax of Python. (Even if I never use it, it puts an extra burden on me when scanning Python code. Something that used to look like a syntax error is now valid. That's more work for me.) However, you can already achieve something similar, and perhaps more expressive. It is possible to define an object 'magic' such that fn = magic.upper fn = lambda x: x.upper() are effectively equivalent. And this can be done now. No need for a PEP and a new version of Python. And available for those who have to use some fixed already existing Python versions. I hope you'd be interesting in coding this up yourself. I'd have a limited amount of time to help you, but it would put you on a good learning curve, for fundamentals of the Python object model. ___ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Preallocated tuples and dicts for function calls
Hi, what about the idea that the interpreter preallocates and preinitializes the tuples and dicts for function calls where possible when loading a module? Before calling a function then the interpreter would just need to update the items which are dynamic and then call the function. Some examples: msgpack.unpackb(b'\x93\x01\x02\x03', use_list=False, raw=False) The above function call needs a tuple with 1 entry and a dict with 2 entries. All entries are constant. So in this case the interpreter can immediately execute the function call. Without the optimization the interpreter would need to: - create new tuple (allocate memory) - write constant into first tuple index. - create dict (allocate memory) - add key+value - add key+value - call function Another example: foo(bar, 3, 5, arg1=bar1, arg2=True) The above needs a tuple with 3 entries. 2 of them are constant. And a dict with 2 entries. 1 of them is constant. With the optimization: - write bar into first tuple index. - replace first key+value pair in the dict. - call function Without the optimization: - create new tuple (allocate memory) - write bar into first tuple index. - write constant into second tuple index. - write constant into third tuple index. - create dict (allocate memory) - add key+value - add key+value - call function If this idea is possible to implement I assume the function calls would receive a great speed improvment. Best regards, Martin ___ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
Re: [Python-ideas] Left arrow and right arrow operators
On Sat, Mar 9, 2019 at 7:05 AM francismb wrote: > > Hi Oleg, > > On 3/3/19 4:06 PM, Oleg Broytman wrote: > >You cannot create operator ``<-`` because it's currently valid > > syntax: > > > > 3 <- 2 > > > > is equivalent to > > > > 3 < -2 > > Yes, its a good point, but for me it's not the same '<-' and '< -' due > (n)blanks in between. It is may be how now it is, but means that it > needs to be always like this? Isn't Python not already > blank(s)/indentation aware? or it's just a grammar NO GO? > Python permits "3<-2", so this is indeed a no-go. You can easily test this at the interactive interpreter. ChrisA ___ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
Re: [Python-ideas] Left arrow and right arrow operators
Hi Oleg, On 3/3/19 4:06 PM, Oleg Broytman wrote: >You cannot create operator ``<-`` because it's currently valid > syntax: > > 3 <- 2 > > is equivalent to > > 3 < -2 Yes, its a good point, but for me it's not the same '<-' and '< -' due (n)blanks in between. It is may be how now it is, but means that it needs to be always like this? Isn't Python not already blank(s)/indentation aware? or it's just a grammar NO GO? Thanks in advance! --francis ___ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
Re: [Python-ideas] Left arrow and right arrow operators
Hi fhsxfhsx, On 3/4/19 5:56 AM, fhsxfhsx wrote: > Could you explain why do you prefer this operator than `+`? Well yes, because of the asymmetric operation done underneath (merging dicts is not symmetric). The asymmetry is explicit in the symbol. Not implicit from the documentation you need to know/read for + (in the case proposed for dictionaries). Regards, --francis ___ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
Re: [Python-ideas] Left arrow and right arrow operators
Hi Calvin, On 3/4/19 2:09 PM, Calvin Spealman wrote: > I don't like the idea of arrows in both directions when you can just swap > the operands instead Well you saw just to examples of contexts (dict and bool). Could you imagine a context where swapping cannot be done and thus there is a need for left- and right arrow? Thanks in advance! --francis ___ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
Re: [Python-ideas] Left arrow and right arrow operators
Hi Todd, On 3/4/19 2:18 PM, Todd wrote: > What is the operator supposed to do? this should depend on what you want to do, the type, the context. How to you would want to use it ? do you see a context where the symbols make meaning to you? Thanks in advance! --francis ___ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
Re: [Python-ideas] PEP: Dict addition and subtraction
On 2019-03-08 16:55, Guido van Rossum wrote: [snip] If we were to use "|" and "&" for dict "union" and "intersection", the mutual distributive properties will hold. Since "|" (especially "|=") *is* suitable for "update", I think we should reserve "+" for some future commutative extension. One argument is that sets have an update() method aliased to "|=", so this makes it more reasonable to do the same for dicts, which also have a. update() method, with similar behavior (not surprising, since sets were modeled after dicts). [snip] One way to think of it is that a dict is like a set, except that each of its members has an additional associated value. ___ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
Re: [Python-ideas] Attribute-Getter Syntax Proposal
On Fri, Mar 8, 2019 at 8:57 AM Samuel Li wrote: > Don't know if this has been suggested before. Instead of writing something > like > > >>> map(lambda x: x.upper(), ['a', 'b', 'c']) > > I suggest this syntax: > >>> map(.upper(), ['a', 'b', 'c']) > Do note you get the same results with `map(str.upper, ['a', 'b', 'c'])`. > > This would also work for attributes: > >>> map(.real, [1j, 2, 3+4j]) > > Internally, this would require translating > > .attribute -> lambda x: x.attribute > > and > > .method(*args, **kwargs) -> lambda x: x.method(*args, **kwargs) > > This translation should only take place where a "normal" attribute lookup > makes no sense (throws a SyntaxError); i.e. foo.bar works as before, > foo(.bar) would previously throw a SyntaxError, so the new syntax applies > and the .bar is interpreted as an attrgetter. > > This is of course only a cosmetic improvement over operator.attrgetter and > operator.methodcaller, but I think it's nice enough to warrant > consideration. > > If you like this idea or think it's utter garbage, feel free to discuss. > Sorry, I'm personally not a fan as it looks like you have a typo in your code, e.g. you left of 'x' or something before the dot. ___ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
Re: [Python-ideas] Attribute-Getter Syntax Proposal
Hi Samuel Interesting idea, and certainly addresses a real problem, if you find yourself creating lots of lambda expressions. But in my first opinion, not so useful that it merits adding to the syntax of Python. (Even if I never use it, it puts an extra burden on me when scanning Python code. Something that used to look like a syntax error is now valid. That's more work for me.) However, you can already achieve something similar, and perhaps more expressive. It is possible to define an object 'magic' such that fn = magic.upper fn = lambda x: x.upper() are effectively equivalent. And this can be done now. No need for a PEP and a new version of Python. And available for those who have to use some fixed already existing Python versions. I hope you'd be interesting in coding this up yourself. I'd have a limited amount of time to help you, but it would put you on a good learning curve, for fundamentals of the Python object model. -- Jonathan ___ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Attribute-Getter Syntax Proposal
Don't know if this has been suggested before. Instead of writing something like >>> map(lambda x: x.upper(), ['a', 'b', 'c']) I suggest this syntax: >>> map(.upper(), ['a', 'b', 'c']) This would also work for attributes: >>> map(.real, [1j, 2, 3+4j]) Internally, this would require translating .attribute -> lambda x: x.attribute and .method(*args, **kwargs) -> lambda x: x.method(*args, **kwargs) This translation should only take place where a "normal" attribute lookup makes no sense (throws a SyntaxError); i.e. foo.bar works as before, foo(.bar) would previously throw a SyntaxError, so the new syntax applies and the .bar is interpreted as an attrgetter. This is of course only a cosmetic improvement over operator.attrgetter and operator.methodcaller, but I think it's nice enough to warrant consideration. If you like this idea or think it's utter garbage, feel free to discuss. ___ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
Re: [Python-ideas] PEP: Dict addition and subtraction
On Thu, Mar 7, 2019 at 9:12 PM Stephen J. Turnbull < turnbull.stephen...@u.tsukuba.ac.jp> wrote: > Ka-Ping Yee writes: > > On Wed, Mar 6, 2019 at 4:01 PM Chris Angelico wrote: > > > > But adding dictionaries is fundamentally *useful*. It is expressive. > > > > It is useful. It's just that + is the wrong name. > > First, let me say that I prefer ?!'s position here, so my bias is made > apparent. I'm also aware that I have biases so I'm sympathetic to > those who take a different position. > TBH, I am warming up to "|" as well. > Rather than say it's "wrong", let me instead point out that I think > it's pragmatically troublesome to use "+". I can think of at least > four interpretations of "d1 + d2" > > 1. update > 2. multiset (~= Collections.Counter addition) > I guess this explains the behavior of removing results <= 0; it makes sense as multiset subtraction, since in a multiset a negative count makes little sense. (Though the name Counter certainly doesn't seem to imply multiset.) > 3. addition of functions into the same vector space (actually, a > semigroup will do ;-), and this is the implementation of > Collections.Counter > 4. "fiberwise" set addition (ie, of functions into relations) > > and I'm very jet-lagged so I may be missing some. > > There's also the fact that the operations denoted by "|" and "||" are > often implemented as "short-circuiting", and therefore not > commutative, while "+" usually is (and that's reinforced for > mathematicians who are trained to think of "+" as the operator for > Abelian groups, while "*" is a (possibly) non-commutative operator. I > know commutativity of "+" has been mentioned before, but the > non-commutativity of "|" -- and so unsuitability for many kinds of > dict combination -- hasn't been emphasized before IIRC. > I've never heard of single "|" being short-circuiting. ("||" of course is infamous for being that in C and most languages derived from it.) And "+" is of course used for many non-commutative operations in Python (e.g. adding two lists/strings/tuples together). It is only *associative*, a weaker requirement that just says (A + B) + C == A + (B + C). (This is why we write A + B + C, since the grouping doesn't matter for the result.) Anyway, while we're discussing mathematical properties, and since SETL was briefly mentioned, I found an interesting thing in math. For sets, union and intersection are distributive over each other. I can't type the operators we learned in high school, so I'll use Python's set operations. We find that A | (B & C) == (A | B) & (A | C). We also find that A & (B | C) == (A & B) | (A & C). Note that this is *not* the case for + and * when used with (mathematical) numbers: * distributes over +: a * (b + c) == (a * b) + (a * c), but + does not distribute over *: a + (b * c) != (a + b) * (a + c). So in a sense, SETL (which uses + and * for union and intersection) got the operators wrong. Note that in Python, + and * for sequences are not distributive this way, since (A + B) * n is not the same as (A * n) + (B * n). OTOH A * (n + m) == A * n + A * m. (Assuming A and B are sequences of the same type, and n and m are positive integers.) If we were to use "|" and "&" for dict "union" and "intersection", the mutual distributive properties will hold. > Since "|" (especially "|=") *is* suitable for "update", I think we > should reserve "+" for some future commutative extension. > One argument is that sets have an update() method aliased to "|=", so this makes it more reasonable to do the same for dicts, which also have a. update() method, with similar behavior (not surprising, since sets were modeled after dicts). > In the spirit of full disclosure: > Of these, 2 is already implemented and widely used, so we don't need > to use dict.__add__ for that. I've never seen 4 in the mathematical > literature (union of relations is not the same thing). 3, however, is > very common both for mappings with small domain and sparse > representation of mappings with a default value (possibly computed > then cached), and "|" is not suitable for expressing that sort of > addition (I'm willing to say it's "wrong" :-). > -- --Guido van Rossum (python.org/~guido) ___ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
Re: [Python-ideas] PEP: Dict addition and subtraction
Hello, I've just read your PEP 585 draft and have some questions. When you say " Like the merge operator and list concatenation, the difference operator requires both operands to be dicts, while the augmented version allows any iterable of keys. >>> d - {'spam', 'parrot'} Traceback (most recent call last): ... TypeError: cannot take the difference of dict and set >>> d -= {'spam', 'parrot'} >>> print(d) {'eggs': 2, 'cheese': 'cheddar'} >>> d -= [('spam', 999)] >>> print(d) {'spam': 999, 'eggs': 2, 'cheese': 'cheddar', 'aardvark': 'Ethel'} " The option d -= {'spam', 'parrot'} where parrot does not exist in the d dict, will raise an exception (eg. KeyNotFound) or be silent? The option d -= [('spam', 999)] should remove the pair from the dict, correct? But the print that follows still shows it there. It's a mistake or am I missing something? Best regards, João Matos smime.p7s Description: S/MIME Cryptographic Signature ___ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
Re: [Python-ideas] Dict joining using + and +=
> Counter also uses +/__add__ for a similar behavior. > > >>> c = Counter(a=3, b=1) > >>> d = Counter(a=1, b=2) > >>> c + d # add two counters together: c[x] + d[x] > Counter({'a': 4, 'b': 3}) > > At first I worried that changing base dict would cause confusion for the > subclass, but Counter seems to share the idea that update and + are synonyms. Counter is a moot analogy. Counter's + and - operators follow the rules of numbers addition and subtraction: >>> c = Counter({"a": 1}) >>> c + Counter({"a": 5}) Counter({'a': 6}) >>> c + Counter({"a": 5}) - Counter({"a": 4}) Counter({'a': 2}) Which also means that in most cases (c1 + c2) - c2 == c1 which is not something you would expect with the suggested "dictionary addition" operation. As a side note, this is not true in general for Counters because of how subtraction handles 0. E.g. >>> c0 = Counter({"a": 0}) >>> c1 = Counter({"a": 1}) >>> (c0 + c1) - c1 Counter() >>> (c0 + c1) - c1 == c0 False --- The current intuition of how + and - work don't apply literally to this suggestion: 1) numeric types are their own story 2) most built-in sequences imply concatenation for + and have no subtraction 3) numpy-like arrays behave closer to numbers 4) Counters mimic numbers in some ways and while addition reminds of concatenation (but order is not relevant) they also have subtraction 5) sets have difference which is probably the closest you expect from dict subtraction, but no + operator --- I understand the arguments against a | operator for dicts but I don't entirely agree with them. dict is obviously a different type of object than all the others I've mentioned, even mathematically, and there is no clear precedent. If sets happened to maintain insertion order, like dicts after 3.6/3.7, I would expect the union operator to also preserve the order. Before 3.6 we probably would have seen dicts as closer to sets from that point of view, and this suggested addition as closer to set union. The question of symmetry ({"a": 1} + {"a": 2}) is an important one and I would consider not enforcing one resolution in PEP 584, and instead leave this undefined (i.e. in the resulting dict, the value could be either 1 or 2, or just completely undefined to also be compatible with Counter-like semantics in the same PEP). This is something to consider carefully if the plan is to make the new operators part of Mapping. It's not obvious that all mappings should implement this the same way, and a survey of what is being done by other implementation of Mappings would be useful. On the other hand leaving it undefined might make it harder to standardize it later, once other implementations have defined their own behavior. This question is probably on its own a valid argument against the proposal. When it comes to dicts (and not Mappings in general) {**d1, **d2} or d.update() already have clearly-defined semantics. The new proposal for a merge() operation might be more useful. The added value would be the ability to add two mappings regardless of concrete type. But it's with Mappings in general that this proposal is the most problematic. On the other hand the subtraction operator is probably less controversial and immediately useful (the idiom to remove keys from a dictionary is not obvious). ___ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
Re: [Python-ideas] Suggestions: dict.flow_update and dict.__add__
I've just learnt something new. Look at >>> from operator import iadd >>> lst = [1, 2, 3] >>> iadd(lst, 'hi') [1, 2, 3, 'h', 'i'] >>> lst [1, 2, 3, 'h', 'i'] This shows that the proposals dict.flow_update and dict.__iadd__ are basically the same. (I think this is quite important for understanding the attraction of fluent programming. We ALREADY like and use it, in the form of augmented assignment of mutables.) This also shows that combined = defaults.copy() combined.update(options) could, if the proposal is accepted, be written as defaults.copy().__iadd__(options) I got the idea from the withdrawn PEP (thank you, Nick Coghlan, for writing it): PEP 577 -- Augmented Assignment Expressions https://www.python.org/dev/peps/pep-0577/ -- Jonathan ___ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/