Re: [Python-Dev] How far to go with user-friendliness
From: Python-Dev on behalf of Ben Finney Sent: Thursday, July 16, 2015 15:59 To: python-dev@python.org Subject: Re: [Python-Dev] How far to go with user-friendliness > Ethan Furman writes: > > > On 07/16/2015 01:29 PM, Michael Foord wrote: > > > On Tuesday, 14 July 2015, Christie Wilson wrote: > > > > >> Unless the line silently executes and they don't notice the mistake for > > >> years :'( > > > > > > Indeed. This has been a problem with mock, misspelled (usually > > > misremembered) assert methods silently did nothing. > > > > > > With this fix in place several failing tests were revealed in code bases! > > > > This is good. :) > > It's good that bugs were found. That does not argue for making an alias > in the library, though; it better argues for those projects adding a > linter check for the common misspellings. > > > > As for assret, it's the common misspelling people have told me > > > about. It seems a ridiculous thing for people to get worked up > > > about, but people enjoy getting worked up. > > Advocating for a clean API is ridiculous? That's a disturbing attitude > to hear from a Python standard library contributor. > > > On the serious side, Python is not a DWIM language, and making > > accommodations for a misspelling feels very DWIMish. As I said in an > > earlier email part of writing good tests is double-checking that a > > test is failing (and for the right reasons). And yes, I am guilty of > > writing bad tests, and getting bit by it, and no, I still don't want > > the testing framework (or any part of Python) guessing what I meant. > > +1. > > These checks are a good thing, but they belong in a linter tool not as > aliases in the API. +1 > -- > \ “You say “Carmina”, and I say “Burana”, You say “Fortuna”, and | > `\I say “cantata”, Carmina, Burana, Fortuna, cantata, Let's Carl | > _o__)the whole thing Orff.” —anonymous | +1 000 000 ijs ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Status on PEP-431 Timezones
Well, I was going to stay silent, but math is something I can do without wasting anyone's time or embarrassing myself. I don't think this mail answers Lennart's concerns, but I do want to get it out there to compete with the comment in `datetime.py`. I apologize if the LaTeX density is too high; I don't trust that my e-mail client would transmit the message faithfully were I to render it myself. I disagree with the view Tim had of time zones when he wrote that comment (and that code). It sounds like he views US/Eastern and US/Central as time zones (which they are), but thinks of the various America/Indiana zones as switching back and forth between them, rather than being time zones in their own right. I think the right perspective is that a time zone *is* the function that its `fromutc()` method implements, although of course we need additional information in order to actually compute (rather than merely mathematically define) its inverse. Daylight Saving Time is a red herring, and assumptions 2 and 4 in that exposition are just wrong from this point of view. In the worst case, Asia/Riyadh's two years of solar time completely shatter these assumptions. I'm convinced that the right viewpoint on this is to view local time and UTC time each as isomorphic to $\RR$ (i.e., effectively as UNIX timestamps, minus the oft-violated guarantee that timestamps are in UTC), and to consider the time zone as \[ fromutc : \RR \to \RR. \] (Leap seconds are a headache for this perspective, but it can still support them with well-placed epicycles.) Then our assumptions (inspired by zoneinfo) about the nature of this map are as follows: * $fromutc$ is piecewise defined, with each piece being continuous and strictly monotonic increasing. Let us call the set of discontinuities $\{ utc_i \in \RR | i \in \ZZ \}$, where the labels are in increasing order, and define $fromutc_i$ to be the $i$-th piece. (The theoretical treatment doesn't suffer if there are only finitely many discontinuities, since we can place additional piece boundaries at will where no discontinuities exist; obviously, an implementation would not take this view.) * The piece $fromutc_i : [utc_i, utc_{i+1}) \to [local_{start, i}, local_{end, i})$ and its inverse, which we will call $fromlocal_i$, are both readily computable. In particular, this means that $local_{start, i} = fromutc(utc_i)$ and $local_{end, i}$ is the limit of $fromutc(t)$ as $t$ approaches $utc_{i+1}$ from the left, and that these values are known. Note that the (tzfile(5))[1] format and (zic(8)[2]) both assume that $fromutc_i$ is of the form $t \mapsto t + off_i$, where $off_i$ is a constant. This assumption is true in practice, but is stronger than we actually need. * The sequences $\{ local_{start, i} | i \in \ZZ \}$ and $\{ local_{end, i} | i \in \ZZ \}$ are strictly increasing, and $local_{end, i-1} < local_{start, i+1}$ for all $i \in \ZZ$. This final condition is enough to guarantee that the preimage of any local time under $fromutc$ contains at most two UTC times. This assumption would be violated if, for example, some jurisdiction decided to fall back two hours by falling back one hour and then immediately falling back a second hour. I recommend the overthrow of any such jurisdiction and its (annexation by the Netherlands)[3]. Without the third assumption, it's impossible to specify a UTC time by a (local time, time zone, DST flag) triple since there may be more than two UTC times corresponding to the same local time, and computing $fromlocal$ becomes more complicated, but the problem can still be solved by replacing the DST flag by an index into the preimage. (Lennart, I think this third assumption is the important part of your "no changes within 48 hours of each other" assumption, which is violated by Asia/Riyadh. Is it enough?) Once we take this view, computing $fromutc(t)$ is trivial: find $i$ with $utc_i \le t < utc_{i+1}$ by binary search (presumably optimized to an $O(1)$ average case by using a good initial guess), and compute $fromutc_i(t)$. Computing $fromlocal(t)$ is somewhat more difficult. The first thing to address is that, as written, $fromlocal$ is not a function; in order to make it one, we need to pass it more information. We could define $fromlocal(t, i) = fromlocal_i(t)$, but that's too circular to be useful. Likewise with my (silly) earlier proposal to store $(local, offset)$ pairs-- then $fromlocal(t, off) = t - off$. What we really need is a (partial, which is better than multi-valued!) function $fromlocal : \RR \times \{True, False\} \to \RR$ that takes a local time and a DST flag and returns a UTC time. We define $fromlocal(local, flag)$ to be the first $utc \in \RR$ such that $fromutc(utc) = local$ when $flag$ is $True$ and the last such $utc$ when $flag$ is $False$. (Our implementation will presumably also allow $flag$ to be $None$, in which case we require $utc$ to be unique.)
Re: [Python-Dev] Status on PEP-431 Timezones
> From: Tim Peters > Sent: Saturday, July 25, 2015 00:14 > To: ISAAC J SCHWABACHER > Cc: Alexander Belopolsky; Lennart Regebro; Python-Dev > Subject: Re: [Python-Dev] Status on PEP-431 Timezones > [Tim] > >> The formulas only produced approximations, and then > >> rounded to 5-second boundaries because the tz data format didn't have > >> enough bits. > [ISAAC J SCHWABACHER ] > > Little known fact: if you have a sub-minute-resolution UTC offset when a > > leap second hits, it rips open a hole in the space-time continuum and > > you find yourself in New Netherlands. > Tell me about it! Last time that happened I had to grow stinking > tulips for 3 years to get enough money to sail back home. I'll never > use a sub-minute-resolution UTC offset again ;-) I meant this one: https://what-if.xkcd.com/54/ :) ijs ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Status on PEP-431 Timezones
> The formulas only produced approximations, and then > rounded to 5-second boundaries because the tz data format didn't have > enough bits. Little known fact: if you have a sub-minute-resolution UTC offset when a leap second hits, it rips open a hole in the space-time continuum and you find yourself in New Netherlands. ijs From: Tim Peters Sent: Saturday, July 25, 2015 00:07 To: ISAAC J SCHWABACHER Cc: Alexander Belopolsky; Lennart Regebro; Python-Dev Subject: Re: [Python-Dev] Status on PEP-431 Timezones [Tim] > Sure. But, honestly, who cares? Riyadh Solar Time was so > off-the-wall that even the Saudis gave up on it 25 years ago (after a > miserable 3-year experiment with it). "Practicality beats purity". Heh. It's even sillier than that - the Saudis never used "Riyadh Solar Time", and it's been removed from release 2015e of the tz database: https://www.ietf.org/timezones/data/NEWS Release 2015e - 2015-06-13 10:56:02 -0700 ... The files solar87, solar88, and solar89 are no longer distributed. They were a negative experiment - that is, a demonstration that tz data can represent solar time only with some difficulty and error. Their presence in the distribution caused confusion, as Riyadh civil time was generally not solar time in those years. Looking back, Paul Eggert explained more in 2013, but it took this long for the patch to land: http://comments.gmane.org/gmane.comp.time.tz/7717 > did Saudi Arabia really use this as clock time? Not as far as I know, for civil time. There was some use for religious purposes but it didn't use the approximation in those files. These files probably cause more confusion than they're worth, so I'll propose a couple of patches to remove them, in two followup emails. I haven't pushed these patches to the experimental github version. The position of the sun is vital to establishing prayer times in Islam, but that's got little to do with civil time in Islamic countries. And Olson didn't take his "Riyadh Solar Time" rules from the Saudis, he made up the times himself: "Times were computed using formulas in the U.S. Naval Observatory's Almanac for Computers 1987[89]". The formulas only produced approximations, and then rounded to 5-second boundaries because the tz data format didn't have enough bits. So, as a motivating example, it's hard to get less compelling: Riyadh Solar is a wholly artificial "time zone" made up by a time zone wonk to demonstrate some limitations of the tz database he maintained. Although I expect he could have done so just as effectively by writing a brief note about it ;-) ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Status on PEP-431 Timezones
> From: Tim Peters > Sent: Friday, July 24, 2015 20:39 > To: ISAAC J SCHWABACHER > Cc: Alexander Belopolsky; Lennart Regebro; Python-Dev > Subject: Re: [Python-Dev] Status on PEP-431 Timezones > > [ISAAC J SCHWABACHER ] > > ... > > I disagree with the view Tim had of time zones when he wrote that comment > > (and that code). It sounds like he views US/Eastern and US/Central as time > > zones (which they are), but thinks of the various America/Indiana zones as > > switching back and forth between them, rather than being time zones in their > > own right > > You can think of them anyway you like. The point of the code was to > provide a simple & efficient way to convert from UTC to local time in > all "time zones" in known actual use at the time; the point of the > comment was to explain the limitations of the code. Although, as > Allexander noted, the stated assumptions are stronger than needed. > > > I think the right perspective is that a time zone *is* the function that its > > `fromutc()` method implements, > > Fine by me ;-) My issue is that you're computing `fromutc()`, which is a function, in terms of `dst()` and `utcoffset()`, which aren't. I think this is backwards; `dst()` and `utcoffset()` should be computed from `fromutc()` plus some additional information that has to be present anyway in order to implement `fromutc()`. With the extra bit, `dst()` and `utcoffset()` become partial functions, which makes it *possible* to get the right answer in all cases, but it's still simpler to start with the total function and work from there. > > although of course we need additional information in order to actually > > compute (rather than merely mathematically define) its inverse. Daylight > > Saving > > Time is a red herring, > > Overstated. DST is in fact the _only_ real complication in 99.99% of > time zones (perhaps even 99.9913% ;-) ). As the docs say, if you have > some crazy-ass time zone in mind, fine, that's why fromutc() was > exposed (so your; crazy-ass tzinfo class can override it). I stand by what I meant by this, even if I did a bad job of expressing the point. Assuming that all time zone discontinuities are due to DST changes breaks many time zones (really almost all of the Olson time zones, though only for a vanishingly small fraction of datetimes), but that's not the point I was making. The point is that it doesn't buy us anything. Though this is probably obscured by all the markup, the more general algorithm I gave is also simpler than the one in the comment in datetime.py, and the reason for that is that it solves an easier problem, but one that serves our practical purposes just as well. > > and assumptions 2 and 4 > > Nitpick: 4 is a consequence of 2, not an independent assumption. > > > in that exposition are just wrong from this point of view. > > As above, there is no particular POV in this code: just a specific > fromutc() implementation, comments that explain its limitations, and > an invitation in the docs to override it if it's not enough for your > case. I went too far in inferring your viewpoint from your code. I don't find fault with the explanation on its own terms. But adding zoneinfo to the stdlib, as PEP 431 proposes to do, requires making weaker assumptions and asking a different question than the one answered in the comment. > > In the worst case, Asia/Riyadh's two years of solar time completely shatter > > these assumptions. > > Sure. But, honestly, who cares? Riyadh Solar Time was so > off-the-wall that even the Saudis gave up on it 25 years ago (after a > miserable 3-year experiment with it). "Practicality beats purity". As a mathematician at heart, I have a deep and abiding conviction, which I expect nobody else to share, that purity begets practicality in the long run. At least if you've found the right abstraction. > > [eliding a more-general view of what time zones "really" are] [note for people just joining this conversation: I think the information in the elision is critical to understanding what I'm talking about] > I'm not eliding it because I disagree with it, but because time zones > are political constructions. "The math" we make up may or may not be > good enough to deal with all future political abominations; for > example: > > > ... > > This assumption would be violated if, for example, some jurisdiction > > decided to fall back two hours by falling back one hour and then > > immediately falling back a second hour. I recommend the overthrow > > of any such jurisdiction and its (annexation by the Netherlands)[3]. > > That's not objectively any more bizarr
Re: [Python-Dev] Status on PEP-431 Timezones
Responses to several partial messages follow. [Lennart Regebro] > Then we can't implement timezones in a reasonable way with the current > API, but have to have something like pytz's normalize() function or > similar. > > I'm sorry I've wasted everyones time with this PEP. [ijs] I think that integrating pytz into the stdlib, which is what the PEP proposes, would be valuable even without changing datetime arithmetic. But I see ways to accomplish the latter without breaking backward compatibility. The dream ain't dead! See below. [Paul Moore] > 2. Arithmetic within a complex timezone. Theoretically, this is simple > enough (convert to UTC, do the calculation naively, and convert back). > But in practice, that approach doesn't always match user expectations. > So you have 2 mutually incompatible semantic options - 1 day after 4pm > is 3pm the following day, or adding 1 day adds 25 hours - either is a > viable choice, and either will confuse *some* set of users. This, I > think, is the one where all the debate is occurring, and the one that > makes my head explode. > It seems to me that the problem is that for this latter issue, it's > the *timedelta* object that's not rich enough. [ijs] Yes! This is the heart of the matter. We can solve *almost* all the problems by having multiple competing timedelta classes-- which we already have. Do you care about what will happen after a fixed amount of elapsed time? Use `numpy.timedelta64` or `pandas.Timedelta`. Want this time tomorrow, come hell, high water, or DST transition? Use `dateutil.relativedelta.relativedelta` or `mx.DateTime.RelativeDateTime`. As long as the timedelta objects we're using are rich enough, we can make `dt + delta` say what we mean. There's no reason we can't have both naive and aware arithmetic in the stdlib at once. All the stdlib needs is an added timedelta class that represents elapsed atomic clock time, and voila! The biggest problem that this can't solve is subtraction. Which timedelta type do you get by subtracting two datetimes? Sure, you can have a `datetime.elapsed_since(self, other: datetime, **kwargs) -> some_timedelta_type` that determines what you want from the kwargs, but `datetime.__sub__` doesn't have that luxury. I think the right answer is that subtraction should yield the elapsed atomic clock time, but that would be a backward-incompatible change so I don't put a high probability on it happening any time soon. See the last message (below) for more on this. > You can't say "add 1 > day, and by 1 day I mean keep the same time tomorrow" as opposed to > "add 1 day, and by that I mean 24 hours"[1]. In some ways, it's > actually no different from the issue of adding 1 month to a date > (which is equally ill-defined, but people "know what they mean" to > just as great an extent). Python bypasses the latter by not having a > timedelta for "a month". C (and the time module) bypasses the former > by limiting all time offsets to numbers of seconds - datetime gave us > a richer timedelta object and hence has extra problems. Because of the limits on the values of its members, `datetime.timedelta` is effectively just a counter of microseconds. It can't distinguish between 1 day, 24 hours, 1440 minutes or 86400 seconds. They're all normalized to the same value. So it's not actually richer; it only appears so. > I don't have any solutions to this final issue. But hopefully the > above analysis (assuming it's accurate!) helps clarify what the actual > debate is about, for those bystanders like me who are interested in > following the discussion. With luck, maybe it also gives the experts > an alternative perspective from which to think about the problem - who > knows? > > Paul > > [1] Well, you can, actually - you say that a timedelta of "1 day" > means "the same time tomorrow" and if you want 24 hours, you say "24 > hours" not "1 day". So timedelta(days=1) != timedelta(hours=24) even > though they give the same result for every case except arithmetic > involving complex timezones. Is that what Lennart has been trying to > say in his posts? I thought for a long time that this would be sufficient, and I still think it's a good spelling that makes it clear what the user wants most of the time, but I have wanted things like "the first time the clock shows 1 hour later than it shows right now" enough times that I no longer think this is quite sufficient. (I *think* you can do that with `dt + dateutil.relativedelta.relativedelta(hour=dt.hour+1, minute=0, second=0, microsecond=0)`, but I'm not sure.) [Tim Peters] > Ah, but it already happens that way - because the builtin datetime > arithmetic is "naive". The docs have always promised this: > > """ > datetime2 = datetime1 + timedelta (1) > datetime2 = datetime1 - timedelta (2) > > 1) datetime2 is a duration of timedelta removed from datetime1, moving > forward in time if timedelta.days > 0, or backward if timedelta.days < > 0. The result has the same tzinfo at
Re: [Python-Dev] PEP-498: Literal String Formatting
I don't know about you, but I sure like this better than what you have: code.putlines(f""" static char {entry.doc_cname}[] = "{ split_string_literal(escape_bytestring(docstr))}"; { # nested! f""" #if CYTHON_COMPILING_IN_CPYTHON struct wrapperbase {entry.wrapperbase_cname}; #endif """ if entry.is_special else ''} {(lambda temp, argn: # my kingdom for a let! f""" for ({temp}=0; {temp} on behalf of Stefan Behnel Sent: Sunday, August 9, 2015 04:53 To: python-dev@python.org Subject: Re: [Python-Dev] PEP-498: Literal String Formatting Stefan Behnel schrieb am 09.08.2015 um 10:06: > Eric V. Smith schrieb am 08.08.2015 um 03:39: >> Following a long discussion on python-ideas, I've posted my draft of >> PEP-498. It describes the "f-string" approach that was the subject of >> the "Briefer string format" thread. I'm open to a better title than >> "Literal String Formatting". >> >> I need to add some text to the discussion section, but I think it's in >> reasonable shape. I have a fully working implementation that I'll get >> around to posting somewhere this weekend. >> >> >>> def how_awesome(): return 'very' >> ... >> >>> f'f-strings are {how_awesome()} awesome!' >> 'f-strings are very awesome!' >> >> I'm open to any suggestions to improve the PEP. Thanks for your feedback. > > [copying my comment from python-ideas here] > > How common is this use case, really? Almost all of the string formatting > that I've used lately is either for logging (no help from this proposal > here) or requires some kind of translation/i18n *before* the formatting, > which is not helped by this proposal either. Thinking about this some more, the "almost all" is actually wrong. This only applies to one kind of application that I'm working on. In fact, "almost all" of the string formatting that I use is not in those applications but in Cython's code generator. And there's a *lot* of string formatting in there, even though we use real templating for bigger things already. However, looking through the code, I cannot see this proposal being of much help for that use case either. Many of the values that get formatted into the strings use some kind of non-trivial expression (function calls, object attributes, also local variables, sometimes variables with lengthy names) that is best written out in actual code. Here are some real example snippets: code.putln( 'static char %s[] = "%s";' % ( entry.doc_cname, split_string_literal(escape_byte_string(docstr if entry.is_special: code.putln('#if CYTHON_COMPILING_IN_CPYTHON') code.putln( "struct wrapperbase %s;" % entry.wrapperbase_cname) code.putln('#endif') temp = ... code.putln("for (%s=0; %s < PyTuple_GET_SIZE(%s); %s++) {" % ( temp, temp, Naming.args_cname, temp)) code.putln("PyObject* item = PyTuple_GET_ITEM(%s, %s);" % ( Naming.args_cname, temp)) code.put("%s = (%s) ? PyDict_Copy(%s) : PyDict_New(); " % ( self.starstar_arg.entry.cname, Naming.kwds_cname, Naming.kwds_cname)) code.putln("if (unlikely(!%s)) return %s;" % ( self.starstar_arg.entry.cname, self.error_value())) We use %-formatting for historical reasons (that's all there was 15 years ago), but I wouldn't switch to .format() because there is nothing to win here. The "%s" etc. place holders are *very* short and do not get in the way (as "{}" would in C code templates). Named formatting would require a lot more space in the templates, so positional, unnamed formatting helps readability a lot. And the value expressions used for the interpolation tend to be expressions rather than simple variables, so keeping those outside of the formatting strings simplifies both editing and reading. That's the third major real-world use case for string formatting now where this proposal doesn't help. The niche is getting smaller. Stefan ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/ischwabacher%40wisc.edu ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP-498: Literal String Formatting
Now with syntax highlighting, if my email client cooperates: code.putlines(f""" static char {entry.doc_cname}[] = "{ split_string_literal(escape_bytestring(docstr))}"; { # nested! f""" #if CYTHON_COMPILING_IN_CPYTHON struct wrapperbase {entry.wrapperbase_cname}; #endif """ if entry.is_special else ''} {(lambda temp, argn: # my kingdom for a let! f""" for ({temp}=0; {temp} on behalf of Stefan Behnel Sent: Sunday, August 9, 2015 04:53 To: python-dev@python.org Subject: Re: [Python-Dev] PEP-498: Literal String Formatting Stefan Behnel schrieb am 09.08.2015 um 10:06: > Eric V. Smith schrieb am 08.08.2015 um 03:39: >> Following a long discussion on python-ideas, I've posted my draft of >> PEP-498. It describes the "f-string" approach that was the subject of >> the "Briefer string format" thread. I'm open to a better title than >> "Literal String Formatting". >> >> I need to add some text to the discussion section, but I think it's in >> reasonable shape. I have a fully working implementation that I'll get >> around to posting somewhere this weekend. >> >> >>> def how_awesome(): return 'very' >> ... >> >>> f'f-strings are {how_awesome()} awesome!' >> 'f-strings are very awesome!' >> >> I'm open to any suggestions to improve the PEP. Thanks for your feedback. > > [copying my comment from python-ideas here] > > How common is this use case, really? Almost all of the string formatting > that I've used lately is either for logging (no help from this proposal > here) or requires some kind of translation/i18n *before* the formatting, > which is not helped by this proposal either. Thinking about this some more, the "almost all" is actually wrong. This only applies to one kind of application that I'm working on. In fact, "almost all" of the string formatting that I use is not in those applications but in Cython's code generator. And there's a *lot* of string formatting in there, even though we use real templating for bigger things already. However, looking through the code, I cannot see this proposal being of much help for that use case either. Many of the values that get formatted into the strings use some kind of non-trivial expression (function calls, object attributes, also local variables, sometimes variables with lengthy names) that is best written out in actual code. Here are some real example snippets: code.putln( 'static char %s[] = "%s";' % ( entry.doc_cname, split_string_literal(escape_byte_string(docstr if entry.is_special: code.putln('#if CYTHON_COMPILING_IN_CPYTHON') code.putln( "struct wrapperbase %s;" % entry.wrapperbase_cname) code.putln('#endif') temp = ... code.putln("for (%s=0; %s < PyTuple_GET_SIZE(%s); %s++) {" % ( temp, temp, Naming.args_cname, temp)) code.putln("PyObject* item = PyTuple_GET_ITEM(%s, %s);" % ( Naming.args_cname, temp)) code.put("%s = (%s) ? PyDict_Copy(%s) : PyDict_New(); " % ( self.starstar_arg.entry.cname, Naming.kwds_cname, Naming.kwds_cname)) code.putln("if (unlikely(!%s)) return %s;" % ( self.starstar_arg.entry.cname, self.error_value())) We use %-formatting for historical reasons (that's all there was 15 years ago), but I wouldn't switch to .format() because there is nothing to win here. The "%s" etc. place holders are *very* short and do not get in the way (as "{}" would in C code templates). Named formatting would require a lot more space in the templates, so positional, unnamed formatting helps readability a lot. And the value expressions used for the interpolation tend to be expressions rather than simple variables, so keeping those outside of the formatting strings simplifies both editing and reading. That's the third major real-world use case for string formatting now where this proposal doesn't help. The niche is getting smaller. Stefan ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/ischwabacher%40wisc.edu ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP-498: Literal String Formatting
Ruby already has this feature, and in my experience syntax highlighters handle it just fine. Here's what vim's default highlighter shows me: puts "we can #{ ["include", "interpolate"].each { |s| puts s } .select { |s| s.include? "erp" } # .first } arbitrary expressions!" So an editor whose syntax highlighting is based on regular expressions already can't cope with the world as it is. :) Does anyone reading this know of a tool that successfully highlights python but not ruby? ijs From: Python-Dev on behalf of Greg Ewing Sent: Tuesday, August 11, 2015 18:34 To: python-dev@python.org Subject: Re: [Python-Dev] PEP-498: Literal String Formatting Stefan Behnel wrote: > Syntax highlighting and in-string expression completion should eventually > help, once IDEs support it. Concerning that, this is going to place quite a burden on syntax highlighters. Doing it properly will require the ability to parse arbitrary Python expressions, or at least match nested brackets. An editor whose syntax hightlighting engine is based on regular expressions could have trouble with that. -- Greg ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/ischwabacher%40wisc.edu ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP-498: Literal String Formatting
Well, I seem to have succeeded in crystallizing opinions on the topic, even if the consensus is, "Augh! Make it stop!" :) The primary objective of that code sample was to make the structure of the code as close as possible to the structure of the interpolated string, since having descriptive text like "{entry.doc_cname}" inline instead of "%s" is precisely what str.format gains over str.__mod__. But there are several different elements in that code, and I'm curious what people find most off-putting. Is it the triple quoted format strings? The nesting? The interpolation with `"""...""" if cond else ''`? Just plain interpolations as are already available with str.format, but without explicitly importing names into the format string's scope via **kwargs? Trying to emulate let? Would a different indentation scheme make things better, or is this a problem with the coding style I've advanced here, or with the feature itself? Also, should this be allowed: def make_frob(foo): def frob(bar): f"""Frob the bar using {foo}""" ? ijs P.S.: I've translated the original snippet into ruby here: https://gist.github.com/ischwabacher/405afb86e28282946cc5, since it's already legal syntax there. Ironically, github's syntax highlighting either fails to parse the interpolation (in edit mode) or fails to treat the heredoc as a string literal (in display mode), but you can open it in your favorite editor to see whether the highlighting makes the code clearer. From: Python-Dev on behalf of Ethan Furman Sent: Wednesday, August 12, 2015 18:11 To: python-dev@python.org Subject: Re: [Python-Dev] PEP-498: Literal String Formatting On 08/10/2015 04:05 PM, ISAAC J SCHWABACHER wrote: > I don't know about you, but I sure like this better than what you have: > > code.putlines(f""" > static char {entry.doc_cname}[] = "{ > split_string_literal(escape_bytestring(docstr))}"; > > { # nested! > f""" > #if CYTHON_COMPILING_IN_CPYTHON > struct wrapperbase {entry.wrapperbase_cname}; > #endif > """ if entry.is_special else ''} > > {(lambda temp, argn: # my kingdom for a let! > f""" > for ({temp}=0; {temp} PyObject *item = PyTuple_GET_ITEM({argn}, {temp}); > }}""")(..., Naming.args_cname)} > > {self.starstar_arg.entry.cname} = > ({Naming.kwds_cname}) ? PyDict_Copy({Naming.kwds_cname}) >: PyDict_New(); > > if (unlikely(!{self.starstar_arg.entry.cname})) return {self.error_value()}; > """) > > What do others think of this PEP-498 sample? (The PEP-501 version looks > pretty similar, so I omit it.) Agh! My brain is hurting! ;) No, I don't care for it at all. -- ~Ethan~ ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/ischwabacher%40wisc.edu ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com