Ampersand operator for strings
Tl;dr: Join strings together with exactly one space between non-blank text where they join. I propose a meaning for s1 & s2 where s1 and s2 are strings. Namely, that it should be equivalent to s1.rstrip() + (' ' if (s1.strip() and s2.strip()) else '') + s2.lstrip() Informally, this will join the two strings together with exactly one space between the last non-blank text in s1 and the first non-blank text in s2. Example: " bar " & " foo " == " bar foo " This operator is associative, so there is no ambiguity in expressions such as s1 & s2 & s3 There *is* a possible ambiguity in expressions such as s1 & s2 + s3 where the relative precedence of `&` and `+` matters when s2 consists solely of white space. E.g. " A " & " " + " C" would evaluate to " A C" not to " A C" because `+` has a higher precedence than '&'. Utility: In decades of experience with another language which had such an operator (spelt differently) I have frequently found it useful for constructing human-readable output (e.g. log output, debug/error messages, on-screen labels). Cognitive burden: This would of course be one more thing to learn. But I suggest that it is fairly intuitive that s1 + s2 s1 & s2 both suggest that two strings are being combined in some way. Bars to overcome: This change would require no fundamental change to Python; just adding an `__and__ function to the str class. Backward compatibility: Given that `str1 & str2` currently raises TypeError, this change would be close to 100% backward-compatible. Alternative meanings: As far as I know nobody has ever suggested an alternative meaning for `&` on strings. Bikeshedding: (1) I don't think it is important for the utility of this change whether `&` strips off all whitespace, or just spaces. I think it is better if it strips off all whitespace, so that it can be understood as working similarly to strip(). (2) The definition could be simplified to s1.rstrip() + ' ' + s2.lstrip() (leave an initial/final space when one string is whitespace only). Again the operator would be associative. Again I don't think this is important. Rob Cliffe
Is it really that much longer to write `f"{s1} {s2}"` when you want that? Maybe a couple characters more total, but once you are in an f-string, you can also do a zillion other things at the same time. On Sun, Mar 5, 2023 at 10:42 PM Rob Cliffe via Python-ideas < python-ideas@python.org> wrote:
Tl;dr: Join strings together with exactly one space between non-blank text where they join.
I propose a meaning for s1 & s2 where s1 and s2 are strings. Namely, that it should be equivalent to s1.rstrip() + (' ' if (s1.strip() and s2.strip()) else '') + s2.lstrip() Informally, this will join the two strings together with exactly one space between the last non-blank text in s1 and the first non-blank text in s2. Example: " bar " & " foo " == " bar foo "
This operator is associative, so there is no ambiguity in expressions such as s1 & s2 & s3 There *is* a possible ambiguity in expressions such as s1 & s2 + s3 where the relative precedence of `&` and `+` matters when s2 consists solely of white space. E.g. " A " & " " + " C" would evaluate to " A C" not to " A C" because `+` has a higher precedence than '&'.
Utility: In decades of experience with another language which had such an operator (spelt differently) I have frequently found it useful for constructing human-readable output (e.g. log output, debug/error messages, on-screen labels).
Cognitive burden: This would of course be one more thing to learn. But I suggest that it is fairly intuitive that s1 + s2 s1 & s2 both suggest that two strings are being combined in some way.
Bars to overcome: This change would require no fundamental change to Python; just adding an `__and__ function to the str class.
Backward compatibility: Given that `str1 & str2` currently raises TypeError, this change would be close to 100% backward-compatible.
Alternative meanings: As far as I know nobody has ever suggested an alternative meaning for `&` on strings.
Bikeshedding: (1) I don't think it is important for the utility of this change whether `&` strips off all whitespace, or just spaces. I think it is better if it strips off all whitespace, so that it can be understood as working similarly to strip(). (2) The definition could be simplified to s1.rstrip() + ' ' + s2.lstrip() (leave an initial/final space when one string is whitespace only). Again the operator would be associative. Again I don't think this is important.
Rob Cliffe _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/66XP7G... Code of Conduct: http://python.org/psf/codeofconduct/
-- The dead increasingly dominate and strangle both the living and the not-yet born. Vampiric capital and undead corporate persons abuse the lives and control the thoughts of homo faber. Ideas, once born, become abortifacients against new conceptions.
On Mon, Mar 6, 2023 at 12:51 AM David Mertz, Ph.D. <david.mertz@gmail.com> wrote:
Is it really that much longer to write `f"{s1} {s2}"` when you want that?
As for being that much longer: yes it is. The more important factor is, I think, the increase in complexity + readabiity for default strings is worth it in this case. One nice thing to think about might be how to make string subclassing to be more useful - so this kind of thing could be done for whoever needs it in one more idiomatic project. The drawback is how cumbersome it is to instantiate a string subclass compared to a string literal. (I just got an idea, but it would be too offtopic here - if I think it is worth, I will post it in a new thread later)
Maybe a couple characters more total, but once you are in an f-string, you can also do a zillion other things at the same time.
On Sun, Mar 5, 2023 at 10:42 PM Rob Cliffe via Python-ideas < python-ideas@python.org> wrote:
Tl;dr: Join strings together with exactly one space between non-blank text where they join.
I propose a meaning for s1 & s2 where s1 and s2 are strings. Namely, that it should be equivalent to s1.rstrip() + (' ' if (s1.strip() and s2.strip()) else '') + s2.lstrip() Informally, this will join the two strings together with exactly one space between the last non-blank text in s1 and the first non-blank text in s2. Example: " bar " & " foo " == " bar foo "
This operator is associative, so there is no ambiguity in expressions such as s1 & s2 & s3 There *is* a possible ambiguity in expressions such as s1 & s2 + s3 where the relative precedence of `&` and `+` matters when s2 consists solely of white space. E.g. " A " & " " + " C" would evaluate to " A C" not to " A C" because `+` has a higher precedence than '&'.
Utility: In decades of experience with another language which had such an operator (spelt differently) I have frequently found it useful for constructing human-readable output (e.g. log output, debug/error messages, on-screen labels).
Cognitive burden: This would of course be one more thing to learn. But I suggest that it is fairly intuitive that s1 + s2 s1 & s2 both suggest that two strings are being combined in some way.
Bars to overcome: This change would require no fundamental change to Python; just adding an `__and__ function to the str class.
Backward compatibility: Given that `str1 & str2` currently raises TypeError, this change would be close to 100% backward-compatible.
Alternative meanings: As far as I know nobody has ever suggested an alternative meaning for `&` on strings.
Bikeshedding: (1) I don't think it is important for the utility of this change whether `&` strips off all whitespace, or just spaces. I think it is better if it strips off all whitespace, so that it can be understood as working similarly to strip(). (2) The definition could be simplified to s1.rstrip() + ' ' + s2.lstrip() (leave an initial/final space when one string is whitespace only). Again the operator would be associative. Again I don't think this is important.
Rob Cliffe _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/66XP7G... Code of Conduct: http://python.org/psf/codeofconduct/
-- The dead increasingly dominate and strangle both the living and the not-yet born. Vampiric capital and undead corporate persons abuse the lives and control the thoughts of homo faber. Ideas, once born, become abortifacients against new conceptions. _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/M7H3VZ... Code of Conduct: http://python.org/psf/codeofconduct/
On 02.03.2023 18:27, Rob Cliffe via Python-ideas wrote:
Tl;dr: Join strings together with exactly one space between non-blank text where they join.
I propose a meaning for s1 & s2 where s1 and s2 are strings. Namely, that it should be equivalent to s1.rstrip() + (' ' if (s1.strip() and s2.strip()) else '') + s2.lstrip() Informally, this will join the two strings together with exactly one space between the last non-blank text in s1 and the first non-blank text in s2. Example: " bar " & " foo " == " bar foo "
I don't find these semantics particularly intuitive. Python already has the + operator for concatenating strings and this doesn't apply any stripping. If you're emphasizing on joining words with single space delimiters, then the usual: def join_words(list_of_words) return ' '.join([x.strip() for x in list_of_words]) works much better. You can also apply this recursively, if needed, or add support for list_of_phrases (first splitting these into a list_of_words). The advantage of join_words() is that it's easy to understand and applies stripping in a concise way. I use such helpers all the time. -- Marc-Andre Lemburg eGenix.com Professional Python Services directly from the Experts (#1, Mar 06 2023)
Python Projects, Coaching and Support ... https://www.egenix.com/ Python Product Development ... https://consulting.egenix.com/
::: We implement business ideas - efficiently in both time and costs ::: eGenix.com Software, Skills and Services GmbH Pastor-Loeh-Str.48 D-40764 Langenfeld, Germany. CEO Dipl.-Math. Marc-Andre Lemburg Registered at Amtsgericht Duesseldorf: HRB 46611 https://www.egenix.com/company/contact/ https://www.malemburg.com/
On Mon, Mar 06, 2023 at 10:33:26AM +0100, Marc-Andre Lemburg wrote:
def join_words(list_of_words) return ' '.join([x.strip() for x in list_of_words])
That's not Rob's suggestion either. Rob's suggestion is an operator which concats two substrings with exactly one space between them, without stripping leading or trailing whitespace of the result. Examples: a = "\nHeading:" b = "Result\n\n" a & b would give "\nHeading: Result\n\n" s = " my hovercraft\n" t = " is full of eels\n" s & t would give " my hovercraft is full of eels\n" I find the concept is very easy to understand: "concat with exactly one space between the operands". But I must admit I'm struggling to think of cases where I would use it. I like the look of the & operator for concatenation, so I want to like this proposal. But I think I will need to see real world code to understand when it would be useful. -- Steve
On 06.03.2023 11:33, Steven D'Aprano wrote:
On Mon, Mar 06, 2023 at 10:33:26AM +0100, Marc-Andre Lemburg wrote:
def join_words(list_of_words) return ' '.join([x.strip() for x in list_of_words])
That's not Rob's suggestion either.
I know, but as I mentioned, I use the above often, whereas I find Rob's definition not very intuitive or useful.
Rob's suggestion is an operator which concats two substrings with exactly one space between them, without stripping leading or trailing whitespace of the result.
Examples:
a = "\nHeading:" b = "Result\n\n" a & b
would give "\nHeading: Result\n\n"
s = " my hovercraft\n" t = " is full of eels\n" s & t
would give " my hovercraft is full of eels\n"
I find the concept is very easy to understand: "concat with exactly one space between the operands". But I must admit I'm struggling to think of cases where I would use it.
I like the look of the & operator for concatenation, so I want to like this proposal. But I think I will need to see real world code to understand when it would be useful.
-- Marc-Andre Lemburg eGenix.com Professional Python Services directly from the Experts (#1, Mar 06 2023)
Python Projects, Coaching and Support ... https://www.egenix.com/ Python Product Development ... https://consulting.egenix.com/
::: We implement business ideas - efficiently in both time and costs ::: eGenix.com Software, Skills and Services GmbH Pastor-Loeh-Str.48 D-40764 Langenfeld, Germany. CEO Dipl.-Math. Marc-Andre Lemburg Registered at Amtsgericht Duesseldorf: HRB 46611 https://www.egenix.com/company/contact/ https://www.malemburg.com/
On Mon, Mar 6, 2023 at 7:37 AM Steven D'Aprano <steve@pearwood.info> wrote:
(...)
I like the look of the & operator for concatenation, so I want to like this proposal. But I think I will need to see real world code to understand when it would be useful.
I'd say we paint the shed blue. I mean - maybe "|" is more pleasant when thinking about concatenation.
-- Steve
Steven D'Aprano writes:
I like the look of the & operator for concatenation, so I want to like this proposal. But I think I will need to see real world code to understand when it would be useful.
I have to second that motion. Pretty much any time I'm constructing lines containing variable text, each string value arrives stripped and I far more often want padding of variable width values rather than space compression. I admit that I use M-SPC (aka just-one-space) lot in Emacsen, but I can't recall wanting it in a program in any language.
On 06/03/2023 15:49, Stephen J. Turnbull wrote:
Steven D'Aprano writes:
I like the look of the & operator for concatenation, so I want to like this proposal. But I think I will need to see real world code to understand when it would be useful.
I have to second that motion. Pretty much any time I'm constructing lines containing variable text, each string value arrives stripped and I far more often want padding of variable width values rather than space compression. Understood. But perhaps in (the tiny minority? of) cases where you *don't* want padding, you would like single space separators? 😁 Perhaps where you're not laying out a table, but constructing a human-readable string? So s1 + ' ' + s2 + ' ' + s3 or ' '.join((s1, s3, s3)) would become s1 & s2 & s3 saving you a bit of typing. Just sayin'. Best wishes Rob Cliffe
I admit that I use M-SPC (aka just-one-space) lot in Emacsen, but I can't recall wanting it in a program in any language. _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/DZXQJ4... Code of Conduct: http://python.org/psf/codeofconduct/
Rob Cliffe writes:
Perhaps where you're not laying out a table,
I'm an economist, laying out tables is what I do. :-) Getting serious:
but constructing a human-readable string?� So ��� s1 + ' ' + s2 + ' ' + s3 or ��� ' '.join((s1, s3, s3)) would become ��� s1 & s2 & s3 saving you a bit of typing.� Just sayin'.
str '+' has long been quite rare in my coding. str concatenation is almost never in an inner loop, or slighly more complex formatting is the point. f-strings and .format save you the type conversion to str. So I don't find that occasional saving at all interesting. A vanishingly small number of my str constructions involve only strs with trivial formatting. What interests me about the proposal is the space-collapsing part, which a naive f-string would do incorrectly if, say, s2 == '' or s3 == '\t\t\ttabs to the left of me'. But where does this space-surrounded str data come from? Steve
Rob Cliffe writes:
Perhaps where you're not laying out a table,
I'm an economist Oh goody! *Please* tell me what our Government needs to do to grow the UK economy and curb inflation. I'll inform my MP immediately. 😁 Seriously though ... , laying out tables is what I do. :-) Getting serious:
but constructing a human-readable string? So s1 + ' ' + s2 + ' ' + s3 or ' '.join((s1, s3, s3)) would become s1 & s2 & s3 saving you a bit of typing. Just sayin'.
str '+' has long been quite rare in my coding. str concatenation is almost never in an inner loop, or slighly more complex formatting is the point. f-strings and .format save you the type conversion to str. So I don't find that occasional saving at all interesting. A vanishingly small number of my str constructions involve only strs with trivial formatting.
What interests me about the proposal is the space-collapsing part, which a naive f-string would do incorrectly if, say, s2 == '' or s3 == '\t\t\ttabs to the left of me'. But where does this space-surrounded str data come from? I would say: Very often in real-life cases it doesn't. So using '&' would be equivalent to stripping the strings and applying ' '.join(). And more concise, and IMHO more readable (albeit, as Mr Berlier helpfully informs us, less efficient 😁). But I can imagine cases where the leftmost string starts with indentation to start a paragraph (or to correctly indent Python code), which you want to preserve. Or perhaps even to make it start in the correct column of a table, ha-ha. As for trailing whitespace in the rightmost string ... Hm, I can't think of a use case ATM. I just thought it would be nice to make the operation symmetrical. s1 & s2 *could* be defined as equivalent to (s1.rstrip() + ' ' + s2.lstrip()).rstrip() (and it would still be associative). Would this be practicality beating
On 07/03/2023 07:26, Stephen J. Turnbull wrote: purity, or a hideous symmetry breaking? I didn't highlight it before, so let me take the opportunity now: One of the examples I listed shows another use case: constructing an operating system command and ensuring that the parameters are separated by (at least) one space. Bear with me while I repeat it: Lib\site-packages\numpy\distutils\system_info.py:2677: cmd = config_exe + ' ' + self.append_config_exe + ' ' + option cmd = config_exe & self.append_config_exe & option Best wishes Rob Cliffe
Steve
Bikeshedding: 1) I forgot to mention whether the '&' operator should apply to byte strings as well as to strings. I propose that it should (some supporting examples below). 2) Joao suggested spelling the operator '|'. But for me: '|' suggests "or" while '&' suggests "and" and is a more intuitive choice for some kind of concatenation. On 06/03/2023 10:33, Steven D'Aprano wrote:
I find the concept is very easy to understand: "concat with exactly one space between the operands". But I must admit I'm struggling to think of cases where I would use it. Well, there are use cases for print() separating its operands with single spaces (by default). So one might guess that something similar would be useful when constructing strings. But read on, Gentle Reader ...
I like the look of the & operator for concatenation, so I want to like this proposal. But I think I will need to see real world code to understand when it would be useful.
Quite right, Steven. (By the way, thanks for reading my suggestion carefully, as you obviously did.) Below I list some examples from the 3.8.3 stdlib and how (I think) they could be rewritten. (Disclosure: I have selected the examples I found which I think are most convincing. Then again, I may have missed some.) I say "I think" because to be 100% sure (rather than 90%+ sure) in all cases would sometimes need a thorough analysis of the values that parts of an expression could (reasonably) take: specifically, whether some could be an empty string or all whitespace and what would happen if they were. Often in practice these cases can be disregarded or are unimportant. And of course the code author should know all about these cases. Arguably, good examples are *under-represented* in the stdlib, because '&' will more often be useful in throw-away diagnostic code (which is all about human-readable text) than in production code. Lib\site-packages\numpy\distutils\system_info.py:2677: cmd = config_exe + ' ' + self.append_config_exe + ' ' + option cmd = config_exe & self.append_config_exe & option Lib\site-packages\wx\lib\masked\maskededit.py:3592: newstr = value[:self._signpos] + ' ' + value[self._signpos+1:-1] + ' ' newstr = value[:self._signpos] & value[self._signpos+1:-1] + ' ' Lib\site-packages\wx\lib\masked\maskededit.py:4056: text = text[:self._signpos] + ' ' + text[self._signpos+1:self._right_signpos] + ' ' + text[self._right_signpos+1:] text = text[:self._signpos] & text[self._signpos+1:self._right_signpos] & text[self._right_signpos+1:] Lib\distutils\sysconfig.py:212: ldshared = ldshared + ' ' + os.environ['LDFLAGS'] ldshared = ldshared & os.environ['LDFLAGS'] There are 6 more similar examples in the same module. The same 7 are in Lib\site-packages\setuptools\_distutils\sysconfig.py. Lib\site-packages\numpy\lib\tests\test_io.py:328-330: assert_equal(c.readlines(), [asbytes((fmt + ' ' + fmt + '\n') % (1, 2)), asbytes((fmt + ' ' + fmt + '\n') % (3, 4))]) assert_equal(c.readlines(), [asbytes((fmt & fmt + '\n') % (1, 2)), 2)), asbytes((fmt & fmt + '\n') % (3, 4))]) Lib\site-packages\numpy\f2py\crackfortran.py:1068: t = typespattern[0].match(m.group('before') + ' ' + name) t = typespattern[0].match(m.group('before') & name) Lib\site-packages\twisted\mail\imap4.py:3606: raise IllegalServerResponse('(' + k + ' '+ status[k] + '): ' + str(e)) raise IllegalServerResponse('(' + k & status[k] + '):' & str(e)) Lib\site-packages\twisted\runner\procmon.py:424-426: return ('<' + self.__class__.__name__ + ' ' + ' '.join(l) + '>') return ('<' + self.__class__.__name__ & ' '.join(l) + '>') Lib\site-packages\wx\lib\pydocview.py:3028: label = '&' + str(i + 1) + ' ' + frame.GetTitle() label = '&' + str(i + 1) & frame.GetTitle() Lib\test\test_pyexpat.py:90-91: self.out.append('Start element: ' + repr(name) + ' ' + sortdict(attrs)) self.out.append('Start element:' & repr(name) & sortdict(attrs)) Lib\test\test_pyexpat.py:102: self.out.append('PI: ' + repr(target) + ' ' + repr(data)) self.out.append('PI:' & repr(target) & repr(data)) Lib\test\test_pyexpat.py:105: self.out.append('NS decl: ' + repr(prefix) + ' ' + repr(uri)) self.out.append('NS decl:' & repr(prefix) & repr(uri)) In the above 3 examples, it is not necessary to replace the first '+' by '&', but I think it reads better to use the same operator both times. (And of course it saves 1 (space) character. 😁) Similarly in some other examples. Lib\site-packages\win32\Demos\security\sspi\fetch_url.py:57: h.putheader('Authorization', auth_scheme + ' ' + auth) h.putheader('Authorization', auth_scheme & auth) Tools\scripts\which.py:51: sts = os.system('ls ' + longlist + ' ' + filename) sts = os.system('ls' & longlist & filename) Less obviously: Lib\site-packages\pycparser\c_generator.py:406-407: nstr = '* %s%s' % (' '.join(modifier.quals), ' ' + nstr if nstr else '') nstr = '*' & ' '.join(modifier.quals) & nstr Examples where (I think) '&' could be applied to byte strings: Lib\site-packages\twisted\conch\ssh\keys.py:1279: return (self.sshType() + b' ' + b64Data + b' ' + comment).strip() return (self.sshType() & b64Data & comment).strip() Lib\site-packages\reportlab\pdfbase\pdfmetrics.py:391: text = text + b' ' + bytes(str(self.widths[i]),'utf8') text = text & + bytes(str(self.widths[i]),'utf8') Lib\site-packages\twisted\mail\pop3.py:326: yield intToBytes(i) + b' ' + intToBytes(size) + b'\r\n' yield intToBytes(i) & intToBytes(size) + b'\r\n' Lib\site-packages\twisted\mail\pop3.py:367: yield intToBytes(i + 1) + b' ' + uid + b'\r\n' yield intToBytes(i + 1) & uid + b'\r\n' Lib\site-packages\twisted\mail\pop3client.py:929: return self.sendShort(b'APOP', username + b' ' + digest) return self.sendShort(b'APOP', username & + digest) Lib\site-packages\twisted\mail\pop3client.py:1193-1194: return self._consumeOrAppend(b'TOP', idx + b' ' + intToBytes(lines), consumer, _dotUnquoter) return self._consumeOrAppend(b'TOP', idx & intToBytes(lines), consumer, _dotUnquoter) Lib\site-packages\twisted\mail\smtp.py:1647: r.append(c + b' ' + b' '.join(v)) r.append(c & b' '.join(v)) Lib\site-packages\twisted\mail\_cred.py:33: return self.user + b' ' + response.encode('ascii') return self.user & response.encode('ascii') Lib\site-packages\twisted\web\test\test_proxy.py:233: lines = [b"HTTP/1.0 " + str(code).encode('ascii') + b' ' + message] lines = [b"HTTP/1.0" & str(code).encode('ascii') & message] There are many examples (too many to list) where '&' could be used but would not add a great deal of value and its use or non-use would be largely a matter of taste. (It would be nice if there were always "One Obvious Way To Do It", but in the real world different tools sometimes overlap in their areas of application.) Some would doubtless find it: Pointless Obscure Of course (like any new feature) it *would* be more obscure - until we got used to it! 😁 Others might welcome (in appropriate use cases): The guarantee that the result string contains one and only one space between its textual parts, even when the first/second operand of '&' contains (unexpectedly?) trailing/leading whitespace. This guarantee making the code, in a way, *more* explicit. An ampersand being more visible than a leading/trailing space inside string quotes (as I am finding out the hard way, proof-reading this e-mail!🙁). (or even) Saving a few characters. (Wash your mouth out with soap, Rob! 😬) A few reasonably representative examples: Lib\cgitb.py:106: pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable pyver = 'Python' & sys.version.split()[0] + ':' & sys.executable Lib\ftplib.py:289: cmd = 'PORT ' + ','.join(bytes) cmd = 'PORT' & ','.join(bytes) Lib\site-packages\pythonwin\pywin\tools\browser.py:182: return str(self.name) + ' (Instance of class ' + str(self.myobject.__class__.__name__) + ')' return str(self.name) & '(Instance of class' & str(self.myobject.__class__.__name__) + ')' Lib\site-packages\pythonwin\pywin\framework\scriptutils.py:564: win32ui.SetStatusText('Failed to ' + what + ' - ' + str(details) ) win32ui.SetStatusText('Failed to' & what & '-' & str(details) ) Personally, I think that examples such as the last, where multiple components are all joined with '&', are ones that particularly gain from increased clarity and reduced clutter. YMMV. Finally: how I might rewrite in Python a sample fragment from my own code in a different language: VehDesc.SetLabel(Vehicle.Reg_No & Vehicle.Make & Vehicle.Type & Vehicle.Colour) Best wishes Rob Cliffe
I'm -1 on this. You can easily make a helper that achieves the desired syntax. Presenting "human readable data" isn't just about collapsing spaces, and having your own helper means that you can adjust the formatting to your specific use case if needed (for example with a different separator). from typing import Self class StripJoin: def __init__(self, value: str = "") -> None: self.value = value def __and__(self, other: str) -> Self: other = other.strip() separator = bool(self.value and other) * " " return StripJoin(f"{self.value}{separator}{other}") def __str__(self) -> str: return self.value j = StripJoin() print(j & " foo " & " bar " & " something ") # Output: "foo bar something" The example above is more efficient than a possible implementation directly on the str builtin as it doesn't strip the left side over and over. However it still incurs repeated allocations and encourages a pattern that performs badly in loops. With a lot of input you should probably accumulate the stripped strings in a list and join them all at once. In any case I recommend reaching out for a library like Rich (https://github.com/Textualize/rich) if you care about formatting the output of your program nicely.
I agree. This behavior is too specialized to be implemented as an operator. + is IME so infrequently used on python strings that we should take caution when proposing new binary string operators. Two strings to concat, maybe; three, possibly; four or more, and I reach for join() or f-strings or anything else. And if we are just joining two or three strings, that is readable right now as str1.rstrip() + ' ' + str2.lstrip(). A solution that is as extensible as join, no need for operators or subclasses: def connect(iterable, /): it = iter(iterable) first = next(it, '') last = next(it, None) if last is None: return first else: parts = [first.rstrip()] for this in it: parts.append(last.strip()) last = this parts.append(last.lstrip()) return ' '.join(parts) But I would not advocate for inclusion in the standard lib as there are too many parameters the user may want to behave differently for them. Keep the trailing spaces? Leading space? Add spaces when connecting an empty string? A string that is only whitespace? Operate only on exactly str or the __str__ value of any object? Regards, Jeremiah On Tue, Mar 7, 2023 at 1:57 AM Valentin Berlier <berlier.v@gmail.com> wrote:
I'm -1 on this. You can easily make a helper that achieves the desired syntax. Presenting "human readable data" isn't just about collapsing spaces, and having your own helper means that you can adjust the formatting to your specific use case if needed (for example with a different separator).
from typing import Self
class StripJoin: def __init__(self, value: str = "") -> None: self.value = value def __and__(self, other: str) -> Self: other = other.strip() separator = bool(self.value and other) * " " return StripJoin(f"{self.value}{separator}{other}") def __str__(self) -> str: return self.value
j = StripJoin() print(j & " foo " & " bar " & " something ") # Output: "foo bar something"
The example above is more efficient than a possible implementation directly on the str builtin as it doesn't strip the left side over and over. However it still incurs repeated allocations and encourages a pattern that performs badly in loops. With a lot of input you should probably accumulate the stripped strings in a list and join them all at once.
In any case I recommend reaching out for a library like Rich ( https://github.com/Textualize/rich) if you care about formatting the output of your program nicely. _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/A7RPR3... Code of Conduct: http://python.org/psf/codeofconduct/
On 07/03/2023 09:54, Valentin Berlier wrote:
I'm -1 on this. You can easily make a helper that achieves the desired syntax. Presenting "human readable data" isn't just about collapsing spaces, and having your own helper means that you can adjust the formatting to your specific use case if needed (for example with a different separator).
from typing import Self
class StripJoin: def __init__(self, value: str = "") -> None: self.value = value def __and__(self, other: str) -> Self: other = other.strip() separator = bool(self.value and other) * " " return StripJoin(f"{self.value}{separator}{other}") def __str__(self) -> str: return self.value
j = StripJoin() print(j & " foo " & " bar " & " something ") # Output: "foo bar something"
The example above is more efficient than a possible implementation directly on the str builtin as it doesn't strip the left side over and over. However it still incurs repeated allocations and encourages a pattern that performs badly in loops. With a lot of input you should probably accumulate the stripped strings in a list and join them all at once. As Steven d'Aprano pointed out re a similar suggestion, this is not the same as my proposal, where " foo " & " bar " & " something " would evaluated to " foo bar something " Far from stripping the left side over and over, it doesn't strip it at all! (Or the right side.) This is trickier to write using join. And if the first or last string can be blank, or all whitespace, it is trickier still. As it is so easy to get these things wrong, perhaps having it built in is not such a terrible idea?😁 Best wishes Rob Cliffe
In any case I recommend reaching out for a library like Rich (https://github.com/Textualize/rich) if you care about formatting the output of your program nicely. _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/A7RPR3... Code of Conduct: http://python.org/psf/codeofconduct/
It's not that tricky to have the lstrip/rstrip behaviour with a join: def space_join(*args): first, *middle, last = args return ' '.join((first.rstrip(), *(s.strip() for s in middle), last.lstrip())) What is harder is to be sure that this would be the expected behaviour when using a `&` operator on strings. Why `' a' & 'b'` would produce `'a b'` and `' ' & 'b'` produce `' b'` for example? Le sam. 11 mars 2023 à 10:04, Rob Cliffe via Python-ideas < python-ideas@python.org> a écrit :
I'm -1 on this. You can easily make a helper that achieves the desired syntax. Presenting "human readable data" isn't just about collapsing spaces, and having your own helper means that you can adjust the formatting to your specific use case if needed (for example with a different separator).
from typing import Self
class StripJoin: def __init__(self, value: str = "") -> None: self.value = value def __and__(self, other: str) -> Self: other = other.strip() separator = bool(self.value and other) * " " return StripJoin(f"{self.value}{separator}{other}") def __str__(self) -> str: return self.value
j = StripJoin() print(j & " foo " & " bar " & " something ") # Output: "foo bar something"
The example above is more efficient than a possible implementation
On 07/03/2023 09:54, Valentin Berlier wrote: directly on the str builtin as it doesn't strip the left side over and over. However it still incurs repeated allocations and encourages a pattern that performs badly in loops. With a lot of input you should probably accumulate the stripped strings in a list and join them all at once. As Steven d'Aprano pointed out re a similar suggestion, this is not the same as my proposal, where " foo " & " bar " & " something " would evaluated to " foo bar something " Far from stripping the left side over and over, it doesn't strip it at all! (Or the right side.) This is trickier to write using join. And if the first or last string can be blank, or all whitespace, it is trickier still. As it is so easy to get these things wrong, perhaps having it built in is not such a terrible idea?😁 Best wishes Rob Cliffe
In any case I recommend reaching out for a library like Rich (
https://github.com/Textualize/rich) if you care about formatting the output of your program nicely.
_______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/A7RPR3... Code of Conduct: http://python.org/psf/codeofconduct/
_______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/J356SW... Code of Conduct: http://python.org/psf/codeofconduct/
-- Antoine Rozo
Having an operand blank or all whitespace is not a common use case for join, nor would it be for my proposed '&' operator. I wanted to present a clear definition, and however I chose it, those corner cases would be non-obvious. That said, I have now withdrawn this proposal due to objections by Bruce Leban and others. Best wishes Rob Cliffe On 11/03/2023 17:13, Antoine Rozo wrote:
It's not that tricky to have the lstrip/rstrip behaviour with a join: def space_join(*args): first, *middle, last = args return ' '.join((first.rstrip(), *(s.strip() for s in middle), last.lstrip()))
What is harder is to be sure that this would be the expected behaviour when using a `&` operator on strings. Why `' a' & 'b'` would produce `'a b'` and `' ' & 'b'` produce `' b'` for example?
Le sam. 11 mars 2023 à 10:04, Rob Cliffe via Python-ideas <python-ideas@python.org> a écrit :
On 07/03/2023 09:54, Valentin Berlier wrote: > I'm -1 on this. You can easily make a helper that achieves the desired syntax. Presenting "human readable data" isn't just about collapsing spaces, and having your own helper means that you can adjust the formatting to your specific use case if needed (for example with a different separator). > > from typing import Self > > class StripJoin: > def __init__(self, value: str = "") -> None: > self.value = value > def __and__(self, other: str) -> Self: > other = other.strip() > separator = bool(self.value and other) * " " > return StripJoin(f"{self.value}{separator}{other}") > def __str__(self) -> str: > return self.value > > j = StripJoin() > print(j & " foo " & " bar " & " something ") > # Output: "foo bar something" > > The example above is more efficient than a possible implementation directly on the str builtin as it doesn't strip the left side over and over. However it still incurs repeated allocations and encourages a pattern that performs badly in loops. With a lot of input you should probably accumulate the stripped strings in a list and join them all at once. As Steven d'Aprano pointed out re a similar suggestion, this is not the same as my proposal, where " foo " & " bar " & " something " would evaluated to " foo bar something " Far from stripping the left side over and over, it doesn't strip it at all! (Or the right side.) This is trickier to write using join. And if the first or last string can be blank, or all whitespace, it is trickier still. As it is so easy to get these things wrong, perhaps having it built in is not such a terrible idea?😁 Best wishes Rob Cliffe > > In any case I recommend reaching out for a library like Rich (https://github.com/Textualize/rich) if you care about formatting the output of your program nicely. > _______________________________________________ > Python-ideas mailing list -- python-ideas@python.org > To unsubscribe send an email to python-ideas-leave@python.org > https://mail.python.org/mailman3/lists/python-ideas.python.org/ > Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/A7RPR3... > Code of Conduct: http://python.org/psf/codeofconduct/
_______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/J356SW... Code of Conduct: http://python.org/psf/codeofconduct/
-- Antoine Rozo
On Sun, Mar 5, 2023 at 7:39 PM Rob Cliffe via Python-ideas < python-ideas@python.org> wrote:
Tl;dr: Join strings together with exactly one space between non-blank
This idea is inappropriate for inclusion in the language. There are too many subtle details in how this should work as noted by others. To give an example which I hope clearly illustrates that this is not simple, what should the value of 'full' & 'width' be? - 'full width' - 'full width' In case it's not clear, those are full width Latin characters which should be joined by a full width (ideographic) space U+3000. What should be inserted when the characters are Kanji (which doesn't usually use spaces) or Amkharic (which uses '፡' U+1361) or a mix of different character sets? --- Bruce
You make a very powerful point, Bruce. Much more so IMO than anyone else has so far. Unless anyone else can find a convincing rebuttal, I withdraw my proposal. Best wishes Rob Cliffe On 07/03/2023 21:49, Bruce Leban wrote:
On Sun, Mar 5, 2023 at 7:39 PM Rob Cliffe via Python-ideas <python-ideas@python.org> wrote:
Tl;dr: Join strings together with exactly one space between non-blank
This idea is inappropriate for inclusion in the language. There are too many subtle details in how this should work as noted by others. To give an example which I hope clearly illustrates that this is not simple,
what should the value of 'full' & 'width' be?
* 'full width' * 'full width'
In case it's not clear, those are full width Latin characters which should be joined by a full width (ideographic) space U+3000. What should be inserted when the characters are Kanji (which doesn't usually use spaces) or Amkharic (which uses '፡' U+1361) or a mix of different character sets?
--- Bruce
participants (10)
-
Antoine Rozo -
Bruce Leban -
David Mertz, Ph.D. -
Jeremiah Paige -
Joao S. O. Bueno -
Marc-Andre Lemburg -
Rob Cliffe -
Stephen J. Turnbull -
Steven D'Aprano -
Valentin Berlier