Linux迷+Python粉 - 技术https://blog.pythonwood.com/2023-10-13T18:18:00+08:00Python开发前端Web程序指南:无需写HTML、CSS、Javascript代码的多种实现概览2023-10-13T18:18:00+08:002023-10-10T22:12:00+08:00pythonwoodtag:blog.pythonwood.com,2023-10-13:/2023/10/Python开发前端Web程序指南:无需写HTML、CSS、Javascript代码的多种实现概览/<!-- ::: post-thumbnail ![](https://www.may69.com/wp-content/uploads/2022/07/chrome_woWckwQ8I6.png){.attachment-full .size-full .wp-post-image width="860" height="311" decoding="async" fetchpriority="high" srcset="https://www.may69.com/wp-content/uploads/2022/07/chrome_woWckwQ8I6.png 860w, https://www.may69.com/wp-content/uploads/2022/07/chrome_woWckwQ8I6-300x108.png 300w, https://www.may69.com/wp-content/uploads/2022/07/chrome_woWckwQ8I6-768x278.png 768w" sizes="(max-width: 860px) 100vw, 860px"} ::: post-info-wrap ::: post-cat ::: post-cats-list [[Python](https://www.may69.com/category/python/)]{.category-button .cb-cat-32} ::: ::: ::: entry-meta [[2022 年 7 月 23 日2023 年 3 月 22 日](https://www.may69.com/purepython/){rel="bookmark"}]{.posted-on}[[[混乱咒语](https://www.may69.com/author/admin/){.url .fn .n}]{.author .vcard}]{.byline} ::: # 纯Python开发前端Web程序指南:无需写HTML、CSS、Javascript代码的多种实现概览 # 实用介绍 --> <p>本指南旨在帮助您快速找到以Pure-Python方式进行Web前端应用程序开发解决方案,含【理论】和【实战】两个方面。如果您了解理论,请跳到下面的<a href="#Theoretical_Introduction">&ldquo;理论介绍&rdquo;部分</a>。否则只需直接跳至<a href="#Practical_Guide">实用指南</a>并选择适合您的内容阅读即可。</p> <h1 id="_1">理论介绍<a class="headerlink" href="#_1" title="Permanent link">&para;</a></h1> <p>欢迎来到 100% 纯 Python Web 开发世界 …</p><!-- ::: post-thumbnail ![](https://www.may69.com/wp-content/uploads/2022/07/chrome_woWckwQ8I6.png){.attachment-full .size-full .wp-post-image width="860" height="311" decoding="async" fetchpriority="high" srcset="https://www.may69.com/wp-content/uploads/2022/07/chrome_woWckwQ8I6.png 860w, https://www.may69.com/wp-content/uploads/2022/07/chrome_woWckwQ8I6-300x108.png 300w, https://www.may69.com/wp-content/uploads/2022/07/chrome_woWckwQ8I6-768x278.png 768w" sizes="(max-width: 860px) 100vw, 860px"} ::: post-info-wrap ::: post-cat ::: post-cats-list [[Python](https://www.may69.com/category/python/)]{.category-button .cb-cat-32} ::: ::: ::: entry-meta [[2022 年 7 月 23 日2023 年 3 月 22 日](https://www.may69.com/purepython/){rel="bookmark"}]{.posted-on}[[[混乱咒语](https://www.may69.com/author/admin/){.url .fn .n}]{.author .vcard}]{.byline} ::: # 纯Python开发前端Web程序指南:无需写HTML、CSS、Javascript代码的多种实现概览 # 实用介绍 --> <p>本指南旨在帮助您快速找到以Pure-Python方式进行Web前端应用程序开发解决方案,含【理论】和【实战】两个方面。如果您了解理论,请跳到下面的<a href="#Theoretical_Introduction">&ldquo;理论介绍&rdquo;部分</a>。否则只需直接跳至<a href="#Practical_Guide">实用指南</a>并选择适合您的内容阅读即可。</p> <h1 id="_1">理论介绍<a class="headerlink" href="#_1" title="Permanent link">&para;</a></h1> <p>欢迎来到 100% 纯 Python Web 开发世界, 向 <span class="caps">HTML</span>/<span class="caps">JS</span>/<span class="caps">CSS</span> 缝合怪说再见吧。早在 <span class="caps">WWW</span> 出现之前,100% 纯 Python Web 开发背后的驱动概念就已在经典软件工程文本&rdquo;计算机程序的结构和解释&rdquo;的第 4&nbsp;章中得到了体现:</p> <blockquote> <p>毫不夸张地说,这是编程中最基本的思想:\ <strong>决定编程语言中表达式含义的求值器只是另一个程序。</strong>\&nbsp;认识到这一点就需要改变我们作为程序员的形象。我们逐渐将自己视为语言的设计者,而不仅仅是他人设计的语言的使用者。</p> <p>阿贝尔森和萨斯曼&rdquo;计算机程序的结构和解释&rdquo;</p> </blockquote> <p>Python可以完成非常广泛领域的各种事情,当然也包含 使用Python开发Web前端应用程序,这是通过把Python作为生成 <span class="caps">CSS</span>/<span class="caps">HTML</span>/<span class="caps">JS</span>&nbsp;等目标语言代码的元语言方式进行的(译者:即python生成html+css+js/ts代码)!</p> <p>请您想一下,我们已经知道,使用Python字典处理<span class="caps">JSON</span>无比丝滑,使用类似lxml的工具库能方便地来生成<span class="caps">XML</span>。我的意思是用Python 处理 <span class="caps">XML</span> 和 <span class="caps">JSON</span> 的收益是无可争议的,且在编程时被广泛认可。因此同样地,我们正在寻求使用 Python 作为 <span class="caps">HTML</span>/<span class="caps">JS</span>/<span class="caps">CSS</span>&nbsp;的元语言。 </p> <p>这极大地简化和抽象了 Web 应用程序开发。在网络出现之前,图形应用程序主要是用单一语言开发的。文本应用还是这样。Web 应用程序经历了一些阶段,<a href="https://metacpan.org/pod/HTML::Seamstress#A-BRIEF-HISTORY-of-Dynamic-HTML-Generation-(Templating)">我在其他地方讨论过</a>:</p> <ol> <li>服务器端包括</li> <li><span class="caps">CGI</span>脚本</li> <li>Java&nbsp;小程序</li> <li>使用后端和前端开发的客户端-服务器部分页面重新加载的应用程序</li> </ol> <p>尽管我们处于第 4 阶段,但第 3 阶段是一种更加统一的 <span class="caps">GUI</span> 开发方法,与 Web 之前使用 X-windows 和 C/<span class="caps">TCL</span>/Smalltalk 开发 <span class="caps">GUI</span>&nbsp;应用程序的方式非常相似。</p> <p>目前问题的存在是因为&#8230;&#8230;</p> <h2 id="_2"><strong>网络从来就不是真正为应用程序设计的:</strong><a class="headerlink" href="#_2" title="Permanent link">&para;</a></h2> <p><span class="caps">WWW</span> 的设计目的是让任何人都可以浏览信息。应用程序是您下载并安装在个人计算机上的东西。但在我们意识到这一点之前,人们通过在此处添加一些 JQuery 或在那里添加一些 <span class="caps">PHP</span>&nbsp;来向网站添加越来越多的功能。不知不觉中,网站和网络应用程序之间的界限就变得模糊了。</p> <p><a href="https://github.com/kamranahmedse/developer-roadmap">虽然数据存储技术的变化相当缓慢,但正如您所见,</a>使用 Javascript 甚至 <span class="caps">CSS</span>&nbsp;进行开发的最佳方式发生了很大变化。</p> <p>在创造大量技术的狂热中,对强大软件开发的需求被抛在了后面。但有些人看到了其中的陷阱,并开始研究替代解决方案,使软件开发人员能够使用一种语言进行开发,同时生成 Web 应用程序所需的多种语言。在 Java 中,我们看到了<a href="https://www.zkoss.org/">zk</a>和<a href="https://vaadin.com/">Vaadin</a>。在 Scala 中,我们看到了<a href="https://www.youtube.com/watch?v=Ksoi6AG9nbA">令人兴奋的</a><a href="http://www.scala-js.org/">ScalaJS</a>实时编码,在 Smalltalk 中我们看到了<a href="http://seaside.st/">Seaside</a>。</p> <p>但最令人印象深刻的是,我们看到了<a href="http://impredicative.com/ur/">UrWeb&#8212;&#8212;&#8212;</a>一种受 <span class="caps">ML</span> 启发的元语言,它生成类型安全的后端和前端代码,从而防止现代 Web&nbsp;开发遇到的所有问题:</p> <ul> <li>代码注入攻击</li> <li>无效的 <span class="caps">HTML</span></li> <li>应用程序内无效链接</li> <li><span class="caps">HTML</span>&nbsp;表单与其处理程序期望的字段之间不匹配</li> <li>对远程 Web 服务器提供的 <span class="caps">AJAX</span>&nbsp;样式服务作出错误假设的客户端代码</li> <li>无效的 <span class="caps">SQL</span>&nbsp;查询</li> <li>与 <span class="caps">SQL</span> 数据库或浏览器和 Web&nbsp;服务器之间的通信中的不正确编组或解组</li> </ul> <h2 id="python-web"><strong>因此我们明白为什么纯 Python Web 开发是必要的:</strong><a class="headerlink" href="#python-web" title="Permanent link">&para;</a></h2> <ul> <li>安全</li> <li>易于开发</li> <li>学习一种语言,而不是 3&nbsp;种或更多快速变化的语言</li> </ul> <h2 id="nojs-web-python"><strong><span class="caps">NOJS</span> Web 开发的 Python 方法概述</strong><a class="headerlink" href="#nojs-web-python" title="Permanent link">&para;</a></h2> <p>我们将其称为&rdquo;<span class="caps">NOJS</span>&rdquo;Web 开发,因为正如<a href="https://qooxdoo.org/">Qooxdoo</a>所示,使用 Javascript,您可以生成和操作 <span class="caps">CSS</span> 和 <span class="caps">HTML</span>。所以 <span class="caps">JS</span>&nbsp;是根,其他一切都从那里生长。</p> <h2 id="javascript"><strong>我该如何避免使用 JavaScript?让我来计算一下&hellip;</strong><a class="headerlink" href="#javascript" title="Permanent link">&para;</a></h2> <p>Python 领域有 3 种主要类型的产品,可让您使用 Python 进行开发,同时交付现代动态的全功能 Web&nbsp;应用程序:</p> <ol> <li><strong>转译器</strong>&ndash; 这些产品主要涉及将 Python 直译为 <span class="caps">JSS</span>/<span class="caps">CSS</span>/<span class="caps">HTML</span>/Web&nbsp;程序集。</li> <li><strong>应用程序套件</strong>-&nbsp;这些产品旨在消除部署工业强度应用程序的大部分或全部问题。</li> <li><strong>构建器</strong>介于转译器和应用程序套件之间。在大多数情况下,构建器(或转译器)与传统的终端服务器 Web 应用程序框架(如 Flask 或 Django)一起使用。<strong><em>但是,正如 Dash 用户过去所</em></strong>经历的那样,将构建器输出集成到全套 Web 应用程序中可能会遇到<a href="https://www.reddit.com/r/Python/comments/p109o0/lona_a_web_framework_for_responsive_web_apps_in/h8aty2l?utm_source=share&amp;utm_medium=web2x&amp;context=3">相当大的痛苦,但随着</a><a href="https://github.com/GibbsConsulting/django-plotly-dash">django-plotly-dash</a>的推出,这对于 Dash 来说不再是问题。**<a href="https://github.com/GibbsConsulting/django-plotly-dash"></a></li> </ol> <h1 id="_3">实用指南<a class="headerlink" href="#_3" title="Permanent link">&para;</a></h1> <p>实用指南分为&rdquo;类&rdquo;。在许多情况下,B 类解决方案与 A 类解决方案一样好。A 类解决方案是针对您可能需要在世界级 Web 应用程序中处理的任何功能的完整解决方案,为数千甚至数百万用户提供数十万次点击。B&nbsp;类解决方案解决特定问题并做得很好。</p> <p>最近 Reddit Python 上有一篇文章,其中一个人需要一个简单的 <span class="caps">UI</span> 来上传文件,然后运行一个进程。我推荐了 B 类解决方案<a href="https://www.may69.com/purepython/#Gradio">Gradio</a>,他用几行 Python&nbsp;就创建了一个漂亮的应用程序,满足了他和他的教授的需求。</p> <p>所以A类和B类是很好的解决方案。C 类和 D&nbsp;类在某些方面有所欠缺,但仍可能有一些用处。</p> <h2 id="a">A 类系统的要求<a class="headerlink" href="#a" title="Permanent link">&para;</a></h2> <ol> <li>它可以直接或通过与另一个功能齐全的框架轻松集成而功能齐全<strong>。</strong>这些要求已经到位,这样人们就不会因为无法扩展以适应不断变化的需求的闪亮的短期解决方案而感到困惑。Streamlit、Gradio 等非常适合单用户 Web 应用程序,但它们并没有提供演进为成熟的工业强度 Web 应用程序的途径。简而言之:除非产品可以直接或通过轻松集成完成<a href="https://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-i-hello-world">Miguel Grinberg 的 Flask Mega 教程</a>中的所有内容,否则它的功能并不完整。</li> <li><strong>维护良好</strong>&#8212;&#8212;&#8212;任何超过 1&nbsp;年没有源代码更新的东西都不能被认为是维护良好的。如果存在严重的未决问题和拉取请求,这也会考虑在内。</li> <li><strong>文档齐全</strong>&#8212;&#8212;&#8212;理想情况下,所有主要形式的文档都存在&#8212;&#8212;&#8212;常见问题解答、教程、指南和参考。</li> <li><strong>良好的支持渠道</strong>&#8212;&#8212;&#8212;快速准确地响应社区问题是必须的。</li> <li>(<a href="https://www.reddit.com/r/Python/comments/zhea3t/comment/izm996l/?utm_source=share&amp;utm_medium=web2x&amp;context=3">新的软标准</a>)它必须能够<strong>扩展以每秒处理 100 万个请求</strong>或更多。在您的个人 Macbook pro 上运行可爱的小玩具应用程序固然不错,但世界排名前 100 的网络资产对无缝处理大量流量的要求要高得多。如果 Web 解决方案无法生成像 amazon.com 这样的网站并像 amazon.com 一样处理 Web&nbsp;流量,那么为当地理发师构建玩具应用程序可能还可以,但它永远无法在要求严格的工业环境中在顶级水平生存。</li> </ol> <h2 id="a_1">A级:工业强度坚如磐石的产品<a class="headerlink" href="#a_1" title="Permanent link">&para;</a></h2> <p>在本节中,我们列出了正在解决实际问题并准备好进行生产部署的产品&#8230;&#8230;只需下载、安装并按照说明操作即可立即为您的问题找到解决方案,因为数百个其他产品已经做了同样的事情。</p> <h3 id="anvil"><strong>anvil</strong>(译者:第一位是软广告,可跳过)<a class="headerlink" href="#anvil" title="Permanent link">&para;</a></h3> <p><a href="http://anvil.works/">http://anvil.works</a>是基于云 Web 环境中提供的所有 Web&nbsp;开发的抽象。它是一款免费增值产品。</p> <p><a href="https://www.reddit.com/r/Python/comments/vqgkuj/comment/iep4jgm/?utm_source=share&amp;utm_medium=web2x&amp;context=3">reddit上有人</a>真的很喜欢Anvil:</p> <p>对我来说,最终的选择是关于<em>生产力</em>。Anvil 并不是一个&rdquo;生成 <span class="caps">HTML</span> 和 <span class="caps">JS</span>&rdquo;的孤立工具。它是一个集成套件,包含构建和部署完整的全栈软件项目所需的所有工具,使用纯 Python:数据库和可视化 <span class="caps">UI</span> 构建器、服务器和客户端功能,以及基本功能(用户管理、电子邮件、Web <span class="caps">API</span>、<span class="caps">PDF</span> 打印) 、Git 集成和版本管理、Google 服务集成等)全部内置。Anvil 的整体设计、<span class="caps">API</span> 范围、部署功能以及它汇集的所有功能(远远超出 <span class="caps">HTML</span>、 <span class="caps">CSS</span> 和 <span class="caps">JS</span> 生成),再加上原生可用的完整 Python 生态系统所支持的广泛功能,这使得它具有极高的生产力,与我见过的其他系统(编写代码 40&nbsp;多年)不同。</p> <h4 id="skulpt">建立在skulpt[雕塑]之上<a class="headerlink" href="#skulpt" title="Permanent link">&para;</a></h4> <p>Anvil 在底层使用了&nbsp;skulpt。</p> <h4 id="-">参考文章-刊物<a class="headerlink" href="#-" title="Permanent link">&para;</a></h4> <p><span class="dquo">&ldquo;</span><a href="https://anvil.works/learn/tutorials/jupyter-notebook-to-web-app">将 Jupyter Notebook 变成 Web 应用程序</a>&ldquo;</p> <h4 id="demo-gallery">实例走廊(Demo Gallery)<a class="headerlink" href="#demo-gallery" title="Permanent link">&para;</a></h4> <p><span class="dquo">&ldquo;</span>每天制作 <span class="caps">YC</span> 初创公司原型 &ndash; <a href="https://anvil.works/learn/examples/meter-feeder">Meter Feeder(<span class="caps">YC</span> 冬季 16)</a>&nbsp;&ldquo;</p> <p><a href="https://anvil.works/learn/examples/magic"><span class="caps">YC</span> 原型 #2:在 2.4&nbsp;小时内构建魔法</a></p> <h3 id="panel"><strong>Panel</strong><a class="headerlink" href="#panel" title="Permanent link">&para;</a></h3> <p>Panel是<a href="https://holoviz.org/index.html">令人印象深刻的工具堆栈</a>的一部分。它专注于使可视化变得简单而强大。</p> <h4 id="bokeh">基于Bokeh构建<a class="headerlink" href="#bokeh" title="Permanent link">&para;</a></h4> <h4 id="demo-gallery_1">实例走廊(Demo Gallery)<a class="headerlink" href="#demo-gallery_1" title="Permanent link">&para;</a></h4> <p><a href="https://awesome-panel.org/">awesome&nbsp;panel</a></p> <h3 id="dash"><strong>Dash</strong><a class="headerlink" href="#dash" title="Permanent link">&para;</a></h3> <p><a href="https://plotly.com/dash/">Dash</a>有几个引人注目的要点:</p> <ul> <li>人们可以构建真正的交互式分析应用程序,而不是被动的仪表板:应用程序可以具有表单和按钮来接收输入并实时更新图形仪表板。</li> <li>适用于桌面和移动设备,并且可以按需生成可打印的 <span class="caps">PDF</span>:有 2 个(<a href="https://www.youtube.com/watch?v=1LqFL2536QI&amp;lc=Ugyzx2IynJWPwheN2Fl4AaABAg.9kcWO5vSWMV9kcYq4snDD4">相互竞争的?</a>)响应式 <span class="caps">UI</span> 开发标准:dash mantine 和 dash&nbsp;bootstrap。 </li> <li>有dash和dash企业版。企业版还具有其他高级功能,例如允许最终用户运行 <span class="caps">GPU</span>&nbsp;加速工作流程以异步处理数亿条记录。</li> </ul> <h4 id="_4"><a class="headerlink" href="#_4" title="Permanent link">&para;</a></h4> <h4 id="plotly-reactjs">基于plotly 和ReactJS 构建<a class="headerlink" href="#plotly-reactjs" title="Permanent link">&para;</a></h4> <h4 id="_5">资源<a class="headerlink" href="#_5" title="Permanent link">&para;</a></h4> <p>Ann Marie Ward 拥有 30 多个包含初级和高级 Dash 材料的存储库。<a href="https://nostarch.com/book-dash">她是《破折号之书</a>》的合著者。几个亮点:</p> <ul> <li><a href="https://github.com/AnnMarieW/dash-multi-page-app-demos">多页面应用程序示例</a>&ndash; 现代 Dash&nbsp;已经超越了单页面应用程序。</li> </ul> <p><a href="https://github.com/GibbsConsulting/django-plotly-dash">django-plotly-dash</a> &ndash; 将 <a href="https://plot.ly/products/dash/">plotly dash</a> 应用程序公开为 <a href="https://www.djangoproject.com/">Django</a> 标签。然后,多个 Dash&nbsp;应用程序可以嵌入到单个网页中,保留并共享内部状态,并且还可以访问当前用户和会话变量。</p> <h4 id="_6">讨论和出版物<a class="headerlink" href="#_6" title="Permanent link">&para;</a></h4> <p><span class="dquo">&ldquo;</span>Pip 安装 Plotly-Dash | <a href="https://www.reddit.com/r/Python/comments/1060efc/pip_install_plotlydash_top_10_useful_resources/">在框架内学习/构建仪表板的十大有用资源</a>&rdquo;&#8212;&#8212;&#8212;<strong>强烈推荐视频和 YouTube 频道</strong>。</p> <p><a href="https://www.reddit.com/r/Python/comments/zo4ctd/dash_dashboards_multipaged_quick_development_with/"><span class="dquo">&ldquo;</span>Dash 仪表板,使用Python 和 React 教程</a>进行多页面快速开发&rdquo;</p> <p><a href="https://link.medium.com/GtsQEdqt7eb">https://link.medium.com/GtsQEdqt7eb</a></p> <p><span class="dquo">&ldquo;</span><a href="https://www.reddit.com/r/Python/comments/wwsz88/quick_intro_to_dash_plotly/?utm_source=share&amp;utm_medium=web2x&amp;context=3">dash快速介绍</a>&ldquo;</p> <p>&rdquo; <a href="https://medium.com/plotly/dash-is-react-for-python-r-and-julia-c75822d1cc24">Dash 是 Python、R 和 Julia 的 React</a>&nbsp;&ldquo;</p> <h4 id="_7">应用领域<a class="headerlink" href="#_7" title="Permanent link">&para;</a></h4> <p><span class="dquo">&ldquo;</span><a href="https://www.reddit.com/r/Python/comments/zlvsdq/plotlydash_is_the_best_framework_for_frontend/">在我看来,Plotly/Dash 是前端开发的最佳框架</a>&ldquo;</p> <p><a href="https://dash-gallery.plotly.host/Portal/">应用程序库</a></p> <h4 id="ca">从C级到A级<a class="headerlink" href="#ca" title="Permanent link">&para;</a></h4> <p>本指南的目标是对那些使简单的 Web 工作变得简单<strong>并</strong>允许您在必要时扩展以开发下一个前 100 名 Web 资产的框架进行评级。等级分级系统的设置是为了确保只有高度可靠、稳健<strong>且</strong>功能齐全的产品才能被评为 A 级。dash曾一度接近 C 级,因为我的研究显示,<a href="https://www.reddit.com/r/Python/comments/wedvzi/comment/iip8vmf/?utm_source=share&amp;utm_medium=web2x&amp;context=3">一位前用户</a>表示:</p> <p>如果这是一个简单的项目,当然可以。</p> <blockquote> <p>不然就太可怕了。我们从 dash 切换到 fastapi +&nbsp;React。从此无怨无悔。</p> <p><a href="https://www.reddit.com/user/TheGuyWithoutName/">无名之人</a>\</p> </blockquote> <p>但<a href="https://www.reddit.com/r/Python/comments/1060efc/pip_install_plotlydash_top_10_useful_resources/">最近在 reddit 上发表的一篇文章</a>表明,<strong><em>Dash 可以做到这一切</em></strong>&#8212;&#8212;&#8212;简单的事情、Jupyter 的事情,是的,还有前 100&nbsp;个网络财产的事情。</p> <h3 id="nicegui">NiceGUI<a class="headerlink" href="#nicegui" title="Permanent link">&para;</a></h3> <p><a href="https://nicegui.io/">NiceGUI</a>有一个非常干净且文档齐全的 <span class="caps">API</span>,作者在其之上构建了很好的可交付成果,例如<a href="https://github.com/zauberzeug/rosys">rosys</a>。</p> <p>一位贡献者为我们提供了 <a href="https://www.reddit.com/r/Python/comments/10d6ugv/comment/j4mkaap/?utm_source=embedv2&amp;utm_medium=comment_embed&amp;utm_content=whitespace&amp;embed_host_url=https%3A%2F%2Fwww.may69.com%2Fpurepython%2F">NiceGUI 当前内部工作原理的概览</a>:</p> <blockquote> <p>NiceGUI 启动一个后端 Web 服务器(运行 FastAPI),然后在指定的路由上提供 html、css 和 javascript。当浏览器请求页面时,前端代码会使用唯一的客户端 <span class="caps">ID</span> 与后端建立 Websocket 连接。当用户按下按钮时,事件会通过 websocket 发送到后端。然后后端执行注册的 Python 代码并通过 websocket 发回任何 <span class="caps">UI</span>&nbsp;更新。</p> <p>虽然很简短,但我希望它能让您对内部结构有一个基本的了解。如果您想了解更多详细信息,请向我提出后续问题。&nbsp;:::</p> </blockquote> <h4 id="streamlit"><span class="dquo">&ldquo;</span>感谢 Streamlit&rdquo;<a class="headerlink" href="#streamlit" title="Permanent link">&para;</a></h4> <p>Streamlit 在 B 类领域获得了广泛采用,但我们对 Streamlit&nbsp;进行了重新审视</p> <blockquote> <p><a href="https://github.com/zauberzeug/nicegui/issues/1#issuecomment-847413651">在状态处理方面</a>它发挥了 太多的魔力。</p> </blockquote> <p>NiceGUI 作者<a href="https://github.com/zauberzeug/nicegui/discussions/21#discussioncomment-2209467">在这里更深入地探讨了 Streamlit 的缺点</a>。</p> <h4 id="_8"><a class="headerlink" href="#_8" title="Permanent link">&para;</a></h4> <h4 id="fastapi">基于 FastAPI 构建<a class="headerlink" href="#fastapi" title="Permanent link">&para;</a></h4> <p>NiceGUI 的作者出于<a href="https://github.com/zauberzeug/nicegui/discussions/135#discussioncomment-4053253">某些特定原因</a>选择了 FastAPI ,尽管<a data-id="1315" data-type="post" href="https://www.may69.com/starlite/">我个人的研究会让我选择 Starlite</a>。现在您可以在 NiceGUI 中编写功能齐全的 Web&nbsp;应用程序。</p> <h4 id="_9">不可链接的锚标签:<a class="headerlink" href="#_9" title="Permanent link">&para;</a></h4> <p>值得称赞的是,NiceGUI 网站是在 NiceGUI 本身中实现的。也就是说,NiceGUI 生成的锚标记没有属性<code>name</code>,因此您无法直接链接到 NiceGUI&nbsp;生成的页面的某些部分。</p> <h4 id="demo-gallery_2">实例走廊(Demo Gallery)<a class="headerlink" href="#demo-gallery_2" title="Permanent link">&para;</a></h4> <p>交互式图像 -<a href="https://www.reddit.com/r/Python/comments/10d6ugv/comment/j4ly3p7/?utm_source=share&amp;utm_medium=web2x&amp;context=3">讨论和演示链接</a></p> <p>执行自定义 <span class="caps">JS</span> &ndash;<a href="https://www.reddit.com/r/Python/comments/10d6ugv/comment/j4ol07n/?utm_source=share&amp;utm_medium=web2x&amp;context=3">讨论和演示链接</a></p> <h4 id="_10">讨论<a class="headerlink" href="#_10" title="Permanent link">&para;</a></h4> <p><span class="dquo">&ldquo;</span>NiceGUI:让任何浏览器成为<a href="https://www.reddit.com/r/Python/comments/10d6ugv/nicegui_let_any_browser_be_the_frontend_for_your/">Python 代码的前端</a>&ldquo;</p> <p>NiceGUI 与 JustPy &ndash;<a href="https://github.com/zauberzeug/nicegui/discussions/247">内容丰富的讨论</a>。</p> <h3 id="idom-reactpy"><strong><span class="caps">IDOM</span> (已改名ReactPy)</strong><a class="headerlink" href="#idom-reactpy" title="Permanent link">&para;</a></h3> <p><a href="https://github.com/idom-team/idom">https://github.com/idom-team/idom</a>可能是典型的构建器库 - 它与 Flask、Django、FastAPI 和<a href="https://github.com/idom-team/idom">其他 4 个框架</a>集成&#8230;&#8230;并且相同的 <span class="caps">IDOM</span>&nbsp;组件可以在所有这些框架中运行而无需修改。</p> <blockquote> <p><strong><span class="caps">IDOM</span> 将您选择的 Python Web 框架连接到 ReactJS 前端,让您无需 JavaScript 即可</strong>创建 交互式网站!</p> <p><a href="https://github.com/idom-team/idom">https://github.com/idom-team/idom</a></p> </blockquote> <p><a href="https://idom-docs.herokuapp.com/docs/index.html">该项目的文档</a>非常全面。他们有<a href="https://github.com/idom-team/idom/discussions">一个活跃的讨论区</a>。并且<a href="https://github.com/idom-team/idom">git repo</a>经常更新。绝对是一种引人注目的 A 类纯 Python Web&nbsp;应用程序开发方法。</p> <h4 id="reactjs">基于 ReactJS 构建<a class="headerlink" href="#reactjs" title="Permanent link">&para;</a></h4> <h4 id="_11">讨论<a class="headerlink" href="#_11" title="Permanent link">&para;</a></h4> <p>在<a href="https://www.reddit.com/r/Python/comments/smdgxl/idom_reactjs_for_any_python_web_framework/">本次讨论</a>中,我们了解到 <span class="caps">IDOM</span><a href="https://idom-docs.herokuapp.com/docs/reference-material/faq.html#does-idom-transpile-python-to-javascript">不会转换为 JavaScript</a>。这使得纯组件函数能够完全兼容并移植到任何支持 websocket 的 Python Web&nbsp;框架。</p> <h3 id="epyk"><strong>Epyk</strong><a class="headerlink" href="#epyk" title="Permanent link">&para;</a></h3> <p><a href="https://epyk-ui.readthedocs.io/en/latest/">Epyk</a>与最常见的 Web Python 框架(即 Flask 和 Django)兼容。默认情况下,服务器包嵌入 Flask&nbsp;应用程序,因为它更易于安装和使用。</p> <p>它有很好的文档和一个很好的工作程序库</p> <h3 id="flet"><strong>Flet</strong><a class="headerlink" href="#flet" title="Permanent link">&para;</a></h3> <p><a href="https://flet.dev/">Flet</a>允许您使用 Python 构建 Flutter&nbsp;应用程序。这是一件大事,因为</p> <blockquote> <p>Flutter 是 Google&nbsp;的一个开源框架,用于从单个代码库构建漂亮的、本机编译的多平台应用程序。</p> </blockquote> <p>我们在这里谈论的是真正的力量。<a href="https://www.may69.com/purepython/#Htag">它基本上是Htag</a>的企业支持版本,这是具有类似功能的巨大的单一开发人员的努力。另一个类似的老产品是<a href="https://www.may69.com/purepython/#Muntjac">Muntjac ,它是</a><a href="https://vaadin.com/">Vaadin</a>到&nbsp;Python的端口,不再受到积极支持。</p> <h4 id="_12">讨论<a class="headerlink" href="#_12" title="Permanent link">&para;</a></h4> <ul> <li><span class="dquo">&ldquo;</span><a href="https://www.reddit.com/r/Python/comments/wzx891/combining_flet_with_fastapi/?utm_source=share&amp;utm_medium=web2x&amp;context=3">将 Flet 与 FastAPI 相结合</a>&ldquo;</li> <li>&rdquo; <a href="https://www.reddit.com/r/Python/comments/zfwqab/python_is_great_for_gui_uifront_end_design_if_you/">Python 非常适合 <span class="caps">GUI</span> (<span class="caps">UI</span>)/前端设计。如果您真的想为无聊的 Python 脚本提供一个漂亮的用户界面,那么您绝对应该查看这个 30 分钟的教程。这里将使用一个名为 Flet 的 Flutter for Python 库。而且它是跨平台的!</a>&ldquo;</li> </ul> <h3 id="pynecone-reflex">Pynecone (已改名reflex)<a class="headerlink" href="#pynecone-reflex" title="Permanent link">&para;</a></h3> <p>Pynecone  <a href="https://www.reddit.com/r/Python/comments/zh0pmy/comment/izkpfpx/?utm_source=share&amp;utm_medium=web2x&amp;context=3">编译为传统的 React(NextJS 风格)应用程序</a>。包装 React 组件非常简单。作者过去曾使用过 Streamlit,并发现它非常适合上手,但对于更复杂的应用程序来说,<a href="https://www.reddit.com/r/Python/comments/zh0pmy/comment/izl8zbs/?utm_source=share&amp;utm_medium=web2x&amp;context=3">发现它在组件、样式和性能方面存在限制</a>。在 Pynecone 中,前端编译为 NextJS 应用程序,因此您可以完全自定义应用程序的外观。Streamlit 在某些情况下也可能很慢,因为它会根据用户事件重新运行整个脚本,而在 Pynecone 中仅传输状态增量。对于性能和 <span class="caps">SEO</span> 来说,nextjs&nbsp;也很棒。</p> <h4 id="_13">可扩展性随手可得!<a class="headerlink" href="#_13" title="Permanent link">&para;</a></h4> <p>Pynecone 具有出色的可扩展性:您可以水平扩展服务器并将其连接到 Redis 实例,以便它们可以访问用户状态。作者在后台使用 FastAPI 作为他们的 Python&nbsp;服务器来处理前端事件并发送回状态增量。</p> <p>此外,在生产模式下运行 Pynecone 应用程序时,您可以使用 NextJS <span class="caps">SSG</span> 将整个前端预渲染为&nbsp;html。</p> <h4 id="_14">参考链接<a class="headerlink" href="#_14" title="Permanent link">&para;</a></h4> <ul> <li><a href="https://pynecone.io/">官方网站</a></li> <li><a href="https://github.com/pynecone-io/pynecone">github</a></li> </ul> <h4 id="demo-gallery_3">实例走廊(Demo Gallery)<a class="headerlink" href="#demo-gallery_3" title="Permanent link">&para;</a></h4> <ul> <li><a href="https://pynecone.io/docs/gallery">https://pynecone.io/docs/gallery</a></li> </ul> <h4 id="_15">讨论<a class="headerlink" href="#_15" title="Permanent link">&para;</a></h4> <ul> <li><a href="https://www.reddit.com/r/Python/comments/zh0pmy/pynecone_web_apps_in_pure_python/">https://www.reddit.com/r/Python/comments/zh0pmy/pynecone_web_apps_in_pure_python</a>&nbsp;/</li> <li><span class="dquo">&ldquo;</span><a href="https://news.ycombinator.com/item?id=33922754#33926335">显示 <span class="caps">HN</span> 2022 年 12 月 14 日</a>&ldquo;</li> </ul> <h3 id="lona"><strong>Lona</strong><a class="headerlink" href="#lona" title="Permanent link">&para;</a></h3> <p><a href="https://github.com/fscherf/lona">https://github.com/fscherf/lona</a>支持<a href="https://lona-web.org/cookbook/integrating-django.html">Django 模型</a>和<a href="https://lona-web.org/contrib/django-auth.html">Django auth 系统</a>的使用。</p> <p>为了考虑用 python 编写的大型 <span class="caps">HTML</span> 树,<a href="https://www.reddit.com/r/Python/comments/p109o0/lona_a_web_framework_for_responsive_web_apps_in/h8asc0i?utm_source=share&amp;utm_medium=web2x&amp;context=3">Lona 支持小部件</a>来封装较小的树及其功能。这使得组件可以重复使用。</p> <p>Lona 有一种异步方法,允许人们在一个函数和一个上下文中编写整个视图。作者<a href="https://www.reddit.com/r/Python/comments/p109o0/lona_a_web_framework_for_responsive_web_apps_in/h8ejjyj?utm_source=share&amp;utm_medium=web2x&amp;context=3">认为这会导致代码更加简洁</a>。</p> <p><a href="https://www.reddit.com/r/Python/comments/p109o0/lona_a_web_framework_for_responsive_web_apps_in/h8dlv5j?utm_source=share&amp;utm_medium=web2x&amp;context=3">据作者介绍,</a> Lona基于aiohttp,内部使用asyncio。Lona <span class="caps">API</span> 完全同步,使开发更加容易。相比之下,使用 asyncio,甚至可以在没有注意到的情况下阻塞整个服务的核心事件循环。因此,Lona 定义了一个类似于 asyncio 的 <span class="caps">API</span>,但可以与阻塞代码无缝集成。</p> <h4 id="_16">讨论<a class="headerlink" href="#_16" title="Permanent link">&para;</a></h4> <ul> <li><a href="https://www.reddit.com/r/Python/comments/ptcje9/lona_a_web_framework_for_responsive_web_apps_in/">https://www.reddit.com/r/Python/comments/ptcje9/lona_a_web_framework_for_responsive_web_apps_in/</a></li> <li><a href="https://www.reddit.com/r/Python/comments/p109o0/lona_a_web_framework_for_responsive_web_apps_in/">https://www.reddit.com/r/Python/comments/p109o0/lona_a_web_framework_for_responsive_web_apps_in/</a></li> <li><a href="https://www.reddit.com/r/Python/comments/qasyxe/true_multi_user_applications_with_lona_174/">https://www.reddit.com/r/Python/comments/qasyxe/true_multi_user_applications_with_lona_174/</a></li> <li><a href="https://www.reddit.com/r/lona_web_org/">https://www.reddit.com/r/lona_web_org/</a></li> <li></li> </ul> <h3 id="nagare"><strong>Nagare [流]</strong><a class="headerlink" href="#nagare" title="Permanent link">&para;</a></h3> <p><a href="https://github.com/nagareproject/core#readme">Nagare</a>获得了 A 级排名。它已经存在十多年了,是最早提供纯 Python 方法进行 Web 应用程序开发的框架之一。它非常完整,他们的咨询公司已经交付了几个令人印象深刻的大型应用程序。当我使用它向一家财富 500&nbsp;强公司部署应用程序时,他们非常支持我。它在很大程度上是一件艺术品和创造力的作品。</p> <p>话虽这么说,它只有简单的 <span class="caps">JS</span> 到 Python&nbsp;的转换,主要限于链接/按钮的&rdquo;onclick&rdquo;事件。</p> <p>它的灵感来自于<a href="http://seaside.st/">Smalltalk 的 Seaside 框架</a>。</p> <p>它基于基于组件的面向对象而不是继承。</p> <p>它并不是为了利用 Javascript&nbsp;的所有功能来创建反应式、高度交互的应用程序。</p> <p>话虽这么说,如果您的愿望是面向对象的 <span class="caps">HTML</span> 生成接口到背面的对象关系存储&nbsp;(SQLAlchemy),那么对于此目的来说,它是非常禅宗的。</p> <p>它被归类为 A 类,因为它可以解决问题。它与 B 类接壤,因为它不能提供所有 javascript 功能。此外,《Nagare》的作者也没有兑现将麂融入《Nagare》的承诺。Muntjac 是一个 Python 程序,它将整个<a href="https://vaadin.com/">Vaadin</a>小部件集引入 Python,从而打造出美观的专业 Web&nbsp;应用程序。</p> <h3 id="reahl">Reahl<a class="headerlink" href="#reahl" title="Permanent link">&para;</a></h3> <p><a href="https://www.reahl.org/">Reahl</a>是另一个勉强维持 A 级评级的工具。该框架的主要优点是它拥有大量开箱即用的小部件,可用于完成成熟的 Web&nbsp;应用程序。我在一个咨询项目中使用了它,并且不需要在它之外寻找任何东西。</p> <p>作者非常聪明且反应灵敏。我鼓励您在选择它之前仔细研究它的 Web 应用程序开发方法。另请阅读讨论组和已关闭的问题。坦白说,我与开发商在某些选择上的看法并不一致。但总而言之,我对他们在我与 Reahl 合作的一个成功完成的企业项目中给予我的快速支持表示赞赏。虽然 Nagare 和 Reahl 都是面向对象的超成熟系统,但它们以截然不同的方式拥抱 <span class="caps">OO</span>&nbsp;Python。</p> <h2 id="b">B 类:某些项目完全可接受的构建块<a class="headerlink" href="#b" title="Permanent link">&para;</a></h2> <p>在本节中,我们将看到实现良好、记录良好的 pure-python-web-dev 的出色方法。请注意,B 类包含许多工业级&rdquo;构建器&rdquo;和&rdquo;转译器&rdquo;,这意味着即使您不会在大多数领域直接使用它们,它们也是当前可行的 A 类解决方案的动力。例如,Anvil 是一个 A 类纯 python-web 框架。但如果没有 Skulpt(B&nbsp;级产品),这一切都是不可能的。</p> <h3 id="gradio">Gradio<a class="headerlink" href="#gradio" title="Permanent link">&para;</a></h3> <p><a href="https://gradio.app/">Gradio</a>可以通过易于使用的用户界面包装几乎所有 Python&nbsp;函数。该函数可以是从图像增强器到税收计算器的任何函数,但最常见的是预训练机器学习模型的预测函数。</p> <p>Gradio 允许人们快速创建界面(从控制台或 Jupyter 笔记本或<a href="https://huggingface.co/pricing">https://huggingface.co/spaces</a>)并&rdquo;launch()&rdquo;它们。 </p> <p>但也可以自定义 <span class="caps">UI</span>&nbsp;组件的外观和/或行为。</p> <p>从我的角度来看,缺点是:</p> <ol> <li>目前尚不清楚如何将 Gradio&nbsp;的输出集成到成熟的网络应用程序中。 </li> <li>它仅提供基于密码的身份验证。 </li> <li>不支持授权</li> </ol> <h4 id="_17">相关出版物<a class="headerlink" href="#_17" title="Permanent link">&para;</a></h4> <p><span class="dquo">&ldquo;</span><a href="https://medium.com/@duerr.sebastian/making-neural-search-queries-accessible-to-everyone-with-gradio-haystack-726e77aca047">通过 Gradio 让每个人都能进行神经搜索查询</a>&ldquo;</p> <p><span class="dquo">&ldquo;</span><a href="https://www.reddit.com/r/Python/comments/xonx2g/dashboard_for_audio_summarization_sentiment/">用于音频摘要、情感分析等的仪表板!</a>&rdquo; &ndash;<a href="https://www.assemblyai.com/blog/getting-started-with-huggingfaces-gradio/">文章链接</a></p> <h3 id="_18"><a class="headerlink" href="#_18" title="Permanent link">&para;</a></h3> <h3 id="_19"><a class="headerlink" href="#_19" title="Permanent link">&para;</a></h3> <h3 id="shiny-for-python">Shiny for Python<a class="headerlink" href="#shiny-for-python" title="Permanent link">&para;</a></h3> <p><a href="https://shiny.rstudio.com/py/">Shiny for Python</a>拥有干净的 <span class="caps">API</span> 和良好的文档。与许多 B 类解决方案一样,它缺乏完整 Web 应用程序的功能 &ndash;&nbsp;身份验证、授权和会话。</p> <h3 id="htag">Htag<a class="headerlink" href="#htag" title="Permanent link">&para;</a></h3> <p><a href="https://github.com/manatlan/htag">Htag</a>是一个非常强大且实现优雅的纯 python-web-dev 解决方案。这是一位多产、才华横溢、积极进取的作者提出的最新解决方案。<a href="https://github.com/manatlan/gtag">他从之前的产品G​​tag</a>和<a href="https://github.com/manatlan/wyc">Wyc</a>中获得了很多经验。</p> <p>之所以是B级,是因为它是建筑商。一个非常灵活和强大的构建器,能够在以下所有部署场景中运行:</p> <ul> <li>对于 <strong>桌面应用程序</strong> :您可以使用 <a href="https://manatlan.github.io/htag/runners/#pywebwiew">PyWebView 运行程序</a>,它将在 pywebview 容器中运行 <span class="caps">UI</span>(或&rdquo;ChromeApp 运行程序&rdquo;,在本地 Chrome&nbsp;应用程序模式下)。 </li> <li>对于 <strong>Web 应用程序</strong> :您可以使用 <a href="https://manatlan.github.io/htag/runners/#webhttp">WebHTTP 运行程序</a>,它将在 Web 服务器中运行 <span class="caps">UI</span>,并在客户端的浏览器中提供 <span class="caps">UI</span>。 </li> <li>对于 <strong>Android 应用程序</strong> :您可以使用 <a href="https://manatlan.github.io/htag/runners/#androidapp">AndroidApp 运行程序</a>,它将通过龙卷风网络服务器在 kiwi webview 中运行 <span class="caps">UI</span>,并且可以嵌入到 apk 中(<a href="https://github.com/manatlan/htagapk">菜谱</a>)</li> <li>对于 <strong>pyscript 应用程序</strong> :您可以使用 <a href="https://manatlan.github.io/htag/runners/#pyscript">PyScript 运行程序</a>,它将在客户端完全运行</li> </ul> <p>事实上,任何可以渲染 <strong>html/js/css</strong>的显示门户,无论是浏览器、pywebview、android/apk 还是任何基于 cef 的东西,都只需要一个 <a href="https://manatlan.github.io/htag/runners/">htag 运行器</a>, 以便 htag&nbsp;能够渲染到它。</p> <p>正如作者所说:</p> <blockquote> <p>是的&#8230;&#8230;承诺就在这里: <strong>它是一个 <span class="caps">GUI</span> 工具包,用于从单个代码库构建&rdquo;漂亮&rdquo;的移动、Web 和桌面应用程序</strong>。</p> <p><a href="https://github.com/manatlan/htag#readme">https://github.com/manatlan/htag#readme</a></p> </blockquote> <h4 id="demo">Demo演示<a class="headerlink" href="#demo" title="Permanent link">&para;</a></h4> <p>加载后,这是一个非常<a href="https://htag.glitch.me/">令人印象深刻且富有表现力的演示。</a></p> <h4 id="_20">讨论<a class="headerlink" href="#_20" title="Permanent link">&para;</a></h4> <ul> <li><span class="dquo">&ldquo;</span>使用 htag<a href="https://www.reddit.com/r/Python/comments/wrmmwf/htagmatplotlib_using_htag_to_create_a_matplotlib/">为桌面、网络或移动设备创建 **matplotlib** 应用程序</a>&ldquo;</li> <li><span class="dquo">&ldquo;</span>HTag:<a href="https://www.reddit.com/r/Python/comments/wp0koc/htag_an_irl_mobile_app_for_android_a_tricount/?utm_source=share&amp;utm_medium=web2x&amp;context=3" rel="noreferrer noopener" target="_blank">一款适用于 Android 的 <span class="caps">IRL</span> 移动应用程序:使用 py3 的 tricount 克隆&#8230;&#8230;</a>&nbsp;&ldquo;</li> <li>HTag:<a href="https://www.reddit.com/r/Python/comments/vysnci/">一个新的 <span class="caps">GUI</span> 从单个代码库中获取了适用于 Web/桌面/Android 的</a><a href="https://www.reddit.com/r/PyScript/comments/ukgjy3/first_frontend_lib_for_pyscript/">pyscript 的</a>第一个前端库;-)&rdquo;</li> <li><span class="dquo">&ldquo;</span>htag 0.4.7(一个 gui/前端库,<a href="https://www.reddit.com/r/PyScript/comments/ummdia/htag_047_a_guifrontend_lib_which_works_very_well/">在 pyscript 中运行良好</a>)&rdquo;</li> </ul> <h3 id="neutron">Neutron [中子]<a class="headerlink" href="#neutron" title="Permanent link">&para;</a></h3> <p><a href="https://github.com/IanTerzo/Neutron">Neutron</a>允许开发人员构建原生 Python 应用程序以及用于前端设计的 <span class="caps">CSS</span> 和 <span class="caps">HTML</span>。基于 <a href="https://github.com/r0x0r/pywebview">pywebview</a> 的本机 <span class="caps">GUI</span> 窗口和 JavaScript-Python&nbsp;通信。</p> <h3 id="vuepy"><strong>Vue.Py</strong><a class="headerlink" href="#vuepy" title="Permanent link">&para;</a></h3> <p><a href="https://github.com/stefanhoelzl/vue.py">Vue.py</a>包装了 Vue.js。Vue.py 基于 Brython,作者很清楚目前存在哪些限制。缺乏应用程序库和较小的用户群导致这是 B&nbsp;类解决方案。</p> <h3 id="justpy-vuejs"><strong>JustPy &ndash; 另一个 Vue.js 包装器</strong><a class="headerlink" href="#justpy-vuejs" title="Permanent link">&para;</a></h3> <p><a href="https://justpy.io/">https://justpy.io/</a></p> <p>Justpy让开发者不再关心前端和后端开发的区别。来自[自述文件](<a href="https://github.com/elimintz/justpy">https://github.com/elimintz/justpy</a>):</p> <p>JustPy&nbsp;的后端是使用以下内容构建的:</p> <ul> <li><a href="https://www.starlette.io/">starlette</a> &ndash; &ldquo;一个轻量级的<a href="https://asgi.readthedocs.io/en/latest/"><span class="caps">ASGI</span></a>框架/工具包,非常适合构建高性能异步服务&rdquo;。</li> <li><a href="https://www.uvicorn.org/">uvicorn</a> &ndash; &ldquo;一个快如闪电的<a href="https://asgi.readthedocs.io/en/latest/"><span class="caps">ASGI</span></a>服务器,基于<a href="https://github.com/MagicStack/uvloop">uvloop</a>和<a href="https://github.com/MagicStack/httptools">httptools</a>构建&rdquo;。</li> </ul> <p>JustPy 的前端(对 JustPy&nbsp;开发人员来说是透明的)是使用以下方式构建的:</p> <ul> <li><a href="https://vuejs.org/">Vue.js</a> &ndash; &ldquo;渐进式 JavaScript&nbsp;框架&rdquo;</li> </ul> <p>JustPy消除前后端区别的方式是拦截前端的相关事件并将其发送到后端进行处理。</p> <p>对于基于明显成熟度的 Vue 解决方案,我认为 JustPy 优于 Vue.py。但两者都没有为完全成熟的 Web&nbsp;应用程序框架的常见问题提供解决方案。</p> <p>最近<a href="https://www.reddit.com/r/Python/comments/ybe1z4/justpy_open_source_community_is_growing/">的 Reddit 帖子</a>显示了原作者对该项目的长期支持的承诺。话虽如此,作者缺乏回应确实导致了<a href="https://github.com/justpy-org/justpy/issues/404#issuecomment-1207331029">基于 Svelte</a>而不是 Vue.js 的JustPy&nbsp;的重大分叉。</p> <h4 id="nicegui_1">构建 NiceGUI<a class="headerlink" href="#nicegui_1" title="Permanent link">&para;</a></h4> <p>JustPy 是 NiceGUI&nbsp;的底层库。</p> <h4 id="_21">出版物:<a class="headerlink" href="#_21" title="Permanent link">&para;</a></h4> <ul> <li>&rdquo; <a href="https://www.reddit.com/r/Python/comments/ybe1z4/justpy_open_source_community_is_growing/">justpy 开源社区正在成长</a>&ldquo;</li> </ul> <h3 id="pyfyre">pyfyre<a class="headerlink" href="#pyfyre" title="Permanent link">&para;</a></h3> <p>我<a href="https://github.com/pyfyre/pyfyre/blob/main/README.md#features">抄录</a>了<a href="https://github.com/pyfyre/pyfyre">官方Github</a>:</p> <ol> <li><strong>基于组件的框架</strong>。有使用其他前端框架经验的开发人员在使用 PyFyre&nbsp;时应该会感到很自在。</li> <li><strong>真正的反应式</strong>。PyFyre 的虚拟 <span class="caps">DOM</span>&nbsp;允许简单高效的状态管理。 </li> <li><strong>快速导航</strong>。PyFyre&nbsp;的单页面应用程序设计使页面之间的导航非常快捷。</li> <li><strong>具有静态类型的 Pythonic 代码</strong>。凭借其类型提示和 Pythonic 编码风格,使用 PyFyre&nbsp;进行开发要容易得多。</li> <li><strong>异步编程</strong>。开箱即用地运行非阻塞函数。</li> <li><strong>CPython 互操作性</strong>。开发人员只能在客户端 Web 上有限地使用 CPython&nbsp;包。</li> <li><strong>JavaScript 互操作性</strong>。允许开发人员利用 <span class="caps">NPM</span> 包并与现有 JavaScript&nbsp;应用程序集成。</li> <li><strong>纯Python</strong>。无需接触 <span class="caps">HTML</span> 和 JavaScript 等其他语言即可构建 Web&nbsp;应用程序。</li> <li><strong>和更多!</strong></li> </ol> <h4 id="_22">讨论<a class="headerlink" href="#_22" title="Permanent link">&para;</a></h4> <ul> <li><a href="https://www.reddit.com/r/Python/comments/z3852d/python_frontend_framework_for_building_websites/"></a>用于构建网站的<a href="https://www.reddit.com/r/Python/comments/z3852d/python_frontend_framework_for_building_websites/">Python&nbsp;前端框架</a></li> </ul> <h4 id="brython">基于 Brython 构建<a class="headerlink" href="#brython" title="Permanent link">&para;</a></h4> <h3 id="transcrypt"><strong>Transcrypt</strong><a class="headerlink" href="#transcrypt" title="Permanent link">&para;</a></h3> <p><a href="http://transcrypt.org/">http://transcrypt.org/</a>是一个 Javascript 生成器,它选择与 Javascript 库而不是 Python 库集成。<a href="https://pyreact.com/">React to Python</a>一书演示了如何使用 Transcrypt 作为成熟应用程序的基础。应用程序示例库令人印象深刻。我个人的挑剔是,他们试图在 Transcrypt 中提供一些 numpy,这违背了他们利用 Javascript 生态系统而不是 Python 的理念。Web 应用程序中明确的职责分离要求他们将 numpy 和相关库留给后端 <span class="caps">API</span>。</p> <p>尽管如此,Transcrypt 是一个经过精心打磨的成熟产品,鼓励任何希望利用 Python 相对于 Javascript 的优势的人将其用作 Js/Css/<span class="caps">HTML</span> 的 <span class="caps">DSL</span>。</p> <p>您绝不应该认为 CPython 的每个方面都可以在 Transcrypt 中使用:<a href="http://www.transcrypt.org/docs/html/philosophy_directions.html#why-are-certain-python-constructions-supported-as-a-local-or-global-option-rather-than-by-default">他们的文档</a>告诉您不然:</p> <blockquote> <p>请注意,Transcrypt 避免了无法在浏览器中执行的构造。这意味着 Transcrypt 和 CPython 处于不同的联盟。Transcrypt 使 Python 程序员能够将大量技能运用到浏览器中,但它绝不是 CPython&nbsp;的替代品。两者应该被视为是互补的。</p> <p>转transcrypt文档。</p> </blockquote> <h3 id="zython">Zython<a class="headerlink" href="#zython" title="Permanent link">&para;</a></h3> <p><a href="https://github.com/sagemathinc/zython">Zython</a>是一个 WebAssembly 项目,其实现与 python-wasm 和 pyodide 完全不同,它们都基于 emscripten,因此存在<a href="https://github.com/sagemathinc/zython/blob/main/docs/differences-from-pyodide.md">zython 不受</a>.</p> <p>该项目的既定目标是&rdquo;&#8230;&#8230;<a href="https://github.com/sagemathinc/zython">创建核心 Python 和依赖包的 WebAssembly 构建,它既可以在 Node.js 命令行上运行,也可以在主要 Web 浏览器中运行(通过 npm 模块,您可以通过 webpack 包含这些模块) 。</a> &rdquo;</p> <p>我发现不幸的是,<code>python-wasm</code>这个项目中使用了包名称 `:看起来<a href="https://github.com/sagemathinc/zython/discussions/32">它会造成不必要的混乱</a>。</p> <h4 id="_23">讨论和文章<a class="headerlink" href="#_23" title="Permanent link">&para;</a></h4> <ul> <li><a href="https://github.com/sagemathinc/zython/discussions">官方论坛</a></li> <li><a href="https://www.reddit.com/r/Python/comments/xy4ah5/github_sagemathinczython_webassembly_python_for/">https://www.reddit.com/r/Python/comments/xy4ah5/github_sagemathinczython_webassemble_python_for/</a></li> <li></li> </ul> <h3 id="bokeh_1"><strong>Bokeh</strong><a class="headerlink" href="#bokeh_1" title="Permanent link">&para;</a></h3> <p>借助<a href="https://bokeh.org/">Bokeh</a>,您可以创建由 JavaScript 驱动的可视化效果,而无需自己编写任何 JavaScript。还可以在 Django 或 Flask 等传统框架中使用 Bokeh&nbsp;输出。</p> <p>对我来说,最大的问题是:仅专注于抽象 javascript 可视化的解决方案有什么好处?Javascript 还可以用于其他用途吗?当我需要另一个解决方案来解决其他 Javascript&nbsp;问题时,为什么我要选择这个?</p> <p>答案在于<a href="https://holoviz.org/">holoviz 框架</a>,它提供了对 Bokeh&nbsp;等的编程访问。</p> <h3 id="pyodide"><strong>pyodide (碘化物)</strong><a class="headerlink" href="#pyodide" title="Permanent link">&para;</a></h3> <p><a href="https://pyodide.org/en/stable/">https://pyodide.org/en/stable/</a></p> <p>Python 与科学堆栈,编译为&nbsp;WebAssembly。</p> <p>Pyodide 可用于您想要在 Web 浏览器中运行 Python&nbsp;的任何环境。</p> <p>Pyodide 通过 WebAssembly 将 Python 3.9 运行时以及 Python 科学堆栈(包括 NumPy、Pandas、Matplotlib、SciPy 和 scikit-learn)引入浏览器。目前有超过 75 个软件包可供选择。此外,还可以从 PyPi 安装纯 Python&nbsp;轮子。</p> <p>Pyodide 提供 Javascript 和 Python 之间对象的透明转换。在浏览器中使用时,Python 可以完全访问 Web <span class="caps">API</span>。</p> <h4 id="_24">构建块<a class="headerlink" href="#_24" title="Permanent link">&para;</a></h4> <p>这是 PyScript&nbsp;的构建基础。</p> <h4 id="_25">文章<a class="headerlink" href="#_25" title="Permanent link">&para;</a></h4> <p><a href="https://testdriven.io/blog/python-webassembly/">https://testdriven.io/blog/python-web&nbsp;assembly/</a></p> <h4 id="_26">接触<a class="headerlink" href="#_26" title="Permanent link">&para;</a></h4> <p><a href="https://pyodide.org/en/stable/project/about.html#communication">https://pyodide.org/en/stable/project/about.html#communication</a></p> <h3 id="pywebio"><strong>PyWebIO</strong><a class="headerlink" href="#pywebio" title="Permanent link">&para;</a></h3> <p><a href="https://pywebio.readthedocs.io/en/latest/">https://pywebio.readthedocs.io/en/latest/</a>是一个构建器,具有 Tornado、Flask、Django 和 aiohttp&nbsp;集成记录。它也可以独立执行。它是令人惊讶的程序化,但为使用函数而不是对象和方法的嵌套渲染提供了良好的支持。</p> <h4 id="_27">示例代码<a class="headerlink" href="#_27" title="Permanent link">&para;</a></h4> <p><a href="https://demo.pyweb.io/olympics/">东京奥运会国家成绩排名</a></p> <h4 id="skulpt-and-brython">Skulpt and Brython<a class="headerlink" href="#skulpt-and-brython" title="Permanent link">&para;</a></h4> <p>都是浏览器内的 Python 实现。但他们有不同的目标以及优势和劣势。<a href="https://groups.google.com/g/brython/c/Oyb9ktV6TU8">布莱森速度更快</a>。然而 Skulpt 需要较慢的执行和加载时间,因为它的<a href="https://github.com/skulpt/skulpt/issues/246">目标是完全符合 Python 标准</a>。产品的目标不同:Brython 的目标是成为 Javascript 的替代品,而 Skulpt 的目标是成为具有 Web 浏览器执行目标的 Python&nbsp;发行版。</p> <p><a href="https://discuss.dizzycoding.com/python-in-browser-how-to-choose-between-brython-pypy-js-skulpt-and-transcrypt/">我在这个网站</a>以及<a href="https://newbedev.com/python-in-browser-how-to-choose-between-brython-pypy-js-skulpt-and-transcrypt">这个网站</a>上找到了一个很好的图表。我不知道谁抄袭了谁,但该表确实很好地概述了各种低级解决方案;</p> <p><img alt="" src="https://www.may69.com/wp-content/uploads/2022/07/image-20-1024x586.png">{.wp-image-105 decoding=&rdquo;async&rdquo; width=&rdquo;590&rdquo; height=&rdquo;337&rdquo; srcset=&rdquo;https://www.may69.com/wp-content/uploads/2022/07/image-20-1024x586.png 1024w, https://www.may69.com/wp-content/uploads/2022/07/image-20-300x172.png 300w, https://www.may69.com/wp-content/uploads/2022/07/image-20-768x440.png 768w, https://www.may69.com/wp-content/uploads/2022/07/image-20.png 1506w&rdquo; sizes=&rdquo;(max-width: 590px) 100vw,&nbsp;590px&rdquo;}</p> <h4 id="_28">相关阅读<a class="headerlink" href="#_28" title="Permanent link">&para;</a></h4> <h2 id="-httpswwwredditcomrpythoncomments2yli88whats_the_best_implementation_of_a95python">- https://www.reddit.com/r/Python/comments/2yli88/whats_the_best_implementation_of_a_python/<a class="headerlink" href="#-httpswwwredditcomrpythoncomments2yli88whats_the_best_implementation_of_a95python" title="Permanent link">&para;</a></h2> <h3 id="skulpt_1"><strong>skulpt (雕塑)</strong><a class="headerlink" href="#skulpt_1" title="Permanent link">&para;</a></h3> <p><a href="https://skulpt.org/">https://skulpt.org/</a></p> <h4 id="4646">构建模块&#8230;&#8230;<a class="headerlink" href="#4646" title="Permanent link">&para;</a></h4> <p>Skulpt 是<a href="https://anvil.works/">Anvil 的</a>基础,它是 A 类纯 python-web-dev&nbsp;解决方案的基础。</p> <h3 id="pyweb3d">PyWeb3D<a class="headerlink" href="#pyweb3d" title="Permanent link">&para;</a></h3> <p><a href="https://www.pyweb3d.org/">PyWeb3D</a>允许您使用 Three.js 库而无需编写 JavaScript。正如我在 Bokeh 评论中所说,人们想知道当需要抽象 Javascript/<span class="caps">HTML</span>/<span class="caps">CSS</span>&nbsp;的其他方面时该怎么做。</p> <h4 id="brypthon">建立在:brypthon<a class="headerlink" href="#brypthon" title="Permanent link">&para;</a></h4> <h4 id="_29">文章和应用<a class="headerlink" href="#_29" title="Permanent link">&para;</a></h4> <p><span class="dquo">&ldquo;</span><a href="https://betterprogramming.pub/three-js-with-python-syntax-pyweb3d-2152bed1a43d">认识 PyWeb3D &mdash; Three.js 与 Python 语法</a>&ldquo;</p> <h3 id="brypthon_1"><strong>brypthon</strong><a class="headerlink" href="#brypthon_1" title="Permanent link">&para;</a></h3> <p><a href="https://brython.info/">https://brython.info/</a></p> <h3 id="reacton-ipywidgets-react-python"><strong>Reacton &ndash; 用于 ipywidgets 的 React 纯 Python 端口</strong><a class="headerlink" href="#reacton-ipywidgets-react-python" title="Permanent link">&para;</a></h3> <p>ipywidgets 是一个用于在 Jupyter Notebook&nbsp;中编写交互式小部件的库。</p> <p><a href="https://github.com/widgetti/reacton">Reacton</a>是一个纯 Python 库,它实现了与 ReactJS 类似的 <span class="caps">API</span>。它不是渲染到 <span class="caps">DOM</span>,而是渲染到 ipywidgets。然后 ipywidget 库负责前端渲染(可以使用 ReactJS、Vue 甚至&nbsp;jQuery)。</p> <h4 id="_30">讨论<a class="headerlink" href="#_30" title="Permanent link">&para;</a></h4> <ul> <li><a href="https://www.reddit.com/r/Python/comments/zkxq1j/reacton_a_pure_python_port_of_react_for_ipywidgets/">最初的 reddit&nbsp;线程。</a></li> <li><span class="dquo">&ldquo;</span><a href="https://maartenbreddels.medium.com/advance-your-ipywidget-app-development-with-reacton-6734a5607d69">使用 Reacton 推进您的 ipywidget 应用程序开发</a>&mdash; React 的纯 Python&nbsp;端口,可加快开发速度&rdquo;</li> </ul> <h3 id="streamlit_1"><strong>streamlit (流线型)</strong><a class="headerlink" href="#streamlit_1" title="Permanent link">&para;</a></h3> <p><a href="https://streamlit.io/">https://streamlit.io/</a>非常强大且非常受欢迎,但是在成熟的 Web 应用程序中添加您期望的功能是<a href="https://discuss.streamlit.io/t/user-authentication/612/18">困难的、黑客的</a>或<a href="https://www.reddit.com/r/Python/comments/ynzbre/comment/ivbo9h4/?utm_source=share&amp;utm_medium=web2x&amp;context=3">混乱的</a>,具体取决于您与谁交谈。然而,显然他们已经被 Snowlake&nbsp;收购,因此他们的前进有强大的后盾。</p> <h4 id="demo-gallery_4">实例走廊(Demo Gallery)<a class="headerlink" href="#demo-gallery_4" title="Permanent link">&para;</a></h4> <p><span class="dquo">&ldquo;</span><a href="https://www.reddit.com/r/Python/comments/y4jdh7/made_a_streamlit_app_to_show_demographic/">制作了一款 Streamlit 应用程序,以显示美国 100 个最大都市区按年龄、种族、性别和教育程度划分的人口统计数据</a>。&rdquo;</p> <p>&rdquo; <a href="https://www.kdnuggets.com/2023/01/streamlit-machine-learning-cheat-sheet.html">Streamlit 机器学习备忘单</a>&ldquo;</p> <p><span class="dquo">&ldquo;</span><a href="https://levelup.gitconnected.com/how-to-build-a-dividend-investing-dashboard-in-python-and-streamlit-a9ad2714c76b">如何使用 Python 和 Streamlit 构建股息投资仪表板</a>&ldquo;</p> <p>&rdquo; <a href="https://www.reddit.com/r/Python/comments/102vasd/nft_and_metadata_generator_python_streamlit/"><span class="caps">NFT</span> 和元数据生成器 &ndash; Python 和 Streamlit</a>&nbsp;&ldquo;</p> <p><span class="dquo">&ldquo;</span><a href="https://www.reddit.com/r/Python/comments/y6c8vn/i_created_a_streamlit_ui_for_openais_whisper_and/">我为 OpenAI 的 Whisper 创建了 Streamlit <span class="caps">UI</span>,并添加了一些用于转录摘要的基本脚手架</a>&ldquo;</p> <p><a href="https://streamlit.io/gallery">gallery</a></p> <p><a href="https://blog.streamlit.io/dbt-cloud-jobs-with-streamlit"><span class="dquo">&ldquo;</span>使用 Streamlit 轻松监控 dbt Cloud&nbsp;作业&rdquo;</a></p> <p><span class="dquo">&ldquo;</span><a href="https://www.reddit.com/r/Python/comments/ynxvpm/plotting_all_public_transport_in_nl_livestream/">使用 Streamlit 绘制 <span class="caps">NL</span> 直播中的所有公共交通图</a>&ldquo;</p> <p><span class="dquo">&ldquo;</span><a href="https://www.reddit.com/r/Python/comments/ww84sv/i_was_unhappy_with_spotify_recommendations_so_i/">我对 Spotify 的推荐不满意,所以我用 Python+Spotify 的 <span class="caps">API</span> 做了 1000 多个。请从 Streamlit 应用程序底部查看您的播放列表</a>。&rdquo; <a href="https://www.reddit.com/r/Python/comments/yyj7zz/first_webapp_project/"><span class="caps">SQL</span>格式化程序</a></p> <h4 id="_31">讨论<a class="headerlink" href="#_31" title="Permanent link">&para;</a></h4> <p><a href="https://www.reddit.com/r/Python/comments/lnu1r9/i_made_a_covid19_immunityvaccination_tracker_and/">https://www.reddit.com/r/Python/comments/lnu1r9/i_made_a_covid19_immunityvaccination_tracker_and/</a></p> <h4 id="_32">文章<a class="headerlink" href="#_32" title="Permanent link">&para;</a></h4> <p><span class="dquo">&ldquo;</span><a href="https://www.reddit.com/r/Python/comments/ykapvv/new_streamlit_tutorial_68_pages_35_minimal_app/">新的 Streamlit 教程</a>,68 页,35 个最小应用程序示例,专注于 <span class="caps">SQL</span>+Streamlit&rdquo;</p> <p><span class="dquo">&ldquo;</span><a href="https://www.reddit.com/r/Python/comments/yek0zr/build_realtime_data_applications_quickly_using/">使用 Streamlit 和 Prisma 快速构建实时数据应用程序</a>&ldquo;</p> <p><a href="https://analyticsindiamag.com/streamlit-vs-plotlydash-comparison-with-python-examples/">https://analyticsindiamag.com/streamlit-vs-plotlydash-comparison-with-python-examples/</a></p> <p><span class="dquo">&ldquo;</span><a href="https://www.reddit.com/r/Python/comments/x7f0zp/i_was_excited_about_yolov7_so_i_built_a_sharable/?utm_source=share&amp;utm_medium=web2x&amp;context=3">我对 YOLOv7 感到很兴奋,因此我使用 <span class="caps">VDP</span> 和 Streamlit 构建了一个可共享的对象检测应用程序。</a>&ldquo;</p> <p><span class="dquo">&ldquo;</span><a href="https://www.reddit.com/r/Python/comments/wsos1n/streamlit_user_and_api_authentication_with_auth0/">使用 Auth0 Next.js <span class="caps">SDK</span> 简化用户和 <span class="caps">API</span> 身份验证</a>&#8217;</p> <h3 id="_33"><a class="headerlink" href="#_33" title="Permanent link">&para;</a></h3> <h2 id="c">C 类:具有严重限制的解决方案<a class="headerlink" href="#c" title="Permanent link">&para;</a></h2> <p>本节涵盖范围有限的产品</p> <h3 id="enaml-web"><strong>enaml web</strong><a class="headerlink" href="#enaml-web" title="Permanent link">&para;</a></h3> <p><a href="https://github.com/codelv/enaml-web">Enamel Web</a>是一个非常广泛的生态系统的一部分:</p> <ul> <li>有一个简单的旧式<a href="https://github.com/nucleic/enaml">Enaml</a>,它可以使用 python 支持的 <span class="caps">DSL</span>&nbsp;简洁地构建桌面应用程序</li> <li><a href="https://github.com/codelv/enaml-web">Enaml-web</a>是Enaml for the web&nbsp;的变体</li> <li>有<a href="https://github.com/codelv/atom-db">atom-db</a>,这是他们的异步<span class="caps">ORM</span></li> <li>还有 Atom,它是 Python 的一个非常强大的对象系统。他们的对象系统有观察者和数据验证。它几乎与 Traitlets 一样好,Traitlets 稍微强大一些,因为您可以轻松地从 Traitlets&nbsp;类生成命令行界面。</li> </ul> <p>Enamel-web&nbsp;有几个演示项目。为什么是C级?</p> <ul> <li>您可以使用更简单的工具和更少的代码来完成简单的事情</li> <li>没有路线图或设施来构建复杂的世界级网络应用程序</li> <li>用户基数显然很小</li> <li>开发者基数显然很小</li> <li>值得一提的是,代码经常更新</li> <li>现实世界中的例子很少。只是两个示例项目</li> <li></li> </ul> <h3 id="_34"><a class="headerlink" href="#_34" title="Permanent link">&para;</a></h3> <h3 id="pyscript"><strong>PyScript</strong><a class="headerlink" href="#pyscript" title="Permanent link">&para;</a></h3> <p><a href="https://pyscript.net/">PyScript</a>由 Anaconda 开发。从表面上看,也只是从表面上看,PyScript 似乎就像 Brython&#8212;&#8212;&#8212;你将 Python 嵌入到 <span class="caps">HTML</span> 和 walla 的一些标签中,动态网页使用 Python 而不是&nbsp;Javascript。</p> <p>但 PyScript 与 Brython 的区别在于它基于 Pyodide。用<a href="https://www.reddit.com/r/Python/comments/uhm1oe/comment/i7dvi4q/?utm_source=share&amp;utm_medium=web2x&amp;context=3">合著者的话说</a>:</p> <blockquote> <p>Pyodide 与您在笔记本电脑上运行的 *CPython* 解释器相同,但编译为目标 WebAssembly。(就像 CPython 被编译为针对笔记本电脑上的 x86 或 M1&nbsp;程序集一样。)</p> <p>这就是为什么 Python 的各种本机 C/C++ 扩展也可以得到支持:它们也被编译为针对&nbsp;WebAssembly。</p> <p>这与 JavaScript 无关。当然不是&rdquo;Pyodide 是用 <span class="caps">JS</span> 编写的 Python&rdquo;&#8212;&#8212;&#8212;这更像是 Brython。(这种方法永远无法导入 numpy、pandas、scipy 等,而不用 Javascript&nbsp;重写所有这些。)</p> <p>Anaconda 首席执行官 Peter&nbsp;Wang</p> </blockquote> <p>既然Anaconda已经开发了Panel,那么有人会想为什么要使用PyScript。王指出: </p> <p>这是比 Panel 更广泛、更基本的功能。您可以在浏览器中运行几乎<em>任何Python。</em>您还可以包装 Javascript 库。因此,我们有一些示例展示了与 Three.<span class="caps">JS</span>、d3&nbsp;等的交互。</p> <p><a href="https://www.reddit.com/r/Python/comments/uhm1oe/comment/i7aep2l/?utm_source=share&amp;utm_medium=web2x&amp;context=3">根据 Wang 的</a>说法,PyScript&nbsp;的意图是:</p> <blockquote> <p>&#8230;为数百万发现现有内容过于复杂的人提供编程能力。即使学习单一语言也够难的了。这些人将无法学习 <span class="caps">JS</span>、现代 Web 开发和 DevOps&nbsp;等的所有复杂性。</p> <p>使用 PyScript,他们只需使用单一语言编写,并带有一点 <span class="caps">HTML</span>,并且可以与任何朋友和同事共享一些东西,并且部署复杂性为零。他们可以通过电子邮件将文件发送给他们,或将其复制到拇指驱动器上。</p> <p>Anaconda 首席执行官 Peter&nbsp;Wang</p> </blockquote> <p>目前,人们对 PyScript 的兴趣远远超出了它为潜在用户提供高效解决方案的能力。然而,该产品强大的企业支持和庞大的开发团队表明,它很可能在明年左右成为 A&nbsp;级系统。它具有巨大的潜力。正如htag的作者所说:</p> <blockquote> <p>这是我多年来见过的最不可思议的事情&#8230;&#8230;在 JavaScript 和 Python&nbsp;世界中</p> <p>它可以打开/解锁很多东西&#8230;&#8230;</p> <p>来自 brython,它以正确的方式解锁了完整的 python(感谢&nbsp;wasm)</p> <p>当然,在虚拟机浏览器能够原生支持它之前,还有很多改进/差距&#8230;&#8230;但这就是要走的路&#8230;&#8230;</p> <p>但承诺就在这里&#8230;&#8230;您可以编写 python 代码(并 pip 任何您想要的库),只需包含&nbsp;js&#8230;&#8230;现在!无法想象即将发生的所有事情&#8230;&#8230;非常兴奋!</p> <p><a href="https://www.reddit.com/r/PyScript/comments/ug7p28/comment/i7nielb/?utm_source=reddit&amp;utm_medium=web2x&amp;context=3">马纳特兰</a></p> </blockquote> <h4 id="_35">问答<a class="headerlink" href="#_35" title="Permanent link">&para;</a></h4> <h5 id="js-python"><span class="caps">JS</span> 和 Python 之间可以传递对象吗?<a class="headerlink" href="#js-python" title="Permanent link">&para;</a></h5> <p><a href="https://www.reddit.com/r/Python/comments/114431u/comment/j8vqaao/?utm_source=share&amp;utm_medium=web2x&amp;context=3">支持传递对象</a>。在 OpenAI <span class="caps">API</span> 示例中,您将看到 js -> py:</p> <p><code>from js import localStorage, document, console, XMLHttpRequest</code></p> <ul> <li>&rdquo; <strong>from js import&hellip;</strong>&nbsp;&ldquo;将js对象直接导入到PyScript的Python中。</li> </ul> <p>朝另一个方向(py -> js)走,你可以使用 <code>PyScript.runtime.globals.get('my_variable_name')</code></p> <p><code>XMLHttpRequest</code> 这是我用来发出 <span class="caps">HTTP</span> 请求的方法, <code>requests</code> 因为 <strong>不受支持</strong> 。另一种选择是使用 <code>pyodide.http.pyfetch</code></p> <p><strong>参考:</strong></p> <p><a href="https://docs.pyscript.net/latest/guides/passing-objects.html">https://docs.pyscript.net/latest/guides/passing-objects.html</a></p> <p><a href="https://docs.pyscript.net/latest/guides/http-requests.html">https://docs.pyscript.net/latest/guides/http-requests.html</a></p> <h4 id="_36">相关出版物<a class="headerlink" href="#_36" title="Permanent link">&para;</a></h4> <ul> <li><span class="dquo">&ldquo;</span><a href="https://www.reddit.com/r/Python/comments/x00qwr/i_made_an_interactive_pandas_cheat_sheet_using/">我使用 PyScript 制作了交互式 Pandas 备忘单</a>&ldquo;</li> <li><span class="dquo">&ldquo;</span><a href="https://www.reddit.com/r/Python/comments/wmkg3y/comment/ijzli9q/">在 Pyodide 和 PyScript 中使用适用于 Python 的 Azure <span class="caps">SDK</span></a>&nbsp;&ldquo;</li> <li><a href="https://www.reddit.com/r/Python/comments/ug1pf6/python_in_html_new_project_by_anaconda_with_all/">https://www.reddit.com/r/Python/comments/ug1pf6/python_in_html_new_project_by_anaconda_with_all/</a></li> <li><a href="https://www.reddit.com/r/Python/comments/uhbby4/whats_the_difference_between_pyscript_template/">https://www.reddit.com/r/Python/comments/uhbby4/whats_the_difference_&nbsp;Between_pyscript_template/</a></li> <li><a href="https://www.reddit.com/r/Python/comments/ugl19x/anaconda_new_from_anaconda_python_in_the_browser/">https://www.reddit.com/r/Python/comments/ugl19x/anaconda_new_from_anaconda_python_in_the_browser/</a></li> <li><a href="https://www.reddit.com/r/Python/comments/uhm1oe/meet_pyscript_new_framework_from_anaconda_that/">https://www.reddit.com/r/Python/comments/uhm1oe/meet_pyscript_new_framework_from_anaconda_that/</a></li> <li><a href="https://www.reddit.com/r/Python/comments/ujicyq/i_tested_pyscript_and_you_can_literally_write/">https://www.reddit.com/r/Python/comments/ujicyq/i_tested_pyscript_and_you_can_literally_write/</a></li> <li><a href="https://bas.codes/posts/pyscript-todo">https://bas.codes/posts/pyscript-todo</a></li> </ul> <h4 id="pyodide_1">基于 pyodide 构建<a class="headerlink" href="#pyodide_1" title="Permanent link">&para;</a></h4> <h3 id="uidom">UiDOm<a class="headerlink" href="#uidom" title="Permanent link">&para;</a></h3> <p><a href="https://github.com/bitplorer/uidom">UIdom&nbsp;官方仓库</a></p> <h4 id="dominate">建立在dominate(主宰)之上<a class="headerlink" href="#dominate" title="Permanent link">&para;</a></h4> <h3 id="gooey">Gooey<a class="headerlink" href="#gooey" title="Permanent link">&para;</a></h3> <p>我<a href="https://github.com/chriskiehl/Gooey#readme">抄袭</a>:</p> <p>Gooey 将您的控制台应用程序转换为最终用户友好的 <span class="caps">GUI</span>&nbsp;应用程序。它可以让您专注于以熟悉的方式构建健壮、可配置的程序,而无需担心如何将其呈现给普通用户并与之交互。</p> <h4 id="_37"><a href="https://github.com/chriskiehl/Gooey#why"></a>为什么?<a class="headerlink" href="#_37" title="Permanent link">&para;</a></h4> <p>因为尽管我们非常喜欢命令提示符,但世界其他地方却将它视为 80 年代初的丑陋遗物。最重要的是,程序通常需要做的不仅仅是一件事,这意味着提供选项,这以前意味着要么构建 <span class="caps">GUI</span>,要么尝试解释如何向控制台应用程序提供参数。Gooey&nbsp;的诞生就是为了(希望)解决这些问题。它使程序易于使用,而且美观!</p> <h4 id="_38"><a href="https://github.com/chriskiehl/Gooey#who-is-this-for"></a>这是给谁的?<a class="headerlink" href="#_38" title="Permanent link">&para;</a></h4> <p>如果您正在为自己、其他程序员构建实用程序,或者生成您想要捕获的结果并将其传输到另一个控制台应用程序的东西(例如 *nix Philosophy utils),那么 Gooey 可能不适合您。然而,如果您正在构建&rdquo;运行并完成&rdquo;、围绕办公室风格的脚本、将比特从 A 点铲到 B 点的东西,或者只是针对非程序员的东西,Gooey 是完美的工具工作。它可以让您随心所欲地构建复杂的应用程序,同时免费获得 <span class="caps">GUI</span>&nbsp;端。</p> <h3 id="wooey">Wooey<a class="headerlink" href="#wooey" title="Permanent link">&para;</a></h3> <p>根据<a href="https://wooey.readthedocs.io/en/latest/index.html">Wooey 文档</a>:</p> <blockquote> <p>Wooey 是一个简单的 Web 界面,用于运行命令行 Python&nbsp;脚本。将其视为将脚本发布到网络上以进行常规数据分析、文件处理或其他任何操作的简单方法。</p> </blockquote> <h3 id="remi"><strong>remi</strong><a class="headerlink" href="#remi" title="Permanent link">&para;</a></h3> <p><a href="https://github.com/dddomodossola/remi">remi</a>放在 C&nbsp;组让我很伤心。作者在他的产品上非常努力并且非常敏感。</p> <p>它提供了一种基于类的用户界面生成方法。它使用内部网络服务器运行,对传统身份验证和授权的<a href="https://github.com/dddomodossola/remi#authentication">支持有限。</a></p> <p>它主要擅长构建供个人使用的用户界面。它比 Gradio&nbsp;更古老。</p> <h3 id="abstracloud">Abstracloud<a class="headerlink" href="#abstracloud" title="Permanent link">&para;</a></h3> <p><a href="https://www.abstracloud.com/pricing">Abstracloud</a>让我想起了 Gradio,但有商业限制。<a href="https://www.abstracloud.com/pricing">定价模型</a>和非自由和开源软件的分发方法似乎有点限制。例如,将<a href="https://www.abstracloud.com/pricing">他们的定价模型</a>与<a href="https://anvil.works/pricing#compare">Anvil 的</a>定价模型进行比较,我们发现 Anvil 的免费帐户中可以有 50,000&nbsp;个数据表行,而任何存储都需要跳转到付费计划。</p> <h4 id="_39">刊物<a class="headerlink" href="#_39" title="Permanent link">&para;</a></h4> <h2 id="-httpswwwredditcomrpythoncommentswg13qrlib_that_generates_web_uis_for_your_scripts_they">- <a href="https://www.reddit.com/r/Python/comments/wg13qr/lib_that_generates_web_uis_for_your_scripts_they/">https://www.reddit.com/r/Python/comments/wg13qr/lib_that_generates_web_uis_for_your_scripts_they/</a><a class="headerlink" href="#-httpswwwredditcomrpythoncommentswg13qrlib_that_generates_web_uis_for_your_scripts_they" title="Permanent link">&para;</a></h2> <h4 id="_40">可交付成果<a class="headerlink" href="#_40" title="Permanent link">&para;</a></h4> <ul> <li><a href="https://www.reddit.com/r/Python/comments/wg4ml7/i_made_a_simple_weight_tracker_that_displays/">https://www.reddit.com/r/Python/comments/wg4ml7/i_made_a_simple_weight_tracker_that_displays/</a></li> </ul> <h3 id="rapydscript"><strong>RapydScript</strong><a class="headerlink" href="#rapydscript" title="Permanent link">&para;</a></h3> <p><a href="https://github.com/atsepkov/RapydScript">https://github.com/atsepkov/RapydScript</a>是一个 C 类系统,主要是因为它不是 Python,也不是 Javascript。他们确实有一组令人印象深刻的图库示例,但自 2021 年 5 月以来,邮件列表和源代码就没有任何活动。当一个人尝试创建一种新语言时,必须首先拥有用户和库,如果其中任何一个出现任何消​​耗,随着时间的推移,这种语言就会变得不那么受欢迎。<a href="https://www.cappuccino.dev/">我们已经在 Coffeescript 、Cappucino 和 Objective-J</a>中看到过这种情况<a href="https://www.cappuccino.dev/"></a>。诚然,Python 有缺点,Javascript 有更多缺点,但我曾经看到一次 <span class="caps">IRC</span> 聊天,有人在争论用 Common Lisp 重写 Emacs,而另一个人说:&rdquo;你的意见无法替代数百万行工作代码&rdquo;&nbsp;。换句话说,如果没有库和用户群,完美的语言就毫无意义。</p> <h3 id="rapydscript-ng-rapydscript">Rapydscript-ng &ndash; RapydScript 的一个分支<a class="headerlink" href="#rapydscript-ng-rapydscript" title="Permanent link">&para;</a></h3> <p><a href="https://github.com/kovidgoyal/rapydscript-ng">https://github.com/kovidgoyal/rapydscript-ng</a>是 Rapydscript ng 的一个分支。自 2021 年 12 月以来,一直没有对该回购协议进行任何承诺。分叉一种语言来创建另一种变体意味着 rapydscript-ng 与 Rapydscript itelf&nbsp;具有相同的采用风险</p> <h3 id="ryact-breact">Ryact 和 Breact<a class="headerlink" href="#ryact-breact" title="Permanent link">&para;</a></h3> <p>Ryact 和 Breact 是 React 的模拟。Ryact 基于 rapydscript 构建,比基于 Brython 构建的 Breact 快 10&nbsp;倍。作为一名作者,他无法满足其项目中工业级软件工程的所有需求。</p> <h4 id="rapydscript-brython">基于 rapydscript 和 Brython 构建<a class="headerlink" href="#rapydscript-brython" title="Permanent link">&para;</a></h4> <h3 id="wasmer-for-pythonpyodide"><strong>WASMer for Python</strong>:Pyodide 的弟弟?<a class="headerlink" href="#wasmer-for-pythonpyodide" title="Permanent link">&para;</a></h3> <p><a href="https://github.com/wasmerio/wasmer-python">https://github.com/wasmerio/wasmer-python</a> &ndash; 是 Python 的 WebAssembly 运行时。作为构建者,它似乎不如 Pyodide&nbsp;受欢迎。此外,开发团队和用户群似乎更小。</p> <h3 id="_41"><a class="headerlink" href="#_41" title="Permanent link">&para;</a></h3> <h3 id="domonic"><strong>Domonic</strong><a class="headerlink" href="#domonic" title="Permanent link">&para;</a></h3> <p><a href="https://github.com/byteface/domonic/">Domonic</a>也是一名建筑商。它包含相当多的子包,其中一些在其他地方可能会更好:</p> <ul> <li>html : 用 python 3 生成 html&nbsp;????</li> <li>dom:python 3 中的 <span class="caps">DOM</span> <span class="caps">API</span>&nbsp;????</li> <li>javascript:python 3 中的 js <span class="caps">API</span>&nbsp;????</li> <li>终端|| cmd :使用 python3 调用终端命令???(<em>见最后</em>)</li> <li><span class="caps">JSON</span>:用于加载/装饰/转换的实用程序</li> <li><span class="caps">SVG</span>:使用 python 生成&nbsp;svg</li> <li>框架|| x3d 标签:使用 aframe 自动生成 3d&nbsp;世界。</li> </ul> <p>作者还有一个名为 htmlx 的精简包,将在仅 <span class="caps">HTML</span>&nbsp;部分中讨论。</p> <h4 id="_42">为什么多莫尼克的评价这么低?<a class="headerlink" href="#_42" title="Permanent link">&para;</a></h4> <p>嗯,文档和源代码存储库都是最新的,所以这不可能是原因。基本上,这是一个未完成的项目,可交付成果很少。例如,在<a href="https://domonic.readthedocs.io/packages/d3.html">有关 d3 接口的文档</a>中,他声明&rdquo;<em>警告:此包仍在开发中&rdquo;。期待错误</em> &#8216;。纯 Python Web 开发的方法似乎比其他项目不太优雅。例如,需要手动包装 d3,然后对其进行不完整的工作,这表明该项目比 Transcrypt 限制得多,Transcrypt 可以使用任何 Javascript&nbsp;库而无需任何特定的包装。</p> <p>作者还开发了 htmlx,它是 domonic 的精简版本,主要限于渲染 <span class="caps">HTML</span>。</p> <h3 id="wave"><strong>Wave</strong><a class="headerlink" href="#wave" title="Permanent link">&para;</a></h3> <p><a href="https://h2oai.github.io/wave/">https://h2oai.github.io/wave/</a>擅长构建实时流式仪表板。它<a href="https://wave.h2o.ai/docs/security">支持 OpenID 和 Basic Auth</a>,但没有示例,也没有表达与 Flask 或 Django 集成的担忧,尽管<a href="https://github.com/h2oai/wave/discussions/934">他们认为它可能应该有效</a>。</p> <p>我安装了 Wave 并进行了巡演。我在使某些示例在 Windows 上运行时遇到问题。即便如此,我发现 Wave&nbsp;非常简洁且非常强大。</p> <p>它是模块化和动态的。我所说的模块化,是指构建网站就像用对象填充 Python 数据结构一样简单。我所说的动态是指直接从 Python <span class="caps">REPL</span> 编辑实时网站的能力给我留下了深刻的印象。试想一下:实时站点可以通过 cron&nbsp;作业进行更新。</p> <p>我有点犹豫,因为必须学习两种不同的使用 Wave 的方法:<a href="https://wave.h2o.ai/docs/tutorial-counter">一种用于脚本,一种用于应用程序</a>。为了让事情变得简单,我总是会编写应用程序。此外,本教程最好有 2 个目录&#8212;&#8212;&#8212;一个用于脚本,一个用于应用程序,而不是将所有 Python&nbsp;示例都放在一个应用程序目录中。</p> <p>我也不喜欢在渲染方法中初始化模型的方式。我开始<a href="https://github.com/h2oai/wave/discussions/964">对此进行讨论</a>。</p> <h2 id="d">D 类:停产产品<a class="headerlink" href="#d" title="Permanent link">&para;</a></h2> <p>本节跟踪不再维护的产品,并且可能无法解决现代 Web&nbsp;应用程序开发问题。</p> <h3 id="dashborg"><strong>Dashborg</strong><a class="headerlink" href="#dashborg" title="Permanent link">&para;</a></h3> <p>将 Dashborg 归类为已不复存在可能有点苛刻。但是 slack 邀请链接不起作用,并且存储库没有最近的提交。事实上,主要的 dashborg 产品不是 <span class="caps">FOSS</span>,只有后端 <span class="caps">SDK</span>&nbsp;才是。用户群似乎很小,并且没有记录的实际用例。</p> <p><a href="https://www.dashborg.net/">https://www.dashborg.net/</a>是独一无二的。<a href="https://gist.github.com/tdd/5ba48ba5a2a179f2d0fa">您可以将其称为解决Angular 噩梦的</a>更明智的方法。它允许人们创建完整的应用程序,但使用&rdquo;实时&rdquo;版本的 <span class="caps">HTML</span>,使用 Go 或 Python&nbsp;后端动态自填充。</p> <p>这很有趣,但它的工作方式与我的想法相反:我宁愿让计算机程序生成 <span class="caps">HTML</span>/<span class="caps">JS</span>/<span class="caps">CSS</span>,也不愿让我的图灵完备语言受到我可以粘贴到 <span class="caps">HTML</span>&nbsp;中的内容的限制。</p> <p>所以我想说,它不会像 Angular&nbsp;那样让我感兴趣&#8212;&#8212;&#8212;功能较弱的语言正在协调使用功能更强大的语言。</p> <p>过去类似的其他工具有 OpenLaszlo。目前流行的此类工具是<a href="https://htmx.org/"><span class="caps">HTMX</span></a>。</p> <h3 id="muntjac"><strong>Muntjac (麂)</strong><a class="headerlink" href="#muntjac" title="Permanent link">&para;</a></h3> <p><a href="https://github.com/rwl/muntjac">Muntjac</a><a href="https://vaadin.com/">Vaadin</a> for Python的实现。Vaadin 是一个企业级 Java Web 应用程序框架,具有大量现代干净的 JavaScript&nbsp;小部件。</p> <p>Vaadin 通过 Java 抽象出了 Javascript,而 Muntjac 以令人印象深刻的方式为 Python&nbsp;做了同样的事情。</p> <h3 id="timothy-crosley"><strong>Timothy Crosley (蒂莫西·克罗斯利)产品</strong><a class="headerlink" href="#timothy-crosley" title="Permanent link">&para;</a></h3> <h4 id="webot">WeBot<a class="headerlink" href="#webot" title="Permanent link">&para;</a></h4> <p><a href="https://github.com/timothycrosley/WebBot">https://github.com/timothycrosley/WebBot</a>是 的集合  几个可以构建 Python Web 应用程序的工具 &nbsp;与原生的构建方式相同。 </p> <p>因此,WebBot 框架鼓励重用, &nbsp;简洁的代码,快速的开发,快乐的开发者。</p> <h4 id="jigna">Jigna<a class="headerlink" href="#jigna" title="Permanent link">&para;</a></h4> <p>Jigna 在<a href="https://www.youtube.com/watch?v=KHSXq5jfv_4">EuroPython 2014 演讲</a>中展示了巨大的前景。基于 Enthought Traits 并得到 Enthought 支持也是其优势所在。然而,<a href="https://github.com/enthought/jigna">源代码存储库</a>已经三年没有任何行动,将其归入已失效类别。</p> <h4 id="jiphy">jiphy<a class="headerlink" href="#jiphy" title="Permanent link">&para;</a></h4> <p><a href="https://github.com/timothycrosley/jiphy">https://github.com/timothycrosley/jiphy</a>是一个几乎已经失效的转译器。</p> <h4 id="dom"><span class="caps">DOM</span><a class="headerlink" href="#dom" title="Permanent link">&para;</a></h4> <p><a href="https://github.com/timothycrosley/thedom">https://github.com/timothycrosley/thedom</a>用于生成 <span class="caps">HTML</span> 和 <span class="caps">JS</span></p> <h3 id="anpylar"><strong>anpylar</strong><a class="headerlink" href="#anpylar" title="Permanent link">&para;</a></h3> <p><a href="https://www.anpylar.com/">https://www.anpylar.com/</a>自 2018&nbsp;年以来一直没有更新。</p> <h3 id="pyjs-pyjamas"><strong>PyJS(以前称为 PyJamas)</strong><a class="headerlink" href="#pyjs-pyjamas" title="Permanent link">&para;</a></h3> <p><a href="http://pyjs.org/">http://pyjs.org/</a>曾经被称为睡衣,但现在这个名字已被保留用于完全不同的东西。</p> <h2 id="htmlcss">仅 <span class="caps">HTML</span>/<span class="caps">CSS</span><a class="headerlink" href="#htmlcss" title="Permanent link">&para;</a></h2> <ol> <li><a href="https://www.reddit.com/r/Python/comments/xsqnn5/fast_html_a_fast_minimalist_html_generator/">快速 <span class="caps">HTML</span></a></li> <li><a href="https://pypi.org/project/htmlwrite/">html&nbsp;写</a></li> <li><a href="https://github.com/messysoup/messysoup">凌乱的汤</a></li> <li><a href="https://github.com/byteface/htmlx/">Htmlx</a>是同一个人编写的名为<a href="https://github.com/byteface/domonic/">domonic</a>的较大软件包的精简版本。<a href="https://www.reddit.com/r/Python/comments/sp1o4e/htmlx_a_pure_python_dom/">讨论</a>。</li> <li><a href="https://github.com/BrainStormYourWayIn/sierra">https://github.com/BrainStormYourWayIn/sierra</a></li> <li>佩里<a href="https://www.reddit.com/r/Python/comments/roaz0i/fancy_way_of_writing_websites_perry_library/">https://www.reddit.com/r/Python/comments/roaz0i/fancy_way_of_writing_websites_perry_library/</a></li> <li><a href="https://github.com/Knio/dominate">https://github.com/Knio/dominate</a></li> <li><a href="https://pypi.org/project/simple-html/">https://pypi.org/project/simple-html/</a></li> </ol> <h2 id="_43"><a class="headerlink" href="#_43" title="Permanent link">&para;</a></h2> <h1 id="_44">笔记<a class="headerlink" href="#_44" title="Permanent link">&para;</a></h1> <h2 id="react-in-python-idom-transcrypt-ryact-breact"><strong> React in Python - <span class="caps">IDOM</span> 与 Transcrypt</strong>(省略 Ryact 和 Breact)<a class="headerlink" href="#react-in-python-idom-transcrypt-ryact-breact" title="Permanent link">&para;</a></h2> <p><span class="caps">IDOM</span> 和 Transcrypt 都有纯粹在 Python 中使用 React 的解决方案。然而,由于 <span class="caps">IDOM</span><a href="https://idom-docs.herokuapp.com/docs/reference-material/faq.html#does-idom-transpile-python-to-javascript">不会转换为 JavaScript</a>,纯组件函数<a href="https://www.reddit.com/r/Python/comments/smdgxl/comment/hvx9pny/?utm_source=share&amp;utm_medium=web2x&amp;context=3">完全兼容并可移植</a>到任何支持 websockets 的 Python Web&nbsp;框架。</p> <h3 id="pynecone"><strong>Pynecone</strong><a class="headerlink" href="#pynecone" title="Permanent link">&para;</a></h3> <p>Pynecone 是一个新项目,它编译为 React 的 NextJS&nbsp;风格,它有一个令人印象深刻的画廊。</p> <h3 id="tangential"><strong>Tangential产品</strong><a class="headerlink" href="#tangential" title="Permanent link">&para;</a></h3> <h4 id="reaction">Reaction<a class="headerlink" href="#reaction" title="Permanent link">&para;</a></h4> <p>感谢 Reacton,React 现在可以在 ipywidgets&nbsp;中使用</p> <h3 id="py-react">py-react<a class="headerlink" href="#py-react" title="Permanent link">&para;</a></h3> <p><a href="https://github.com/elilambnz/react-py">py-react支持通过</a><a href="https://www.may69.com/purepython/#pyodide">Pyodide</a>在浏览器中运行 Python 。<a href="https://www.may69.com/purepython/#Skulpt">话虽这么说,它似乎并不像其他浏览器中的 python 产品( skulpt</a>、<a href="#Brython">brython</a>、<a href="#PyScript">pyscript</a> )那样渴望成为一个 Web 应用程序工具包。因此 py-react 列在切线部分。<a href="https://elilambnz.github.io/react-py">你可以在这里</a>尝试一下。</p> <p>该产品的讨论主题:</p> <ul> <li><span class="dquo">&ldquo;</span><a href="https://www.reddit.com/r/Python/comments/wjz4vp/python_code_running_in_the_browser_using_reactpy/">使用react-py在浏览器中运行Python代码</a>&ldquo;</li> </ul> <h2 id="python"><strong>非Python的同类产品</strong><a class="headerlink" href="#python" title="Permanent link">&para;</a></h2> <h3 id="urweb">UrWeb<a class="headerlink" href="#urweb" title="Permanent link">&para;</a></h3> <p><a href="https://github.com/urweb/urweb">UrWeb</a>是一种单一的强类型语言,可以编译成可以发出 <span class="caps">SQL</span> 和 Javascript&nbsp;的单一二进制文件。</p> <h3 id="vaadin">Vaadin<a class="headerlink" href="#vaadin" title="Permanent link">&para;</a></h3> <p><a href="https://vaadin.com/">Vaadin</a>是一款基于 Java 的产品,具有大量小部件,它允许 Java 开发人员拥有所有交互性,而无需处理 Javascript&nbsp;的麻烦。</p> <h3 id="htmx"><span class="caps">HTMX</span><a class="headerlink" href="#htmx" title="Permanent link">&para;</a></h3> <p>许多希望留在 Django/Flask 领域的人<a href="https://news.ycombinator.com/item?id=33926029">选择 <span class="caps">HTMX</span></a>来赋予他们 Javascript&nbsp;的力量。</p> <h1 id="faq">常见问题 (<span class="caps">FAQ</span>)<a class="headerlink" href="#faq" title="Permanent link">&para;</a></h1> <h2 id="app"><strong>对哪些技术构建的app有令人深刻的印象?</strong><a class="headerlink" href="#app" title="Permanent link">&para;</a></h2> <h3 id="streamlit_2">Streamlit<a class="headerlink" href="#streamlit_2" title="Permanent link">&para;</a></h3> <p><a href="https://streamlit.io/gallery">gallery</a></p> <p><a href="https://blog.streamlit.io/dbt-cloud-jobs-with-streamlit"><span class="dquo">&ldquo;</span>使用 Streamlit 轻松监控 dbt Cloud 作业&rdquo;</a>&nbsp;:::</p>K8S运维总结之关于Kubernetes项目最佳实践的思考2021-12-14T23:46:00+08:002021-12-14T23:46:00+08:00pythonwoodtag:blog.pythonwood.com,2021-12-14:/2021/12/K8S运维总结之关于Kubernetes项目最佳实践的思考/<p>Kubernetes [kubə&rsquo;netis]简称<span class="caps">K8S</span>或Kube,平时使用<span class="caps">K8S</span>主力是Minikube,在几个项目生产实践中,则使用<span class="caps">GCP</span>/<span class="caps">AWS</span>/阿里云的对应的<span class="caps">K8S</span>实现,<span class="caps">GKE</span>/<span class="caps">EKS</span>/<span class="caps">ACK</span>。以下是作者在项目运维中获得和经反思提炼的知识总结 …</p><p>Kubernetes [kubə&rsquo;netis]简称<span class="caps">K8S</span>或Kube,平时使用<span class="caps">K8S</span>主力是Minikube,在几个项目生产实践中,则使用<span class="caps">GCP</span>/<span class="caps">AWS</span>/阿里云的对应的<span class="caps">K8S</span>实现,<span class="caps">GKE</span>/<span class="caps">EKS</span>/<span class="caps">ACK</span>。以下是作者在项目运维中获得和经反思提炼的知识总结,部分理解带有个人观点。</p> <hr> <h2 id="1kubernetes">1、Kubernetes 基础概念<a class="headerlink" href="#1kubernetes" title="Permanent link">&para;</a></h2> <p><img alt="Kubernetes集群基础概念.jpg" src="https://blog.pythonwood.com/uploads/2021/Kubernetes集群基础概念.jpg" title="Kubernetes集群基础概念.jpg"></p> <h3 id="pods">理解 Pods<a class="headerlink" href="#pods" title="Permanent link">&para;</a></h3> <p>Kubernetes 中最小计算单元,内含pause和一个或一组进程。深入pods技术细节见<a href="https://segmentfault.com/a/1190000021710436" title="pod">Kubernetes Pod 网络精髓:pause 容器详解</a>。</p> <h3 id="_1">理解网络<a class="headerlink" href="#_1" title="Permanent link">&para;</a></h3> <p>Kubernetes有2个网络地址池<span class="caps">CIDR</span>分别供Pod和Service。Service和Pod都是有<span class="caps">IP</span>的网络实体,会消耗ip池地址,且各<span class="caps">IP</span>互通(由<span class="caps">CNI</span>实现)。Pod还是个计算实体承载服务,Service则按一定规则转发流量到0个或多个pod。实现模型理解见<a href="https://morven.life/posts/networking-6-k8s-summary/" title="net">浅聊 Kubernetes&nbsp;网络模型</a></p> <h3 id="service">理解Service<a class="headerlink" href="#service" title="Permanent link">&para;</a></h3> <p>Service本质就是dns解析+proxy转发,通过Service名:port方式就能访问真正的实体pod,类似非<span class="caps">K8S</span>生态的consul,但<span class="caps">K8S</span>内部服务名字的dns解析都是高度自动化的,无感知的。</p> <h3 id="podvm">有状态下pod漂移与vm漂移<a class="headerlink" href="#podvm" title="Permanent link">&para;</a></h3> <p>ip在pod生命周期内不变,但pod会因销毁重建导致ip漂移。内存与未绑定文件在pod销毁期间就清空了。相比而言,vm漂移技术成熟,ip内存文件都是一起在线飘到新地方,不存在重启销毁问题。</p> <hr> <h2 id="2kubernetes">2、理解Kubernetes技术<a class="headerlink" href="#2kubernetes" title="Permanent link">&para;</a></h2> <h3 id="1">1. 社区角度:<a class="headerlink" href="#1" title="Permanent link">&para;</a></h3> <p>从2015年7月Kubernetes v1.0正式发布至今v1.22版本,基于Kubernetes的生态已经非常庞大,直接导致go的流行,运维云原生化趋势。 <img alt="kubernetes结合devops概念图.png" src="https://blog.pythonwood.com/uploads/2021/kubernetes结合devops概念图.png" title="kubernetes结合devops概念图.png"></p> <h3 id="2">2. 工程师角度:<a class="headerlink" href="#2" title="Permanent link">&para;</a></h3> <p>绝大部分编排k8s的中间产物都是yaml文件,所以k8s工程师被称为yaml工程师。但其实ansible/salt工程师才是最先全用yaml的。 <img alt="K8S工程师写yaml.png" src="https://blog.pythonwood.com/uploads/2021/K8S工程师写yaml.png" title="K8S工程师写yaml.png"></p> <h3 id="3">3. 技术角度:<a class="headerlink" href="#3" title="Permanent link">&para;</a></h3> <p>内核技术升级是上层技术革新的基础,当年nginx使用epoll网络<span class="caps">IO</span>模型率先实现10K并发,如今docker/Kube实际上是内核cgroup/namespace进程环境限制/隔离加内核netfilter网络模块的上层产物。——技术早已出现,只是换个地方而更被人熟知,这现象可称为【军用科技民用化】。</p> <h3 id="4">4. 运维效用角度:<a class="headerlink" href="#4" title="Permanent link">&para;</a></h3> <p>自动化套件ansible/salt也是非常成熟的,另一方面非容器或非linux机的自动化集群管理并非k8s强项,k8s仅在支持容器化的项目上高效,而大部分项目可以容器化(0.9*0.9依然接近1,但不是全部)。 <img alt="kubernetes对比ansible.png" src="https://blog.pythonwood.com/uploads/2021/kubernetes对比ansible.png" title="kubernetes对比ansible.png"></p> <h3 id="5">5. 基于作者理解:<a class="headerlink" href="#5" title="Permanent link">&para;</a></h3> <ul> <li>k8s是“定义即状态”的运维实现,对应软件代码“定义即实现”具体指发展到<span class="caps">IDL</span>层面(接口描述语言)。</li> <li>k8s内置电池,一个k8s集群相当于实现了一个跑在容器的逻辑机房(计算+网络+存储都是可扩展的),外加一个ansible/salt控制中心。</li> <li>k8s本身学习难度大,非初学者友好,需要较深的linux内核/网络基本做底,但k8s生态的文章,精品率更高,反过来能加速学习容器化与linux相关知识的过程。</li> </ul> <hr> <h2 id="3kube">3、Kube入门学习建议<a class="headerlink" href="#3kube" title="Permanent link">&para;</a></h2> <h3 id="_2">💡 理解上把容器对标物,从虚拟机转变到进程来。<a class="headerlink" href="#_2" title="Permanent link">&para;</a></h3> <ol> <li>容器是一个新概念,从字面上并不好理解其真本质:隔离</li> <li>容器更像一个进程,而不是一个轻量的虚拟机。</li> </ol> <h3 id="k8s">💡 个人学习k8s路径选型<a class="headerlink" href="#k8s" title="Permanent link">&para;</a></h3> <ol> <li>从单机上的容器(docker/containerd)出发,跳一步到单机的<span class="caps">K8S</span>(minikube),再到多节点<span class="caps">K8S</span>(minikube),再适应云商的改版<span class="caps">K8S</span>。</li> <li>Ingress也有很多种,建议如果熟悉nginx,先从ingress-nginx入手。</li> <li>服务治理Istio囊括范围非常大,k8s只是组件之一,容易找不着北。个人觉得不适合用来入门k8s。</li> <li>官方dashboard已经很好,配合<a href="https://github.com/derailed/k9s" title="k9s"><span class="caps">K9S</span></a>工具已经够用了。一个管<span class="caps">UI</span>,一个管console。k9s真是vi党的福音。</li> <li>lens也是好工具,管理国内集群无明显延迟感。国外可能会稍卡顿。</li> </ol> <h3 id="_3">💡 容器 ≈ 进程+网络。<a class="headerlink" href="#_3" title="Permanent link">&para;</a></h3> <ol> <li>除了理解linux内核,也需要iptables/ipvs理解能力。</li> <li>网络理解更难啃些,建议不要跳过docker网络直接理解k8s网络cni。 <img alt="内核netfilter图标.png" src="https://blog.pythonwood.com/uploads/2021/内核netfilter图标.png" title="内核netfilter图标.png"></li> </ol> <h3 id="docker-compose">💡 使用docker-compose作为对照参考<a class="headerlink" href="#docker-compose" title="Permanent link">&para;</a></h3> <ol> <li>对比中理解docker编排/k8s编排各自的长短处。会对k8s理解得更加全面和立体。</li> <li>docker-compose也是一股容器编排方面的重要力量。有余力者学1得2。 </li> </ol> <h3 id="minikube">💡 个人经验最佳学习搭档<a href="https://kubernetes.io/" title="doc">官方文档书籍</a> + <a href="https://minikube.sigs.k8s.io/" title="minikube">minikube</a>实践 。<a class="headerlink" href="#minikube" title="Permanent link">&para;</a></h3> <ol> <li>官方文档要重复看,坚持看,一般看第三遍就懂了。</li> <li>minikube是官方首推的学习和测试k8s环境,只需单机docker环境即可启动一个完备的k8s集群,很轻量,最快支持最新k8s版本。</li> <li>推荐第三方书的话 <a href="https://item.jd.com/12724298.html" title="book">《kubernetes网络权威指南》</a></li> </ol> <hr> <h2 id="4kube">4、Kube最佳实践,经验建议<a class="headerlink" href="#4kube" title="Permanent link">&para;</a></h2> <h3 id="imagesk8sprojzz-projxx">💡 打包images兼容非<span class="caps">K8S</span>容器环境运行,更利运维部署,以及开发调试。【Projzz, Projxx】<a class="headerlink" href="#imagesk8sprojzz-projxx" title="Permanent link">&para;</a></h3> <ul> <li>Projzz的镜像兼容docker,并且cp内部某套集群就是用docker部署的,线上则全用<span class="caps">K8S</span>部署的。</li> <li>Projxx的Pod启动是准备3-4个部分容器,最终合并到最终容器的emptyDir来running,如果选这种模式确实只能k8s了。</li> </ul> <blockquote> <p>做一个通用的镜像,能独立运行。用好动态部分来让同一镜像变成不同的runtime容器,如volume挂载,配置,环境env变量都是动态的。</p> </blockquote> <h3 id="appprojyy">💡 相似微服务可以统一镜像,使用<span class="caps">APP</span>环境变量启动镜像的不同部分【Projyy】<a class="headerlink" href="#appprojyy" title="Permanent link">&para;</a></h3> <blockquote> <p>相对于各微服务独立打包镜像的分包模式,还有一种简单的全包模式。</p> </blockquote> <p>Projyy镜像都是java进程,启动脚本命令基本一样,只是目录和jar包不同,使用了轻量的全包模式。通过指定<span class="caps">APP</span>环境变量,启动对应微服务。兼容docker/k8s。</p> <p>全包镜像模式好处:</p> <ol> <li>统一的Dockerfile,entrypoint.sh不用维护多个文件。</li> <li>减少镜像总占用空间,版本管理起来更轻量简洁。(harbor界面也简洁了)</li> <li>更接近vm时代supervisor的管理整代码包的方式。更好理解。</li> </ol> <h3 id="externalnameendpointskubeprojxx">💡 用ExternalName型和EndPoints型的服务进行Kube内部服务名固定。【Projxx】<a class="headerlink" href="#externalnameendpointskubeprojxx" title="Permanent link">&para;</a></h3> <blockquote> <p>用Service映射内部/外部服务简化架构:</p> <ol> <li> <p>组件依赖以服务<span class="caps">SVC</span>出现供微服务调用。Projxx依赖为zoo-svr, mysql-svr, redis-svr 与 zoo-svr-out,&nbsp;mysql-svr-out。</p> </li> <li> <p><span class="caps">SVC</span>底层的EndPoints/ExternalName映射各集群不同。如正式va集群是中心,微服务调用mysql-svr-out/mysql-svr-out底层相同,sg集群则不同。</p> </li> <li> <p>如下图,屏蔽底层差异后,研发不用关心底层,mysql等服务的映射关系由运维定义和修改,容灾切换。</p> </li> </ol> </blockquote> <p>Projxx图解: <img alt="Kubernetes统一SVC名指向外部依赖.png" src="https://blog.pythonwood.com/uploads/2021/Kubernetes统一SVC名指向外部依赖.png" title="Kubernetes统一SVC名指向外部依赖.png"></p> <h3 id="namespace">💡 在namespace级别隔离业务环境,而非集群级别隔离。<a class="headerlink" href="#namespace" title="Permanent link">&para;</a></h3> <blockquote> <p>减少k8s集群,理想状态是一个测试集群(dev/qa/pre/time/audit服)+一个正式集群。【Projyy】</p> </blockquote> <p>为了让单集群支持多环境,需要以下条件:</p> <ol> <li>yaml/chart中不写死namespace,使用kubectl -n <ns> 和 helm -n <ns> 在运行时指定namespace。</li> <li>节点映射到pod中的目录或文件名,需要保证不同namespace间不不一样。注意hostpaht和local映射。</li> <li>ingress域名不能在多namespace里共用,不同namespace用不同域名。(一般已经天然满足的)</li> <li>daemonset组件处理好不同namespace里不同环境的情况。比如filebeat以daemonset部署时可以收集多namespace的日志。</li> </ol> <h3 id="hostpathpodsshnodeprojzz">💡 善用hostpath在pod层面实现节点的初始化,日志清理等,不建议ssh到node进行初始化。【Projzz】<a class="headerlink" href="#hostpathpodsshnodeprojzz" title="Permanent link">&para;</a></h3> <blockquote> <p>将node的东西暴露给pod,就可以从pod层面处理好node的事项。以下推荐度逐渐递减</p> </blockquote> <ul> <li>以crontab/job加hostpath挂载处理初始化,还能定时清理日志等。</li> <li>以daemonset加hostpath挂载</li> <li>使用initpod模式加hostpath挂载</li> </ul> <h3 id="deploymentstatefulsetro">💡 多用Deployment而不是多用StatefulSet【<span class="caps">RO</span>】<a class="headerlink" href="#deploymentstatefulsetro" title="Permanent link">&para;</a></h3> <blockquote> <p>如无必要,Deployment好于StatefulSet,尤其在大副本数滚动更新时StatefulSet慢</p> </blockquote> <ul> <li>默认情况,Deployments更新2批次完成,而StatefulSet逐个重启,虽然可优化,但不如Deployment快和便捷。</li> <li>需要hostname/dns固定时间,启动顺序(如mysql主从集群)有要求时才特别的需要StatefulSet。</li> <li>Ro的Account登陆校验,Bgame跨服,Global模块,用不到特殊情况,account更新比较慢,理论上改成Deployments会更优。</li> </ul> <h3 id="_4">💡 其他建议:<a class="headerlink" href="#_4" title="Permanent link">&para;</a></h3> <ol> <li>kubectx/kubens实际上在交互shell时才比较好用图省敲键盘。在脚本或自动化流程中,多使用&ndash;kubeconfig和&ndash;context参数指定集群更好。</li> <li>Fairy使用kustomize跑着也很稳,其求同存异的patch思路,也是很好的,免去helm那样写go模版。</li> <li>pod/service/namespace的名字尽量精简,<a href="https://kubernetes.io/zh/docs/concepts/services-networking/dns-pod-service/#pod-sethostnameasfqdn-field" title="FQDN64c">Linux内核的主机名字段限定了<span class="caps">FQDN</span>最多 64 个字符</a>。</li> <li>ingress尽量合并以减少总量,像gcp的gke就存在多于15个ingress是重载非常慢的问题。</li> <li>珍惜两个cidr地址的使用,太大了网络ip使用量,即pods/svc太多,会导致集群内耗过多。&nbsp;这类比开发微服务太小散,会导致cpu内耗在(反)序列化中。某字节内部资料说有10%</li> <li>尽量减少总容器量,比如微服务较多时,daemonset的filebeat部署,比inject/sidecar类型的部署模式省容器。</li> <li>提升副本数不如提升配置,副本数20升级60,&nbsp;在业务代码支持情况下,不如保持20个,配置升3倍。</li> <li>总的来说,本质上就是微服务不是越多越好,目前业界有种不良趋势,服务拆得太小。把服务越拆越细,这事本身也像一个技术界内卷行为。</li> </ol> <hr> <h2 id="5kube">5、Kube带来的问题反思<a class="headerlink" href="#5kube" title="Permanent link">&para;</a></h2> <h3 id="1-kube">1. 云厂商各自实现部分,并不统一,造成割裂,在复杂(云)之上制造复杂(Kube)。<a class="headerlink" href="#1-kube" title="Permanent link">&para;</a></h3> <h4 id="_5">正例:<a class="headerlink" href="#_5" title="Permanent link">&para;</a></h4> <p>基于<span class="caps">LB</span>的证书解密实现,<a href="https://help.aliyun.com/document_detail/86531.html" title="aliyun">阿里云</a>/<a href="https://aws.amazon.com/cn/premiumsupport/knowledge-center/eks-cidr-ip-address-loadbalancer/" title="aws"><span class="caps">AWS</span></a>均是annotation注释指向某个cert证书对象的id。运维开发的效用在于屏蔽这些差异。参考【某_ingress_chart】代码。</p> <h4 id="_6">反例:<a class="headerlink" href="#_6" title="Permanent link">&para;</a></h4> <p>基于<span class="caps">LB</span>的whiteiplist实现,阿里云 / <span class="caps">AWS</span>不同。annotation注释指向一块acl对象id /&nbsp;使用spec中loadBalancerSourceRanges。兼容起来麻烦,也只能运维配置,最终可能还不如在游戏层实现【Projxx】</p> <h3 id="2-16lb">2. 产生大量不好识别的16进制名称的<span class="caps">LB</span><a class="headerlink" href="#2-16lb" title="Permanent link">&para;</a></h3> <p>LoadBalance型服务,产生的名字不规律。难识别。</p> <h3 id="3-ingress">3. ingress 与动静文件分离问题<a class="headerlink" href="#3-ingress" title="Permanent link">&para;</a></h3> <p>使用nginx&nbsp;ingress也无法做到动静分离,只能将静态文件另外部署,如cdn,ingress后配nginx服等等。</p> <p><a href="https://github.com/nginxinc/kubernetes-ingress/issues/323" title="#323">How to setup ingress to serve static content on kubernetes?&nbsp;#323</a></p>面试算法编程选记2题之二分法-寻找斜率为K的2点2020-06-22T00:00:00+08:002020-06-22T00:00:00+08:00pythonwoodtag:blog.pythonwood.com,2020-06-22:/2020/06/面试算法编程选记2题之二分查-寻找斜率为K的2点/<p>因为一直是用自学+坚持自学方法走过来的,折腾技术运用还可以,基础算法编程能力一直偏弱。</p> <p>1、二分法属于思维简单,细节弄人的典型。之前陷入过二分法脑风暴中不能通透,这次趁面试遇到好好再过一次,提高深度。</p> <p>2、输入数组A 例如&nbsp;[(x1,y1),(x2,y2)&hellip;],输出斜率为K的点对数目</p> <h3 id="_1">二分查找<a class="headerlink" href="#_1" title="Permanent link">&para;</a></h3> <p>二分查找要处理好中点 …</p><p>因为一直是用自学+坚持自学方法走过来的,折腾技术运用还可以,基础算法编程能力一直偏弱。</p> <p>1、二分法属于思维简单,细节弄人的典型。之前陷入过二分法脑风暴中不能通透,这次趁面试遇到好好再过一次,提高深度。</p> <p>2、输入数组A 例如&nbsp;[(x1,y1),(x2,y2)&hellip;],输出斜率为K的点对数目</p> <h3 id="_1">二分查找<a class="headerlink" href="#_1" title="Permanent link">&para;</a></h3> <p>二分查找要处理好中点,缩小方法,避免死循环。重在细节实现。&nbsp;Plus增强后支持最左最右查找</p> <p>已过 leetcode算法题:<a href="https://www.nowcoder.com/questionTerminal/28d5a9b7fc0b4a078c9a6d59830fb9b9">https://www.nowcoder.com/questionTerminal/28d5a9b7fc0b4a078c9a6d59830fb9b9</a></p> <div class="highlight"><pre><span></span><span class="s s-Atom">class</span> <span class="nv">BinarySearch</span><span class="s s-Atom">:</span> <span class="s s-Atom">def</span> <span class="nf">getPos</span><span class="p">(</span><span class="s s-Atom">self</span><span class="p">,</span> <span class="nv">A</span><span class="p">,</span> <span class="s s-Atom">n</span><span class="p">,</span> <span class="s s-Atom">val</span><span class="p">)</span><span class="s s-Atom">:</span> <span class="s s-Atom">a1</span><span class="p">,</span> <span class="s s-Atom">a2</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="s s-Atom">n</span><span class="o">-</span><span class="mi">1</span> <span class="s s-Atom">#</span> <span class="s s-Atom">a1</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="s s-Atom">a2</span> <span class="o">=</span> <span class="s s-Atom">n</span><span class="o">-</span><span class="mi">1</span><span class="p">;</span> <span class="s s-Atom">while</span> <span class="s s-Atom">a1</span> <span class="s s-Atom">&lt;=</span> <span class="s s-Atom">a2:</span> <span class="s s-Atom">#</span> <span class="s s-Atom">a1</span><span class="p">,</span> <span class="s s-Atom">a2</span> <span class="s s-Atom">位置未检</span> <span class="s s-Atom">mid</span> <span class="o">=</span> <span class="p">(</span><span class="s s-Atom">a1</span><span class="o">+</span><span class="s s-Atom">a2</span><span class="p">)</span><span class="o">//</span><span class="mi">2</span> <span class="s s-Atom">#</span> <span class="s s-Atom">中间索引赋值是关键,可等左,不等右</span> <span class="s s-Atom">#</span> <span class="nf">print</span><span class="p">(</span><span class="s s-Atom">val</span><span class="p">,</span> <span class="nv">A</span><span class="p">,</span> <span class="s s-Atom">a1</span><span class="p">,</span> <span class="s s-Atom">a2</span><span class="p">,</span> <span class="s s-Atom">mid</span><span class="p">)</span> <span class="s s-Atom">if</span> <span class="nv">A</span><span class="p">[</span><span class="s s-Atom">mid</span><span class="p">]</span> <span class="o">==</span> <span class="nn">val</span><span class="p">:</span> <span class="s s-Atom">return</span> <span class="s s-Atom">mid</span> <span class="s s-Atom">elif</span> <span class="nv">A</span><span class="p">[</span><span class="s s-Atom">mid</span><span class="p">]</span> <span class="o">&lt;</span> <span class="nn">val</span><span class="p">:</span> <span class="s s-Atom">#</span> <span class="nf">print</span><span class="p">(</span><span class="nv">A</span><span class="p">,</span> <span class="s s-Atom">a1</span><span class="p">,</span> <span class="s s-Atom">a2</span><span class="p">,</span> <span class="s s-Atom">mid</span><span class="p">)</span> <span class="s s-Atom">a1</span> <span class="o">=</span> <span class="s s-Atom">mid</span> <span class="o">+</span> <span class="mi">1</span> <span class="s s-Atom">#</span> <span class="nf">print</span><span class="p">(</span><span class="nv">A</span><span class="p">,</span> <span class="s s-Atom">a1</span><span class="p">,</span> <span class="s s-Atom">a2</span><span class="p">,</span> <span class="s s-Atom">mid</span><span class="p">)</span> <span class="nn">else</span><span class="p">:</span> <span class="s s-Atom">a2</span> <span class="o">=</span> <span class="s s-Atom">mid</span> <span class="o">-</span> <span class="mi">1</span> <span class="nn">else</span><span class="p">:</span> <span class="s s-Atom">return</span> <span class="o">-</span><span class="mi">1</span> <span class="s s-Atom">def</span> <span class="nf">getPosPlus</span><span class="p">(</span><span class="s s-Atom">self</span><span class="p">,</span> <span class="nv">A</span><span class="p">,</span> <span class="s s-Atom">n</span><span class="p">,</span> <span class="s s-Atom">val</span><span class="p">,</span> <span class="s s-Atom">searchtype</span><span class="o">=</span><span class="mi">0</span><span class="p">)</span><span class="s s-Atom">:</span> <span class="s s-Atom">&#39;&#39;&#39;支持最左,最右二分查找的修改Plus版本</span> <span class="s s-Atom"> &#39;left&#39;:-1, &#39;fast&#39;:0, &#39;right&#39;:1 其中0是默认版本,找到即返回。</span> <span class="s s-Atom"> &#39;&#39;&#39;</span> <span class="s s-Atom">a1</span><span class="p">,</span> <span class="s s-Atom">a2</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="s s-Atom">n</span><span class="o">-</span><span class="mi">1</span> <span class="s s-Atom">while</span> <span class="s s-Atom">a1</span> <span class="o">&lt;</span> <span class="s s-Atom">a2:</span> <span class="s s-Atom">#</span> <span class="s s-Atom">直到重合时,单元素</span> <span class="s s-Atom">mid</span> <span class="o">=</span> <span class="p">(</span><span class="s s-Atom">a1</span><span class="o">+</span><span class="s s-Atom">a2</span><span class="p">)</span><span class="o">//</span><span class="mi">2</span> <span class="s s-Atom">#</span> <span class="s s-Atom">中间索引赋值是关键,可等左,不等右</span> <span class="s s-Atom">#</span> <span class="nf">print</span><span class="p">(</span><span class="s s-Atom">val</span><span class="p">,</span> <span class="nv">A</span><span class="p">,</span> <span class="s s-Atom">a1</span><span class="p">,</span> <span class="s s-Atom">a2</span><span class="p">,</span> <span class="s s-Atom">mid</span><span class="p">)</span> <span class="s s-Atom">if</span> <span class="nv">A</span><span class="p">[</span><span class="s s-Atom">mid</span><span class="p">]</span> <span class="o">==</span> <span class="nn">val</span><span class="p">:</span> <span class="s s-Atom">if</span> <span class="s s-Atom">searchtype</span> <span class="o">==</span> <span class="mi">0</span><span class="s s-Atom">:</span> <span class="s s-Atom">return</span> <span class="s s-Atom">mid</span> <span class="s s-Atom">if</span> <span class="s s-Atom">searchtype</span> <span class="o">==</span> <span class="o">-</span><span class="mi">1</span><span class="s s-Atom">:</span> <span class="s s-Atom">a2</span> <span class="o">=</span> <span class="s s-Atom">mid</span> <span class="s s-Atom">elif</span> <span class="s s-Atom">searchtype</span> <span class="o">==</span> <span class="mi">1</span><span class="s s-Atom">:</span> <span class="s s-Atom">a1</span> <span class="o">=</span> <span class="s s-Atom">mid</span> <span class="s s-Atom">elif</span> <span class="nv">A</span><span class="p">[</span><span class="s s-Atom">mid</span><span class="p">]</span> <span class="o">&lt;</span> <span class="nn">val</span><span class="p">:</span> <span class="s s-Atom">#</span> <span class="nf">print</span><span class="p">(</span><span class="nv">A</span><span class="p">,</span> <span class="s s-Atom">a1</span><span class="p">,</span> <span class="s s-Atom">a2</span><span class="p">,</span> <span class="s s-Atom">mid</span><span class="p">)</span> <span class="s s-Atom">a1</span> <span class="o">=</span> <span class="s s-Atom">mid</span> <span class="s s-Atom">if</span> <span class="s s-Atom">a1</span> <span class="o">+</span> <span class="mi">1</span> <span class="o">==</span> <span class="s s-Atom">a2:</span> <span class="s s-Atom">#</span> <span class="s s-Atom">避免剩余2个元素时,</span> <span class="s s-Atom">mid=左陷入死循环</span> <span class="s s-Atom">a1</span> <span class="o">=</span> <span class="s s-Atom">a2</span> <span class="s s-Atom">#</span> <span class="nf">print</span><span class="p">(</span><span class="nv">A</span><span class="p">,</span> <span class="s s-Atom">a1</span><span class="p">,</span> <span class="s s-Atom">a2</span><span class="p">,</span> <span class="s s-Atom">mid</span><span class="p">)</span> <span class="nn">else</span><span class="p">:</span> <span class="s s-Atom">a2</span> <span class="o">=</span> <span class="s s-Atom">mid</span> <span class="nn">else</span><span class="p">:</span> <span class="s s-Atom">assert</span> <span class="s s-Atom">a1</span> <span class="o">==</span> <span class="s s-Atom">a2</span> <span class="s s-Atom">return</span> <span class="s s-Atom">a1</span> <span class="s s-Atom">if</span> <span class="nv">A</span><span class="p">[</span><span class="s s-Atom">a1</span><span class="p">]</span> <span class="o">==</span> <span class="s s-Atom">val</span> <span class="s s-Atom">else</span> <span class="o">-</span><span class="mi">1</span> <span class="s s-Atom">if</span> <span class="k">__</span><span class="s s-Atom">name__</span> <span class="o">==</span> <span class="s s-Atom">&#39;__main__&#39;:</span> <span class="s s-Atom">rt</span> <span class="o">=</span> <span class="nv">BinarySearch</span><span class="p">()</span> <span class="s s-Atom">for</span> <span class="nv">A</span> <span class="nf">in</span> <span class="p">((</span><span class="mi">1</span><span class="p">,),</span> <span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">5</span><span class="p">),</span> <span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">9</span><span class="p">),</span> <span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">5</span><span class="p">),</span> <span class="p">[</span><span class="mi">4</span><span class="p">,</span><span class="mi">4</span><span class="p">,</span><span class="mi">10</span><span class="p">,</span><span class="mi">21</span><span class="p">])</span><span class="s s-Atom">:</span> <span class="s s-Atom">n</span> <span class="o">=</span> <span class="nf">len</span><span class="p">(</span><span class="nv">A</span><span class="p">)</span> <span class="s s-Atom">for</span> <span class="s s-Atom">val</span> <span class="s s-Atom">in</span> <span class="nv">A</span><span class="s s-Atom">:</span> <span class="s s-Atom">#</span> <span class="s s-Atom">idx</span> <span class="o">=</span> <span class="s s-Atom">rt</span><span class="p">.</span><span class="nf">getPos</span><span class="p">(</span><span class="nv">A</span><span class="p">,</span> <span class="s s-Atom">n</span><span class="p">,</span> <span class="s s-Atom">val</span><span class="p">)</span> <span class="s s-Atom">#</span> <span class="nf">print</span><span class="p">(</span><span class="s s-Atom">&#39;find %3s in %10s: index=%s&#39;</span> <span class="c1">% (val, A, idx))</span> <span class="s s-Atom">#</span> <span class="s s-Atom">支持最左,最右二分查找的修改Plus版本</span> <span class="s s-Atom">idx</span> <span class="o">=</span> <span class="s s-Atom">rt</span><span class="p">.</span><span class="nf">getPosPlus</span><span class="p">(</span><span class="nv">A</span><span class="p">,</span> <span class="s s-Atom">n</span><span class="p">,</span> <span class="s s-Atom">val</span><span class="p">)</span> <span class="nf">print</span><span class="p">(</span><span class="s s-Atom">&#39;find %3s in %10s: index=%s&#39;</span> <span class="c1">% (val, A, idx))</span> <span class="s s-Atom">idx</span> <span class="o">=</span> <span class="s s-Atom">rt</span><span class="p">.</span><span class="nf">getPosPlus</span><span class="p">(</span><span class="nv">A</span><span class="p">,</span> <span class="s s-Atom">n</span><span class="p">,</span> <span class="s s-Atom">val</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="nf">print</span><span class="p">(</span><span class="s s-Atom">&#39;find %3s in %10s: index=%s&#39;</span> <span class="c1">% (val, A, idx))</span> </pre></div> <h3 id="k">寻找斜率为K的点对<a class="headerlink" href="#k" title="Permanent link">&para;</a></h3> <p>算法题:</p> <p>有一个数组,数组每个元素是一个对象,每个对象有x和y两个值,这个数组记录 为A: A = [{x1, y1}, {x2, y2}, &hellip;];我们把数组A中任意两个满足以下关系的元素叫 做“点对”:(y2-y1)/(x2-x1) = K, K是一个常数。编写程序:给定A与K,返回A中点&nbsp;对的数目。</p> <div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">itertools</span> <span class="kn">import</span> <span class="n">groupby</span> <span class="n">K</span> <span class="o">=</span> <span class="mi">1</span> <span class="c1"># 斜率</span> <span class="k">def</span> <span class="nf">kpairs</span><span class="p">(</span><span class="n">A</span><span class="p">,</span> <span class="n">k</span><span class="o">=</span><span class="n">K</span><span class="p">):</span> <span class="sd">&#39;&#39;&#39;</span> <span class="sd"> 分析:计算一遍点到直线y=kx距离 |Kx - y| / √(k*k+1),距离等两点的可能与y=kx平行。先验证y=kx上的,距离等不一定平行。</span> <span class="sd"> 技巧:结合题目实际,可不开平方pow运算,不取绝对值。</span> <span class="sd"> &#39;&#39;&#39;</span> <span class="k">print</span><span class="p">(</span><span class="s1">&#39;debug: kpairs(</span><span class="si">%s</span><span class="s1">, </span><span class="si">%s</span><span class="s1">)&#39;</span> <span class="o">%</span> <span class="p">(</span><span class="n">k</span><span class="p">,</span> <span class="n">A</span><span class="p">))</span> <span class="n">result</span> <span class="o">=</span> <span class="mi">0</span> <span class="n">distance</span> <span class="o">=</span> <span class="p">[</span> <span class="p">(</span><span class="n">k</span><span class="o">*</span><span class="n">x</span><span class="o">-</span><span class="n">y</span><span class="p">)</span> <span class="o">/</span> <span class="p">(</span><span class="n">k</span><span class="o">**</span><span class="mi">2</span><span class="o">+</span><span class="mi">1</span><span class="p">)</span> <span class="k">for</span> <span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">)</span> <span class="ow">in</span> <span class="n">A</span> <span class="p">]</span> <span class="n">point_distance</span> <span class="o">=</span> <span class="nb">sorted</span><span class="p">(</span><span class="nb">zip</span><span class="p">(</span><span class="n">A</span><span class="p">,</span> <span class="n">distance</span><span class="p">),</span> <span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="n">x</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> <span class="c1"># 距离排序,取点</span> <span class="k">for</span> <span class="n">distance</span><span class="p">,</span> <span class="n">pointiter</span> <span class="ow">in</span> <span class="n">groupby</span><span class="p">(</span><span class="n">point_distance</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="n">x</span><span class="p">[</span><span class="mi">1</span><span class="p">]):</span> <span class="n">points</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">x</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">pointiter</span><span class="p">)</span> <span class="n">count</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">points</span><span class="p">)</span> <span class="k">print</span><span class="p">(</span><span class="s1">&#39;debug: line:y=</span><span class="si">%3s</span><span class="s1">x, got </span><span class="si">%3s</span><span class="s1"> point distance=</span><span class="si">%7.3s</span><span class="s1">: </span><span class="si">%s</span><span class="s1">&#39;</span> <span class="o">%</span> <span class="p">(</span><span class="n">k</span><span class="p">,</span> <span class="n">count</span><span class="p">,</span> <span class="n">distance</span><span class="p">,</span> <span class="n">points</span><span class="p">))</span> <span class="c1"># debug</span> <span class="k">if</span> <span class="n">count</span> <span class="o">&gt;</span> <span class="mi">1</span><span class="p">:</span> <span class="n">result</span> <span class="o">+=</span> <span class="n">count</span><span class="o">*</span><span class="p">(</span><span class="n">count</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span><span class="o">/</span><span class="mi">2</span> <span class="c1"># 组合数 4 -&gt; 6</span> <span class="k">return</span> <span class="n">result</span> <span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s1">&#39;__main__&#39;</span><span class="p">:</span> <span class="n">A</span> <span class="o">=</span> <span class="p">[(</span><span class="mi">0</span><span class="p">,</span><span class="mi">3</span><span class="p">),</span> <span class="p">(</span><span class="mi">3</span><span class="p">,</span><span class="mi">0</span><span class="p">),</span> <span class="p">(</span><span class="mi">3</span><span class="p">,</span><span class="mi">3</span><span class="p">),</span> <span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">)]</span> <span class="c1"># 正方形</span> <span class="k">assert</span> <span class="n">kpairs</span><span class="p">(</span><span class="n">A</span><span class="p">)</span> <span class="o">==</span> <span class="mi">1</span><span class="p">,</span> <span class="s1">&#39;check and debug kpairs(</span><span class="si">%s</span><span class="s1">)&#39;</span><span class="o">%</span><span class="n">A</span> <span class="k">assert</span> <span class="n">kpairs</span><span class="p">(</span><span class="n">A</span><span class="p">,</span> <span class="mi">10</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span><span class="p">,</span> <span class="s1">&#39;check and debug kpairs(</span><span class="si">%s</span><span class="s1">)&#39;</span><span class="o">%</span><span class="n">A</span> <span class="n">A</span> <span class="o">=</span> <span class="p">[(</span><span class="mi">3</span><span class="p">,</span><span class="mi">9</span><span class="p">),</span> <span class="p">(</span><span class="mi">9</span><span class="p">,</span><span class="mi">9</span><span class="p">),</span> <span class="p">(</span><span class="mi">20</span><span class="p">,</span><span class="mi">20</span><span class="p">),</span> <span class="p">(</span><span class="mi">10</span><span class="p">,</span><span class="mi">16</span><span class="p">),</span> <span class="p">(</span><span class="mi">22</span><span class="p">,</span><span class="mi">28</span><span class="p">)]</span> <span class="k">assert</span> <span class="n">kpairs</span><span class="p">(</span><span class="n">A</span><span class="p">)</span> <span class="o">==</span> <span class="mi">4</span><span class="p">,</span> <span class="s1">&#39;check and debug kpairs(</span><span class="si">%s</span><span class="s1">)&#39;</span><span class="o">%</span><span class="n">A</span> <span class="k">assert</span> <span class="n">kpairs</span><span class="p">(</span><span class="n">A</span><span class="p">,</span> <span class="mi">4</span><span class="p">)</span> <span class="o">==</span> <span class="mi">1</span><span class="p">,</span> <span class="s1">&#39;check and debug kpairs(</span><span class="si">%s</span><span class="s1">)&#39;</span><span class="o">%</span><span class="n">A</span> </pre></div> <h2 id="_2">参考<a class="headerlink" href="#_2" title="Permanent link">&para;</a></h2> <ol> <li>点到直线距离公式的几种推导 <a href="https://zhuanlan.zhihu.com/p/26307123">https://zhuanlan.zhihu.com/p/26307123</a></li> </ol>面试高频题-LRU缓存的python实现2019-08-22T14:00:00+08:002019-08-22T14:00:00+08:00pythonwoodtag:blog.pythonwood.com,2019-08-22:/2019/08/面试高频题-LRU缓存的python实现/<p>过程简略:&nbsp;url去重的方法,数据库四种隔离级别,乐观锁悲观锁,算法题研讨。算法讨论占了很长时间,以下是把这个过程沉淀后的一遍随笔。</p> <h3 id="leetcode146-lru">leetcode算法题:146. <span class="caps">LRU</span>缓存机制<a class="headerlink" href="#leetcode146-lru" title="Permanent link">&para;</a></h3> <p><a href="https://leetcode-cn.com/problems/lru-cache/">https://leetcode-cn.com/problems/lru-cache/</a></p> <blockquote> <p>运用你所掌握的数据结构,设计和实现一个  <span class="caps">LRU</span> (最近最少使用 …</p></blockquote><p>过程简略:&nbsp;url去重的方法,数据库四种隔离级别,乐观锁悲观锁,算法题研讨。算法讨论占了很长时间,以下是把这个过程沉淀后的一遍随笔。</p> <h3 id="leetcode146-lru">leetcode算法题:146. <span class="caps">LRU</span>缓存机制<a class="headerlink" href="#leetcode146-lru" title="Permanent link">&para;</a></h3> <p><a href="https://leetcode-cn.com/problems/lru-cache/">https://leetcode-cn.com/problems/lru-cache/</a></p> <blockquote> <p>运用你所掌握的数据结构,设计和实现一个  <span class="caps">LRU</span> (最近最少使用) 缓存机制。它应该支持以下操作: 获取数据 get 和 写入数据 put&nbsp;。</p> <p>获取数据 get(key) - 如果密钥 (key) 存在于缓存中,则获取密钥的值(总是正数),否则返回&nbsp;-1。</p> <p>写入数据 put(key, value) -&nbsp;如果密钥不存在,则写入其数据值。当缓存容量达到上限时,它应该在写入新数据之前删除最近最少使用的数据值,从而为新的数据值留出空间。</p> <p>进阶:</p> <p>你是否可以在 O(1)&nbsp;时间复杂度内完成这两种操作?</p> <p>示例:</p> </blockquote> <div class="highlight"><pre><span></span>LRUCache cache = new LRUCache( 2 /* 缓存容量 */ ); cache.put(1, 1); cache.put(2, 2); cache.get(1); // 返回 1 cache.put(3, 3); // 该操作会使得密钥 2 作废 cache.get(2); // 返回 -1 (未找到) cache.put(4, 4); // 该操作会使得密钥 1 作废 cache.get(1); // 返回 -1 (未找到) cache.get(3); // 返回 3 cache.get(4); // 返回 4 </pre></div> <h2 id="_1">思考过程简要<a class="headerlink" href="#_1" title="Permanent link">&para;</a></h2> <p>第一次遇到,没有做好题。之后总结思考如下。面试完重新整理好代码,才通过。</p> <p>1、数据结构知识弱,链表随机增删复杂度O(1),&nbsp;数组复杂度O(n)。使用按时间排序的双向链表。头部总是最新访问或插入的,尾巴总是最老的。使用额外maxsize限制大小,nowsize记录目前大小。</p> <p>2、链表元素是key-val的进一步封装的Node类。链表是另一个类,类总head和tail表示头尾两个空的node。一直不删。</p> <p>3、开头想到最小堆,用得不对。二分法等比较查找下限O(lgN),与哈希法的O(1)差距意识不明显。而哈希函数用内置字典即可。</p> <p>4、拆分小函数复用代码。比如get = 出链 + 插入头部, put = 出链 + 插入头部(update) 或者&nbsp;插入头部(非update)</p> <p>5、之后发现python有functools.lru_cache的现成实现,值得学习。</p> <h2 id="leetcode">leetcode通过提交的代码<a class="headerlink" href="#leetcode" title="Permanent link">&para;</a></h2> <div class="highlight"><pre><span></span><span class="kr">class</span> <span class="nx">Node</span>: <span class="kt">def</span> <span class="nx">__init__</span><span class="p">(</span><span class="nx">self</span><span class="p">,</span> <span class="nx">key</span><span class="o">=</span><span class="nx">None</span><span class="p">,</span> <span class="nx">val</span><span class="o">=</span><span class="nx">None</span><span class="p">)</span><span class="o">:</span> <span class="nx">self</span><span class="p">.</span><span class="nx">key</span> <span class="o">=</span> <span class="nx">key</span> <span class="nx">self</span><span class="p">.</span><span class="nx">val</span> <span class="o">=</span> <span class="nx">val</span> <span class="nx">self</span><span class="p">.</span><span class="nx">prev</span> <span class="o">=</span> <span class="nx">None</span> <span class="nx">self</span><span class="p">.</span><span class="nx">next</span> <span class="o">=</span> <span class="nx">None</span> <span class="kr">class</span> <span class="nx">LRUCache</span><span class="o">:</span> <span class="s1">&#39;&#39;&#39;</span> <span class="s1"> 小函数: 删node,入head</span> <span class="s1"> 注意:head和tail是空的node,不能删除</span> <span class="s1"> &#39;&#39;&#39;</span> <span class="nx">def</span> <span class="nx">__init__</span><span class="p">(</span><span class="nx">self</span><span class="p">,</span> <span class="nx">maxsize</span><span class="o">=</span><span class="mi">10</span><span class="p">)</span><span class="o">:</span> <span class="nx">self</span><span class="p">.</span><span class="nx">maxsize</span> <span class="o">=</span> <span class="nx">maxsize</span> <span class="nx">self</span><span class="p">.</span><span class="nx">nowsize</span> <span class="o">=</span> <span class="mi">0</span> <span class="nx">self</span><span class="p">.</span><span class="nx">head</span> <span class="o">=</span> <span class="nx">Node</span><span class="p">()</span> <span class="nx">self</span><span class="p">.</span><span class="nx">tail</span> <span class="o">=</span> <span class="nx">Node</span><span class="p">()</span> <span class="nx">self</span><span class="p">.</span><span class="nx">tail</span><span class="p">.</span><span class="nx">prev</span> <span class="o">=</span> <span class="nx">self</span><span class="p">.</span><span class="nx">head</span> <span class="nx">self</span><span class="p">.</span><span class="nx">head</span><span class="p">.</span><span class="nx">next</span> <span class="o">=</span> <span class="nx">self</span><span class="p">.</span><span class="nx">tail</span> <span class="err">#</span> <span class="nx">key</span> <span class="o">-&gt;</span> <span class="nx">nodes</span><span class="p">.</span><span class="nx">val</span> <span class="nx">self</span><span class="p">.</span><span class="nx">nodes</span> <span class="o">=</span> <span class="p">{}</span> <span class="nx">def</span> <span class="nx">get</span><span class="p">(</span><span class="nx">self</span><span class="p">,</span> <span class="nx">key</span><span class="p">)</span><span class="o">:</span> <span class="nx">node</span> <span class="o">=</span> <span class="nx">self</span><span class="p">.</span><span class="nx">nodes</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="nx">key</span><span class="p">,</span> <span class="nx">None</span><span class="p">)</span> <span class="k">if</span> <span class="nx">node</span> <span class="o">!=</span> <span class="nx">None</span><span class="o">:</span> <span class="err">#</span> <span class="mi">2019</span><span class="o">-</span><span class="mi">08</span><span class="o">-</span><span class="mi">21</span><span class="err">面试时加的要求</span> <span class="nx">self</span><span class="p">.</span><span class="nx">popNode</span><span class="p">(</span><span class="nx">node</span><span class="p">)</span> <span class="nx">self</span><span class="p">.</span><span class="nx">addNode</span><span class="p">(</span><span class="nx">node</span><span class="p">)</span> <span class="k">return</span> <span class="nx">node</span><span class="p">.</span><span class="nx">val</span> <span class="k">else</span><span class="o">:</span> <span class="k">return</span> <span class="o">-</span><span class="mi">1</span> <span class="nx">def</span> <span class="nx">put</span><span class="p">(</span><span class="nx">self</span><span class="p">,</span> <span class="nx">key</span><span class="p">,</span> <span class="nx">val</span><span class="p">)</span><span class="o">:</span> <span class="nx">self</span><span class="p">.</span><span class="nx">set</span><span class="p">(</span><span class="nx">key</span><span class="p">,</span> <span class="nx">val</span><span class="p">)</span> <span class="nx">def</span> <span class="nx">set</span><span class="p">(</span><span class="nx">self</span><span class="p">,</span> <span class="nx">key</span><span class="p">,</span> <span class="nx">val</span><span class="p">)</span><span class="o">:</span> <span class="nx">node</span> <span class="o">=</span> <span class="nx">self</span><span class="p">.</span><span class="nx">nodes</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="nx">key</span><span class="p">,</span> <span class="nx">None</span><span class="p">)</span> <span class="k">if</span> <span class="nx">node</span> <span class="o">!=</span> <span class="nx">None</span><span class="o">:</span> <span class="err">#</span> <span class="err">在链表中,</span><span class="nx">update</span><span class="err">操作</span> <span class="nx">self</span><span class="p">.</span><span class="nx">popNode</span><span class="p">(</span><span class="nx">node</span><span class="p">)</span> <span class="err">#</span> <span class="nx">self</span><span class="p">.</span><span class="nx">addNode</span><span class="p">(</span><span class="nx">Node</span><span class="p">(</span><span class="nx">key</span><span class="p">,</span> <span class="nx">val</span><span class="p">))</span> <span class="nx">def</span> <span class="k">delete</span><span class="p">(</span><span class="nx">self</span><span class="p">,</span> <span class="nx">key</span><span class="p">)</span><span class="o">:</span> <span class="nx">node</span> <span class="o">=</span> <span class="nx">self</span><span class="p">.</span><span class="nx">nodes</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="nx">key</span><span class="p">,</span> <span class="nx">None</span><span class="p">)</span> <span class="k">if</span> <span class="nx">node</span> <span class="o">!=</span> <span class="nx">None</span>: <span class="kt">self.popNode</span><span class="p">(</span><span class="nx">node</span><span class="p">)</span> <span class="nx">def</span> <span class="nx">popNode</span><span class="p">(</span><span class="nx">self</span><span class="p">,</span> <span class="nx">node</span><span class="p">)</span><span class="o">:</span> <span class="k">if</span> <span class="nx">node</span><span class="p">.</span><span class="nx">val</span> <span class="o">==</span> <span class="nx">None</span>: <span class="kt">return</span> <span class="err">#</span> <span class="err">使用</span><span class="nx">head</span><span class="err">和</span><span class="nx">tail</span><span class="err">为空</span><span class="nx">node</span><span class="err">时无需检查</span> <span class="err">#</span> <span class="k">if</span> <span class="nx">node</span><span class="p">.</span><span class="nx">next</span><span class="o">:</span> <span class="err">#</span> <span class="nx">node</span><span class="p">.</span><span class="nx">next</span><span class="p">.</span><span class="nx">prev</span> <span class="o">=</span> <span class="nx">node</span><span class="p">.</span><span class="nx">prev</span> <span class="err">#</span> <span class="k">else</span><span class="o">:</span> <span class="err">#</span> <span class="nx">self</span><span class="p">.</span><span class="nx">tail</span> <span class="o">=</span> <span class="nx">node</span><span class="p">.</span><span class="nx">next</span> <span class="err">#</span> <span class="k">if</span> <span class="nx">node</span><span class="p">.</span><span class="nx">prev</span><span class="o">:</span> <span class="err">#</span> <span class="nx">node</span><span class="p">.</span><span class="nx">prev</span><span class="p">.</span><span class="nx">next</span> <span class="o">=</span> <span class="nx">node</span><span class="p">.</span><span class="nx">next</span> <span class="err">#</span> <span class="k">else</span><span class="o">:</span> <span class="err">#</span> <span class="nx">self</span><span class="p">.</span><span class="nx">head</span> <span class="o">=</span> <span class="nx">node</span><span class="p">.</span><span class="nx">next</span> <span class="nx">node</span><span class="p">.</span><span class="nx">next</span><span class="p">.</span><span class="nx">prev</span> <span class="o">=</span> <span class="nx">node</span><span class="p">.</span><span class="nx">prev</span> <span class="nx">node</span><span class="p">.</span><span class="nx">prev</span><span class="p">.</span><span class="nx">next</span> <span class="o">=</span> <span class="nx">node</span><span class="p">.</span><span class="nx">next</span> <span class="nx">self</span><span class="p">.</span><span class="nx">nowsize</span> <span class="o">-=</span> <span class="mi">1</span> <span class="err">#</span> <span class="err">字典更新</span> <span class="nx">del</span> <span class="nx">self</span><span class="p">.</span><span class="nx">nodes</span><span class="p">[</span><span class="nx">node</span><span class="p">.</span><span class="nx">key</span><span class="p">]</span> <span class="k">return</span> <span class="nx">node</span> <span class="nx">def</span> <span class="nx">addNode</span><span class="p">(</span><span class="nx">self</span><span class="p">,</span> <span class="nx">node</span><span class="p">)</span><span class="o">:</span> <span class="err">#</span> <span class="err">总在链表头加入</span> <span class="k">if</span> <span class="nx">node</span><span class="p">.</span><span class="nx">val</span> <span class="o">==</span> <span class="nx">None</span>: <span class="kt">return</span> <span class="k">if</span> <span class="nx">self</span><span class="p">.</span><span class="nx">nowsize</span> <span class="o">&gt;=</span> <span class="nx">self</span><span class="p">.</span><span class="nx">maxsize</span><span class="o">:</span> <span class="err">#</span> <span class="err">满了,就去掉尾巴再插入</span> <span class="nx">self</span><span class="p">.</span><span class="nx">popNode</span><span class="p">(</span><span class="nx">self</span><span class="p">.</span><span class="nx">tail</span><span class="p">.</span><span class="nx">prev</span><span class="p">)</span> <span class="nx">node</span><span class="p">.</span><span class="nx">next</span> <span class="o">=</span> <span class="nx">self</span><span class="p">.</span><span class="nx">head</span><span class="p">.</span><span class="nx">next</span> <span class="nx">node</span><span class="p">.</span><span class="nx">prev</span> <span class="o">=</span> <span class="nx">self</span><span class="p">.</span><span class="nx">head</span> <span class="nx">self</span><span class="p">.</span><span class="nx">head</span><span class="p">.</span><span class="nx">next</span><span class="p">.</span><span class="nx">prev</span> <span class="o">=</span> <span class="nx">node</span> <span class="nx">self</span><span class="p">.</span><span class="nx">head</span><span class="p">.</span><span class="nx">next</span> <span class="o">=</span> <span class="nx">node</span> <span class="err">#</span> <span class="err">费时的</span><span class="nx">debug</span><span class="err">错误:这句之后</span><span class="p">[[</span><span class="s1">&#39;c&#39;</span><span class="p">,</span> <span class="mi">12</span><span class="p">]]</span> <span class="o">-&gt;</span> <span class="p">[]</span> <span class="nx">self</span><span class="p">.</span><span class="nx">nowsize</span> <span class="o">+=</span> <span class="mi">1</span> <span class="err">#</span> <span class="err">字典增加</span> <span class="nx">self</span><span class="p">.</span><span class="nx">nodes</span><span class="p">[</span><span class="nx">node</span><span class="p">.</span><span class="nx">key</span><span class="p">]</span> <span class="o">=</span> <span class="nx">node</span> <span class="kd">@property</span> <span class="nx">def</span> <span class="nx">vals</span><span class="p">(</span><span class="nx">self</span><span class="p">)</span><span class="o">:</span> <span class="err">#</span> <span class="nx">debug</span> <span class="err">#</span> <span class="nx">node</span> <span class="o">=</span> <span class="nx">self</span><span class="p">.</span><span class="nx">head</span> <span class="err">#</span> <span class="err">错误:发现用时</span><span class="mi">15</span><span class="err">分钟</span> <span class="nx">node</span> <span class="o">=</span> <span class="nx">self</span><span class="p">.</span><span class="nx">head</span><span class="p">.</span><span class="nx">next</span> <span class="nx">_vals</span> <span class="o">=</span> <span class="p">[]</span> <span class="err">#</span> <span class="k">while</span> <span class="nx">node</span><span class="p">.</span><span class="nx">val</span><span class="o">:</span> <span class="err">#</span> <span class="mi">2019</span><span class="o">-</span><span class="mi">08</span><span class="o">-</span><span class="mi">21</span><span class="err">大坑,</span><span class="nx">node</span><span class="p">.</span><span class="nx">val</span> <span class="o">=</span> <span class="mi">0</span><span class="err">时会失败!费了</span><span class="mi">1</span><span class="err">小时!!!</span> <span class="k">while</span> <span class="nx">node</span> <span class="o">!=</span> <span class="nx">None</span> <span class="nx">and</span> <span class="nx">node</span><span class="p">.</span><span class="nx">val</span> <span class="o">!=</span> <span class="nx">None</span>: <span class="kt">_vals.append</span><span class="p">([</span><span class="nx">node</span><span class="p">.</span><span class="nx">key</span><span class="p">,</span><span class="nx">node</span><span class="p">.</span><span class="nx">val</span><span class="p">])</span> <span class="nx">node</span> <span class="o">=</span> <span class="nx">node</span><span class="p">.</span><span class="nx">next</span> <span class="k">return</span> <span class="nx">_vals</span> <span class="nx">def</span> <span class="nx">pprint</span><span class="p">(</span><span class="nx">self</span><span class="p">)</span><span class="o">:</span> <span class="err">#</span> <span class="nx">debug</span> <span class="nx">print</span><span class="p">(</span><span class="nx">self</span><span class="p">.</span><span class="nx">vals</span><span class="p">,</span> <span class="nx">flush</span><span class="o">=</span><span class="nx">True</span><span class="p">)</span> <span class="k">if</span> <span class="nx">__name__</span> <span class="o">==</span> <span class="s1">&#39;__main__&#39;</span><span class="o">:</span> <span class="nx">lru</span> <span class="o">=</span> <span class="nx">LRUCache</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span> <span class="nx">lru</span><span class="p">.</span><span class="nx">set</span><span class="p">(</span><span class="s1">&#39;b&#39;</span><span class="p">,</span> <span class="mi">12</span><span class="p">)</span> <span class="nx">lru</span><span class="p">.</span><span class="nx">pprint</span><span class="p">()</span> <span class="nx">print</span><span class="p">(</span><span class="s1">&#39;stage end: -----------------&#39;</span><span class="p">)</span> <span class="nx">lru</span><span class="p">.</span><span class="nx">set</span><span class="p">(</span><span class="s1">&#39;a&#39;</span><span class="p">,</span> <span class="mi">12</span><span class="p">)</span> <span class="nx">lru</span><span class="p">.</span><span class="nx">set</span><span class="p">(</span><span class="s1">&#39;d&#39;</span><span class="p">,</span> <span class="mi">12</span><span class="p">)</span> <span class="nx">lru</span><span class="p">.</span><span class="nx">set</span><span class="p">(</span><span class="s1">&#39;c&#39;</span><span class="p">,</span> <span class="mi">12</span><span class="p">)</span> <span class="nx">lru</span><span class="p">.</span><span class="nx">pprint</span><span class="p">()</span> <span class="nx">print</span><span class="p">(</span><span class="s1">&#39;stage end: -----------------&#39;</span><span class="p">)</span> <span class="nx">print</span><span class="p">(</span><span class="nx">lru</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s1">&#39;a&#39;</span><span class="p">))</span> <span class="nx">print</span><span class="p">(</span><span class="s1">&#39;stage end: -----------------&#39;</span><span class="p">)</span> <span class="nx">lru</span><span class="p">.</span><span class="k">delete</span><span class="p">(</span><span class="s1">&#39;a&#39;</span><span class="p">)</span> <span class="nx">lru</span><span class="p">.</span><span class="nx">pprint</span><span class="p">()</span> <span class="nx">print</span><span class="p">(</span><span class="s1">&#39;stage end: -----------------&#39;</span><span class="p">)</span> <span class="nx">lru</span><span class="p">.</span><span class="nx">set</span><span class="p">(</span><span class="s1">&#39;d&#39;</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="nx">lru</span><span class="p">.</span><span class="nx">pprint</span><span class="p">()</span> <span class="nx">print</span><span class="p">(</span><span class="s1">&#39;stage end: -----------------&#39;</span><span class="p">)</span> <span class="err">#</span> <span class="nx">leetcode</span><span class="err">的测试用例</span> <span class="nx">cache</span> <span class="o">=</span> <span class="nx">LRUCache</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span> <span class="nx">cache</span><span class="p">.</span><span class="nx">put</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span> <span class="nx">cache</span><span class="p">.</span><span class="nx">put</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">2</span><span class="p">);</span> <span class="nx">cache</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span> <span class="err">#</span> <span class="err">返回</span> <span class="mi">1</span> <span class="nx">cache</span><span class="p">.</span><span class="nx">pprint</span><span class="p">()</span> <span class="nx">cache</span><span class="p">.</span><span class="nx">put</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="mi">3</span><span class="p">);</span> <span class="err">#</span> <span class="err">该操作会使得密钥</span> <span class="mi">2</span> <span class="err">作废</span> <span class="nx">cache</span><span class="p">.</span><span class="nx">pprint</span><span class="p">()</span> <span class="nx">cache</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="mi">2</span><span class="p">);</span> <span class="err">#</span> <span class="err">返回</span> <span class="o">-</span><span class="mi">1</span> <span class="p">(</span><span class="err">未找到</span><span class="p">)</span> <span class="nx">cache</span><span class="p">.</span><span class="nx">pprint</span><span class="p">()</span> <span class="nx">cache</span><span class="p">.</span><span class="nx">put</span><span class="p">(</span><span class="mi">4</span><span class="p">,</span> <span class="mi">4</span><span class="p">);</span> <span class="err">#</span> <span class="err">该操作会使得密钥</span> <span class="mi">1</span> <span class="err">作废</span> <span class="nx">cache</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span> <span class="err">#</span> <span class="err">返回</span> <span class="o">-</span><span class="mi">1</span> <span class="p">(</span><span class="err">未找到</span><span class="p">)</span> <span class="nx">cache</span><span class="p">.</span><span class="nx">pprint</span><span class="p">()</span> <span class="nx">cache</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="mi">3</span><span class="p">);</span> <span class="err">#</span> <span class="err">返回</span> <span class="mi">3</span> <span class="nx">cache</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="mi">4</span><span class="p">);</span> <span class="err">#</span> <span class="err">返回</span> <span class="mi">4</span> </pre></div> <h2 id="_2">参考<a class="headerlink" href="#_2" title="Permanent link">&para;</a></h2> <ol> <li> <p>leetcode算法题:146. <span class="caps">LRU</span>缓存机制 <a href="https://leetcode-cn.com/problems/lru-cache/">https://leetcode-cn.com/problems/lru-cache/</a></p> </li> <li> <p>Python 缓存机制与 functools.lru_cache <a href="http://blog.konghy.cn/2016/04/20/python-cache/">http://blog.konghy.cn/2016/04/20/python-cache/</a></p> </li> </ol>Linux服务器安装轻量X环境xfce桌面和VNC服务2019-04-27T21:00:00+08:002019-04-27T21:00:00+08:00pythonwoodtag:blog.pythonwood.com,2019-04-27:/2019/04/Linux服务器安装轻量X环境xfce桌面和VNC服务/<p>有些任务需要Linux桌面环境,例如使用chrome/firefox浏览器进行测试或抓取数据。简要记录安装过程备需。任何时候,一个免key的<span class="caps">SSH</span>登录环境都能带来方便。</p> <p>以下环境是Ubuntu18.04,&nbsp;Ubuntu其他版本大同小异。其他linux发行版需修改。</p> <h3 id="xfce">安装必须的xfce桌面基础包。还有语言支持包<a class="headerlink" href="#xfce" title="Permanent link">&para;</a></h3> <p>桌面环境我选xfce。足够轻量体验也很好。vnc服务器我选tightvncserver,简单高效。</p> <div class="highlight"><pre><span></span># X环境,设置中文环境 …</pre></div><p>有些任务需要Linux桌面环境,例如使用chrome/firefox浏览器进行测试或抓取数据。简要记录安装过程备需。任何时候,一个免key的<span class="caps">SSH</span>登录环境都能带来方便。</p> <p>以下环境是Ubuntu18.04,&nbsp;Ubuntu其他版本大同小异。其他linux发行版需修改。</p> <h3 id="xfce">安装必须的xfce桌面基础包。还有语言支持包<a class="headerlink" href="#xfce" title="Permanent link">&para;</a></h3> <p>桌面环境我选xfce。足够轻量体验也很好。vnc服务器我选tightvncserver,简单高效。</p> <div class="highlight"><pre><span></span># X环境,设置中文环境 sudo apt install xfdesktop4 tightvncserver xfce4-terminal xfce4-panel ttf-wqy-zenhei ttf-wqy-microhei language-pack-zh-hans-base language-pack-zh-hans </pre></div> <h3 id="_1">设置桌面显示中文<a class="headerlink" href="#_1" title="Permanent link">&para;</a></h3> <p>英语普通4级的我,桌面环境还是用母语熟悉。</p> <div class="highlight"><pre><span></span># 设置中文环境 sudo dpkg-reconfigure locales # 时区 sudo dpkg-reconfigure tzdata </pre></div> <h3 id="vncxstartup">初始化vnc,设置密码和xstartup环境<a class="headerlink" href="#vncxstartup" title="Permanent link">&para;</a></h3> <p>完成后相关配置文件都在$<span class="caps">HOME</span>/.vnc文件夹内,复制文件夹设置权限归属即可,不须重新配置。</p> <h4 id="vnc">初始一个默认.vnc文件夹<a class="headerlink" href="#vnc" title="Permanent link">&para;</a></h4> <div class="highlight"><pre><span></span>vncserver -localhost :1 # 开启1号,只监听在127.0.0.1本地lo网卡 # 监听0.0.0.0可用 vncserver :1 vncserver -kill :1 # 关闭1号 </pre></div> <h4 id="vncxstartupvnc">修改~/.vnc/xstartup,登录vnc后的启动桌面命令<a class="headerlink" href="#vncxstartupvnc" title="Permanent link">&para;</a></h4> <p>文件最后一句内容</p> <div class="highlight"><pre><span></span>startxfce4 &amp; </pre></div> <h4 id="vncpasswdvnc">使用vncpasswd命令设置vnc密码<a class="headerlink" href="#vncpasswdvnc" title="Permanent link">&para;</a></h4> <div class="highlight"><pre><span></span>vncpasswd </pre></div> <h3 id="vnc_1">vnc启动与安全<a class="headerlink" href="#vnc_1" title="Permanent link">&para;</a></h3> <p>参考上面即可。如监听localhost地址,可用ssh本地转发功能建立ssh隧道再进行连接。</p> <div class="highlight"><pre><span></span>ssh -gfTNL 5901:localhost:5901 host # vnc的1号端口对应5901, 2、3等端口对应递增。 </pre></div> <h3 id="vnc_2">vnc服务要开机启动<a class="headerlink" href="#vnc_2" title="Permanent link">&para;</a></h3> <p>因版本不同差别较大,需要配置较多,vnc服务不是常用,不需开机自启。</p> <h2 id="_2">参考<a class="headerlink" href="#_2" title="Permanent link">&para;</a></h2> <p>How to Install and Configure <span class="caps">VNC</span> on Ubuntu <a href="https://www.digitalocean.com/community/tutorials/how-to-install-and-configure-vnc-on-ubuntu-16-04">https://www.digitalocean.com/community/tutorials/how-to-install-and-configure-vnc-on-ubuntu-16-04</a></p> <p>How to install <span class="caps">VNC</span> on Linux ( <span class="caps">GUI</span> for your Linux <span class="caps">VPS</span> ) <a href="https://www.interserver.net/tips/kb/install-vnc-linux-gui-linux-vps/">https://www.interserver.net/tips/kb/install-vnc-linux-gui-linux-vps/</a></p>