TE
科技回声
首页24小时热榜最新最佳问答展示工作
GitHubTwitter
首页

科技回声

基于 Next.js 构建的科技新闻平台,提供全球科技新闻和讨论内容。

GitHubTwitter

首页

首页最新最佳问答展示工作

资源链接

HackerNews API原版 HackerNewsNext.js

© 2025 科技回声. 版权所有。

PEP 750 – Template Strings

437 点作者 grep_it大约 1 个月前

46 条评论

Mawr大约 1 个月前
It&#x27;s fascinating how differently languages approach the string formatting design space.<p>- Java&#x27;s been trying to add f&#x2F;t-strings, but its designers appear to be perfectionists to a fault, unable to accept anything that doesn&#x27;t solve every single problem possible to imagine: [1].<p>- Go developers seem to have taken no more than 5 minutes considering the problem, then thoughtlessly discarded it: [2]. A position born from pure ignorance as far as I&#x27;m concerned.<p>- Python, on the other hand, has consistently put forth a balanced approach of discussing each new way of formatting strings for some time, deciding on a good enough implementation and going with it.<p>In the end, I find it hard to disagree with Python&#x27;s approach. Its devs have been able to get value from first the best variant of sprintf in .format() since 2008, f-strings since 2016, and now t-strings.<p>[1]: <a href="https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=40737095">https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=40737095</a><p>[2]: <a href="https:&#x2F;&#x2F;github.com&#x2F;golang&#x2F;go&#x2F;issues&#x2F;34174#issuecomment-1450932232">https:&#x2F;&#x2F;github.com&#x2F;golang&#x2F;go&#x2F;issues&#x2F;34174#issuecomment-14509...</a>
评论 #43649341 未加载
评论 #43649134 未加载
评论 #43649235 未加载
评论 #43650407 未加载
评论 #43650203 未加载
评论 #43649313 未加载
评论 #43649425 未加载
评论 #43653690 未加载
评论 #43650467 未加载
评论 #43651319 未加载
评论 #43748596 未加载
评论 #43648945 未加载
nhumrich大约 1 个月前
Nick Humrich here, the author who helped rewrite PEP 501 to introduce t-strings, which was the foundation for this PEP. I am not an author on this accepted PEP, but I know this PEP and story pretty well. Let me know if you have any questions.<p>I am super excited this is finally accepted. I started working on PEP 501 4 years ago.
评论 #43648298 未加载
评论 #43648524 未加载
评论 #43649447 未加载
评论 #43649108 未加载
评论 #43648283 未加载
评论 #43648752 未加载
评论 #43648718 未加载
评论 #43648906 未加载
kstrauser大约 1 个月前
Most excellent! I love f-strings and replaced all the various other string interpolation instances in my code with them, but they have the significant issue that you can&#x27;t defer evaluating them. For instance, you can write:<p><pre><code> &gt;&gt;&gt; template = &#x27;Hello, {name}&#x27; &gt;&gt;&gt; template.format(name=&#x27;Bob&#x27;) &#x27;Hello, Bob&#x27; </code></pre> Until this, there wasn&#x27;t a way to use f-strings formatting without interpolating the results at that moment:<p><pre><code> &gt;&gt;&gt; template = f&#x27;Hello, {name}&#x27; Traceback (most recent call last): File &quot;&lt;python-input-5&gt;&quot;, line 1, in &lt;module&gt; template = f&#x27;Hello, {name}&#x27; ^^^^ NameError: name &#x27;name&#x27; is not defined </code></pre> It was annoying being able to use f-strings almost everywhere, but str.format in enough odd corners that you have to put up with it.
评论 #43649676 未加载
评论 #43648016 未加载
评论 #43647982 未加载
评论 #43648216 未加载
评论 #43648042 未加载
评论 #43648183 未加载
评论 #43648467 未加载
ratorx大约 1 个月前
I’m not convinced that a language level feature is worth it for this. You could achieve the same thing with a function returning an f-string no? And if you want injection safety, just use a tag type and a sanitisation function that takes a string and returns the type. Then the function returning the f-string could take the Sanitised string as an argument to prevent calling it with unsanitised input.<p>I guess it’s more concise, but differentiating between eager and delayed execution with a single character makes the language less readable for people who are not as familiar with Python (especially latest update syntax etc).<p>EDIT: to flesh out with an example:<p>class Sanitised(str): # init function that sanitises or just use as a tag type that has an external sanitisation function.<p>def sqltemplate(name: Sanitised) -&gt; str: return f”select * from {name}”<p># Usage sqltemplate(name=sanitise(“some injection”))<p># Attempt to pass unsanitised sqltemplate(name=“some injection”) # type check error
评论 #43648286 未加载
评论 #43749161 未加载
评论 #43648117 未加载
评论 #43648091 未加载
评论 #43648123 未加载
simonw大约 1 个月前
I&#x27;m excited about this. I really like how JavaScript&#x27;s tagged template literals <a href="https:&#x2F;&#x2F;developer.mozilla.org&#x2F;en-US&#x2F;docs&#x2F;Web&#x2F;JavaScript&#x2F;Reference&#x2F;Template_literals#tagged_templates" rel="nofollow">https:&#x2F;&#x2F;developer.mozilla.org&#x2F;en-US&#x2F;docs&#x2F;Web&#x2F;JavaScript&#x2F;Refe...</a> can help handle things like automatic HTML escaping or SQL parameterization, it looks like these will bring the same capability to Python.
评论 #43648199 未加载
评论 #43648390 未加载
评论 #43749176 未加载
spankalee大约 1 个月前
Maintainer of lit-html here, which uses tagged template literals in JavaScript extensively.<p>This looks really great! It&#x27;s almost exactly like JavaScript tagged template literals, just with a fixed tag function of:<p><pre><code> (strings, ...values) =&gt; {strings, values}; </code></pre> It&#x27;s pretty interesting how what would be the tag function in JavaScript, and the arguments to it, are separated by the Template class. At first it seems like this will add noise since it takes more characters to write, but it can make nested templates more compact.<p>Take this type of nested template structure in JS:<p><pre><code> html`&lt;ul&gt;${items.map((i) =&gt; html`&lt;li&gt;${i}&lt;&#x2F;li&gt;`}&lt;&#x2F;ul&gt;` </code></pre> With PEP 750, I suppose this would be:<p><pre><code> html(t&quot;&lt;ul&gt;{map(lambda i: t&quot;&lt;li&gt;{i}&lt;&#x2F;li&gt;&quot;, items)}&lt;&#x2F;ul&gt;&quot;) </code></pre> Python&#x27;s unfortunate lambda syntax aside, not needing html() around nested template could be nice (assuming an html() function would interpret plain Templates as HTML).<p>In JavaScript reliable syntax highlighting and type-checking are keyed off the fact that a template can only ever have a single tag, so a static analyzer can know what the nested language is. In Python you could separate the template creation from the processing possibly introduce some ambiguities, but hopefully that&#x27;s rare in practice.<p>I&#x27;m personally would be interested to see if a special html() processing instruction could both emit server-rendered HTML and say, lit-html JavaScript templates that could be used to update the DOM client-side with new data. That could lead to some very transparent fine-grained single page updates, from what looks like traditional server-only code.
评论 #43649733 未加载
评论 #43648707 未加载
评论 #43649157 未加载
评论 #43649698 未加载
casenmgreen22 天前
I read a fair part of the doc, from the start, I wanted to see how I would use t-strings in code; in the sense of, I know how I use f-strings now, in Python code, and I wanted to understand in the same way, how I would use t-strings in code. I have not understood how I would use t-strings.
评论 #43750392 未加载
throwawayffffas大约 1 个月前
So we are well on our way to turning python to PHP.<p>Edit: Sorry I was snarky, its late here.<p>I already didn&#x27;t like f-strings and t-strings just add complexity to the language to fix a problem introduced by f-strings.<p>We really don&#x27;t need more syntax for string interpolation, in my opinion string.format is the optimal. I could even live with % just because the syntax has been around for so long.<p>I&#x27;d rather the language team focus on more substantive stuff.
评论 #43648150 未加载
评论 #43649231 未加载
评论 #43648308 未加载
评论 #43654166 未加载
mcdeltat大约 1 个月前
Could someone explain more why this should be a language feature?<p>My understanding of template strings is they are like f-strings but don&#x27;t do the interpolation bit. The name binding is there but the values are not formatted into the string yet. So effectively this provides a &quot;hook&quot; into the stringification of the interpolated values, right?<p>If so, this seems like a very narrow feature to bake into the language... Personally, I haven&#x27;t had issues with introducing some abstraction like functions or custom types to do custom interpolation.
评论 #43649563 未加载
评论 #43649533 未加载
评论 #43649555 未加载
评论 #43649732 未加载
callamdelaney大约 1 个月前
I like this but am still not a fan of the constant adding of things to the language. It’s starting to feel like a language designed by committee, which it basically is.
评论 #43648900 未加载
评论 #43648926 未加载
评论 #43649011 未加载
评论 #43649051 未加载
pgjones大约 1 个月前
If you want to see a usage for this I&#x27;ve built, and use, [SQL-tString](<a href="https:&#x2F;&#x2F;github.com&#x2F;pgjones&#x2F;sql-tstring">https:&#x2F;&#x2F;github.com&#x2F;pgjones&#x2F;sql-tstring</a>) as an SQL builder.
sgarland大约 1 个月前
Am I missing something, or is this a fancier string.Template [0]? Don&#x27;t get me wrong, it looks very useful, especially the literals.<p>[0]: <a href="https:&#x2F;&#x2F;docs.python.org&#x2F;3&#x2F;library&#x2F;string.html#template-strings" rel="nofollow">https:&#x2F;&#x2F;docs.python.org&#x2F;3&#x2F;library&#x2F;string.html#template-strin...</a>
评论 #43659612 未加载
pansa2大约 1 个月前
Putting aside template strings themselves for the moment, I&#x27;m stunned by some of the code in this PEP. It&#x27;s so verbose! For example, &quot;Implementing f-strings with t-strings&quot;:<p><pre><code> def f(template: Template) -&gt; str: parts = [] for item in template: match item: case str() as s: parts.append(s) case Interpolation(value, _, conversion, format_spec): value = convert(value, conversion) value = format(value, format_spec) parts.append(value) return &quot;&quot;.join(parts) </code></pre> Is this what idiomatic Python has become? 11 lines to express a loop, a conditional and a couple of function calls? I use Python because I want to write <i>executable pseudocode</i>, not <i>excessive superfluousness</i>.<p>By contrast, here&#x27;s the equivalent Ruby:<p><pre><code> def f(template) = template.map { |item| item.is_a?(Interpolation) ? item.value.convert(item.conversion).format(item.format_spec) : item }.join</code></pre>
评论 #43648663 未加载
评论 #43648650 未加载
评论 #43650001 未加载
评论 #43651569 未加载
评论 #43654268 未加载
评论 #43649102 未加载
SuperV1234大约 1 个月前
This is a great PEP. Very similar to what I wanted to achieve with my P1819 for C++, back in 2019: <a href="https:&#x2F;&#x2F;www.open-std.org&#x2F;jtc1&#x2F;sc22&#x2F;wg21&#x2F;docs&#x2F;papers&#x2F;2019&#x2F;p1819r0.html" rel="nofollow">https:&#x2F;&#x2F;www.open-std.org&#x2F;jtc1&#x2F;sc22&#x2F;wg21&#x2F;docs&#x2F;papers&#x2F;2019&#x2F;p18...</a>
illegally大约 1 个月前
Feels unnecessary...<p>Can&#x27;t think of a good reason now on why I would need this rather than just a simple f-string.<p>Any unsafe string input should normally be sanitized before being added in a template&#x2F;concatenation, leaving the sanitization in the end doesn&#x27;t seem like the best approach, but ok.
评论 #43649200 未加载
chaz6大约 1 个月前
I like the implementation, but it looks like nobody has pointed out that Python already has a built-in string template system [1]. Granted, it&#x27;s not quite as simple to use, but I have been using it for a while.<p>[1] <a href="https:&#x2F;&#x2F;docs.python.org&#x2F;3&#x2F;library&#x2F;string.html#template-strings" rel="nofollow">https:&#x2F;&#x2F;docs.python.org&#x2F;3&#x2F;library&#x2F;string.html#template-strin...</a><p>edit: this was mentioned by milesrout in <a href="https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=43649607">https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=43649607</a>
actinium226大约 1 个月前
So does this mean that any place where code exists that looks for `type(someinstance) == str` will break because the type will be `Template` even though `someinstance` could still be used in the following code?
评论 #43648525 未加载
ic_fly2大约 1 个月前
In the past when I needed this I just made a function that processed the f string, often enough a simple lambda function would do. This looks like additional complexity for not a lot of gain.
评论 #43648735 未加载
DonHopkins大约 1 个月前
I wonder what fun The Amazing David Beazley thinks PEP 750 t-strings are?<p>I recently asked him:<p>--<p>Hi David! I am a huge long time fan of SWIG and your numerous epic talks on Python.<p>I remember watching you give a kinda recent talk where you made the point that it’s a great idea to take advantage of the latest features in Python, instead of wasting your time trying to be backwards compatible.<p>I think you discussed how great f-strings were, which I was originally skeptical about, but you convinced me to change my mind.<p>I’ve googled around and can’t find that talk any more, so maybe I was confabulating, or it had a weird name, or maybe you’ve just given so many great talks I couldn’t find the needle in the haystack.<p>What made me want to re-watch and link my cow-orkers to your talk was the recent rolling out of PEP 701: Syntactic formalization of f-strings, which makes f-strings even better!<p>Oh by the way, do you have any SWIG SWAG? I’d totally proudly wear a SWIG t-shirt!<p>-Don<p>--<p>He replied:<p>Hi Don,<p>It was probably the &quot;Fun of Reinvention&quot;.<p><a href="https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=js_0wjzuMfc" rel="nofollow">https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=js_0wjzuMfc</a><p>If not, all other talks can be found at:<p><a href="https:&#x2F;&#x2F;www.dabeaz.com&#x2F;talks.html" rel="nofollow">https:&#x2F;&#x2F;www.dabeaz.com&#x2F;talks.html</a><p>As for swag, I got nothing. Sorry!<p>Cheers, Dave<p>--<p>Thank you!<p>This must be some corollary of rule 34:<p><a href="https:&#x2F;&#x2F;www.swigwholesale.com&#x2F;swig-swag" rel="nofollow">https:&#x2F;&#x2F;www.swigwholesale.com&#x2F;swig-swag</a><p>(Don’t worry, sfw!)<p>-Don<p>--<p>The f-strings section starts at 10:24 where he&#x27;s live coding Python on a tombstone with a dead parrot. But the whole talk is well worth watching, like all his talks!<p><a href="https:&#x2F;&#x2F;youtu.be&#x2F;js_0wjzuMfc?t=624" rel="nofollow">https:&#x2F;&#x2F;youtu.be&#x2F;js_0wjzuMfc?t=624</a>
mortar大约 1 个月前
&gt; If a single interpolation is expensive to evaluate, it can be explicitly wrapped in a lambda in the template string literal<p>I’m having trouble understanding this - Can someone please help out with an example use case for this? It seems like before with an f string we had instant evaluation, now with a t string we control the evaluation, why would we further delay evaluation - Is it just to utilise running a function on a string first (i.e. save a foo = process(bar) line?)
评论 #43648997 未加载
评论 #43648921 未加载
oftenwrong大约 1 个月前
This appears similar to Java&#x27;s String Template preview feature that was withdrawn:<p><a href="https:&#x2F;&#x2F;openjdk.org&#x2F;jeps&#x2F;465" rel="nofollow">https:&#x2F;&#x2F;openjdk.org&#x2F;jeps&#x2F;465</a><p>This is probably the best overview of why it was withdrawn:<p><a href="https:&#x2F;&#x2F;mail.openjdk.org&#x2F;pipermail&#x2F;amber-spec-experts&#x2F;2024-April&#x2F;004106.html" rel="nofollow">https:&#x2F;&#x2F;mail.openjdk.org&#x2F;pipermail&#x2F;amber-spec-experts&#x2F;2024-A...</a>
unsnap_biceps大约 1 个月前
This is super exciting but I wish they added a function to render the template to a string rather then having everyone write their own version of basic rendering.
评论 #43648247 未加载
评论 #43648361 未加载
评论 #43648342 未加载
whoiscroberts大约 1 个月前
Why should I use this instead of Template class from string
eviks大约 1 个月前
With the proliferation of string type prefixes will they add one that represents a r#&quot;&quot;# real raw string capable of ending with a backslash?
wodenokoto大约 1 个月前
I&#x27;ve been toying with the idea of having arbitrary string types, like<p><pre><code> sql&quot;SELECT FROM ...&quot; </code></pre> or<p><pre><code> re&quot;\d\d[abc]&quot; </code></pre> that the development environment could highlight properly, that would ... I don&#x27;t know. In the end t and f string don&#x27;t do anything that a t() and f() function couldn&#x27;t have done, except they are nice. So it would be nice to have more.
评论 #43659664 未加载
spullara大约 1 个月前
Good addition. Java has done a few previews of this and is still trying to figure out the best way. Maybe the feedback on the Python version will help.
fmajid大约 1 个月前
These templates don’t seem to be semantically aware like Go’s html&#x2F;template that takes care of mitigating XSS for you, among other things.
评论 #43648637 未加载
behnamoh大约 1 个月前
Is it a replacement for Jinja2 templates? I use them a lot in LLM pipelines (e.g., to fill in the system prompt and provide more context).
评论 #43648094 未加载
评论 #43649936 未加载
评论 #43648544 未加载
throwaway7783大约 1 个月前
Making t-strings not actual strings but a different type is the genius here.<p>It is now be a generic expression evaluator and a template rendered!
est大约 1 个月前
&gt; If a single interpolation is expensive to evaluate, it can be explicitly wrapped in a lambda in the template string literal<p>&gt; <a href="https:&#x2F;&#x2F;peps.python.org&#x2F;pep-0750&#x2F;#approaches-to-lazy-evaluation" rel="nofollow">https:&#x2F;&#x2F;peps.python.org&#x2F;pep-0750&#x2F;#approaches-to-lazy-evaluat...</a><p>Hmm, I have a feeling there&#x27;s a pitfall.
wruza大约 1 个月前
As a python meh-er, this is actually good design. Everyone is jumping on C that it has no strings, but then other languages throw raw strings at you with some interpolation and call it a day. Also it&#x27;s 2025 and people will still comment &quot;do we need such a bloated string mechanism&quot; and then watch new devs produce bulks of injectionable strings.
pphysch大约 1 个月前
This could be a game-changer for applications that involve lots of HTML, SQL, or other languages that tend to be embedded within Python programs. Frankly, HTML templating is the worst part of Python webdev DX for me.<p>Excited to see what libraries and tooling comes out of this.
评论 #43648026 未加载
评论 #43647925 未加载
评论 #43647919 未加载
ray_v大约 1 个月前
Wait, I wasn&#x27;t supposed to be using f strings in SQL queries?! (don&#x27;t @ me)
meisel大约 1 个月前
Aside from sanitization, this also allows replication of Ruby’s %W[…] syntax
sakesun大约 1 个月前
I always think the coming of this feature is inevitable.
apothegm大约 1 个月前
Are these less useless for translation than f-strings?
AlienRobot大约 1 个月前
Thanks but I still use &quot;%s&quot; % (a,) the way I learned a dozen years ago and I&#x27;ll keep doing it until the day I die.
评论 #43648658 未加载
smitty1e大约 1 个月前
For a quick glance, I didn&#x27;t see the corner case where the old-style `%` interpolation (may) shine over PEP750: building up a JSON document with a dictionary:<p>&gt;&gt;&gt; hello_world = {&quot;hello&quot;:&quot;HELL&quot; ,&quot;world&quot;:&quot;O&#x27;WORLD&quot;}<p>&gt;&gt;&gt; json_template=&#x27;{&quot;hello&quot;:&quot;%(hello)s&quot;,&quot;world&quot;:&quot;%(world)s&quot;}&#x27;<p>&gt;&gt;&gt; print(json_template % hello_world)<p>{&quot;hello&quot;:&quot;HELL&quot;,&quot;world&quot;:&quot;O&#x27;WORLD&quot;}
epistasis大约 1 个月前
I&#x27;m quite disappointed with the pace of development of the Python language. Five years of support for a particular version seems far too short.<p>I mostly use Python in scientific contexts, and hitting end-of-life after five years means that for a lot project, code needs to transition language versions in the middle of a project. Not to mention the damage to reproducibility. Once something is marked &quot;end of life&quot; it means that future OS versions are going to have a really good reason to say &quot;this code shouldn&#x27;t even be <i>able</i> to run on our new OS.&quot;<p>Template strings seem OK, but I would give up all new language features in a heartbeat to get a bit of long term support.
评论 #43649760 未加载
评论 #43659790 未加载
评论 #43657055 未加载
ydnaclementine大约 1 个月前
can&#x27;t wait to have my linter tell me I should be using t-strings instead of f-strings. apologies for not being patient enough to read through this to find it, but I hope they can remove f-strings:<p>&gt; There should be one-- and preferably only one --obvious way to do it.
评论 #43647973 未加载
评论 #43648140 未加载
metadat大约 1 个月前
What kind of special string will be added next? We already have f-strings, .format, %s ...
评论 #43648988 未加载
otabdeveloper4大约 1 个月前
Aw sweet, a third way to do string interpolation in Python.<p>I&#x27;m really loving this lovecraftian space the &quot;batteries included&quot; and &quot;one obvious way to do it&quot; design philosophy brought us!
btilly大约 1 个月前
I dislike this feature.<p>The stated use case is to avoid injection attacks. However the primary reason why injection attacks work is that the easiest way to write the code makes it vulnerable to injection attacks. This remains true, and so injection attacks will continue to happen.<p>Templates offer to improve this by adding interpolations, which are able to do things like escaping. However the code for said interpolations is now located at some distance from the template. You therefore get code that locally looks good, even if it has security mistakes. Instead of one source of error - the developer interpolated - you now have three. The developer forgot to interpolate, the developer chose the wrong interpolation, or the interpolation itself got it wrong. We now have more sources of error, and more action at a distance. Which makes it harder to audit the code for sources of potential error.<p>This is something I&#x27;ve observed over my life. Developers don&#x27;t notice the cognitive overhead of all of the abstractions that they have internalized. Therefore over time they add more. This results in code that works &quot;by magic&quot;. And serious problems if the magic doesn&#x27;t quite work in the way that developers are relying on.<p>Templates are yet another step towards &quot;more magic&quot;. With predictable consequences down the road.
评论 #43648159 未加载
评论 #43648908 未加载
评论 #43650312 未加载
评论 #43649137 未加载
评论 #43648185 未加载
评论 #43648126 未加载
bhargavtarpara大约 1 个月前
prob dont need jinja anymore then
kazinator大约 1 个月前
15 minute implementation in TXR Lisp.<p>Background: TXR already Lisp has quasi-string-literals, which are template strings that do implicit interpolation when evaluated. They do not produce an object where you can inspect the values and fixed strings and do things with these before the merge.<p><pre><code> 1&gt; (let ((user &quot;Bob&quot;) (greeting &quot;how are you?&quot;)) `Hello @user, @greeting`) &quot;Hello Bob, how are you?&quot; </code></pre> The underlying syntax behind the `...` notation is the sys:quasi expression. We can quote the quasistring and look at the <i>car</i> (head symbol) and <i>cdr</i> (rest of the list):<p><pre><code> 2&gt; (car &#x27;`Hello @user, @greeting`) sys:quasi 3&gt; (cdr &#x27;`Hello @user, @greeting`) (&quot;Hello &quot; @user &quot;, &quot; @greeting) </code></pre> So that is a bit like f-strings.<p>OK, now with those pieces, I just right now made a macro <i>te</i> that gives us a template object.<p><pre><code> 4&gt; (load &quot;template&quot;) nil </code></pre> You invoke it with one argument as (te &lt;quasistring&gt;)<p><pre><code> 5&gt; (let ((user &quot;Bob&quot;) (greeting &quot;how are you?&quot;)) (te `Hello @user, @greeting`)) #S(template merge #&lt;interpreted fun: lambda (#:self-0073)&gt; strings #(&quot;Hello &quot; &quot;, &quot;) vals #(&quot;Bob&quot; &quot;how are you?&quot;)) 6&gt; *5.vals #(&quot;Bob&quot; &quot;how are you?&quot;) 7&gt; *5.strings #(&quot;Hello &quot; &quot;, &quot;) 8&gt; *5.(merge) &quot;Hello Bob, how are you?&quot; 9&gt; (set [*5.vals 0] &quot;Alice&quot;) &quot;Alice&quot; 10&gt; *5.(merge) &quot;Hello Alice, how are you?&quot; </code></pre> You can see the object captured the values from the lexical variables, and we can rewrite them, like changing Bob to Alice. When we call the <i>merge</i> method on the object, it combines the template and the values.<p>(We cannot alter the strings in this implementation; they are for &quot;informational purposes only&quot;).<p>Here is how the macro expands:<p><pre><code> 11&gt; (macroexpand-1 &#x27;(te `Hello @user, @greeting`)) (new template merge (lambda (#:self-0073) (let* ((#:vals-0074 #:self-0073.vals) (#:var-0075 [#:vals-0074 0]) (#:var-0076 [#:vals-0074 1])) `Hello @{#:var-0075}, @{#:var-0076}`)) strings &#x27;#(&quot;Hello &quot; &quot;, &quot;) vals (vec user greeting)) </code></pre> It produces a constructor invocation (new template ...) which specifies values for the slots <i>merge</i>, <i>strings</i> and <i>vals</i>.<p>The initialization of <i>strings</i> is trivial: just a vector of the strings pulled from the quasistring.<p>The <i>vals</i> slot is initialized by a `(vec ...)` call whose arguments are the expressions from the quasistring. This gets evaluated in the right lexical scope where the macro is expanded. This is how we capture those values.<p>The most complicated part is the <i>lambda</i> expression that initializes merge. This takes a single argument, which is the self-object, anonymized by a gensym variable for hygiene. It binds the <i>.vals</i> slot of the object to another gensym lexical. Then a genyms local variable is bound for each value, referencing into consecutive elements of the value vector. E.g. #:var-0075 is bound to [#:vals-0074 0], the first value.<p>The body of the <i>let</i> is a transformed version of the original template, in which the interpolated expressions are replaced by gensyms, which reference the bindings that index into the vector.<p>The complete implementation in template.tl (referenced by (load &quot;template&quot;) in command line 4) is:<p><pre><code> (defstruct template () merge strings vals) (defun compile-template (quasi) (match (@(eq &#x27;sys:quasi) . @args) quasi (let ((gensyms (build-list)) (exprs (build-list)) (strings (build-list)) (xquasi (build-list &#x27;(sys:quasi))) (self (gensym &quot;self-&quot;)) (vals (gensym &quot;vals-&quot;))) (while-true-match-case (pop args) ((@(eq &#x27;sys:var) @(bindable @sym)) exprs.(add sym) (let ((g (gensym &quot;var-&quot;))) gensyms.(add g) xquasi.(add g))) ((@(eq &#x27;sys:expr) @expr) exprs.(add expr) (let ((g (gensym &quot;expr-&quot;))) gensyms.(add g) xquasi.(add g))) (@(stringp @str) strings.(add str) xquasi.(add str)) (@else (compile-error quasi &quot;invalid expression in template: ~s&quot; else))) ^(new template merge (lambda (,self) (let* ((,vals (qref ,self vals)) ,*[map (ret ^(,@1 [,vals ,@2])) gensyms.(get) 0]) ,xquasi.(get))) strings &#x27;,(vec-list strings.(get)) vals (vec ,*exprs.(get)))))) (defmacro te (quasi) (compile-template quasi)) </code></pre> We can see an expansion:<p>That Lisp Curse document, though off the mark in general, was right the observation that social problems in languages like Python are just technical problems in Lisp (and often minor ones).<p>In Python you have to wait for some new PEP to be approved in order to get something that is like f-strings but gives you an object which intercepts the interpolation. Several proposals are tendered and then one is picked, etc. People waste their time producing rejected proposals, and time on all the bureucracy in general.<p>In Lisp land, oh we have basic template strings already, let&#x27;s make template objects in 15 minutes. Nobody else has to approve it or like it. It will backport into older versions of the language easily.<p>P.S.<p>I was going to have the template object carry a hash of those values that are produced by variables; while coding this, I forgot. If we know that an interpolation is @greeting, we&#x27;d like to be access something using the <i>greeting</i> symbol as a key.<p>(I don&#x27;t see any of this is as useful, so I don&#x27;t plan on doing anything more to it. It has no place in Lisp, because for instance, we would not take anything resembling this approach for HTML generation, or anything else.)
pjmlp大约 1 个月前
Yet another way to do strings in Python, I was more than happy with the original way with tupple parameters.