duangsuse::Echo
708 subscribers
4.23K photos
127 videos
583 files
6.43K links
import this:
美而不丑、明而不暗、短而不凡、长而不乱,扁平不宽,读而后码,行之天下,勿托地上天国。
异常勿吞,难过勿过,叹一真理。效率是很重要,盲目最是低效。
简明是可靠的先验,不是可靠的祭品。
知其变,守其恒,为天下式;穷其变,知不穷,得地上势。知变守恒却穷变知新,我认真理,我不认真。

技术相干订阅~
另外有 throws 闲杂频道 @dsuset
转载频道 @dsusep
极小可能会有批评zf的消息 如有不适可退出
suse小站(面向运气编程): https://WOJS.org/#/
Download Telegram
...服了,用这样脏的修改也会有这样的结果……
做到七点半,就不修了睡大觉。 这个问题是蛮特殊的,在构造器调用里出现,恰巧我没有为赋值的情况考虑。 何况 codegen 本来就是为视图树的后序遍历情况考虑的,根本没想某些构造器还有创建窗口副作用…… 不过我突然想到一个 workaround 估计还可以
真无语了,吃饭去
This media is not supported in your browser
VIEW IN TELEGRAM
马上 TkGUI 就要进入 PyPI 了,真棒。可我一点也不开心。
真的不知道这样瘸腿的设计如何做到正确codegen…… 一般来说是有个区域限制的吧,比如某个 window 内codegen就只能访问它的上下文,所以不用处理命名冲突,但我对这个奇葩代码生成方法理解的本来就不深刻,只是想拿它简化代码而已…… (而且我真是不想加任何限制虽然原理的编程建模本身有功能限制)
真不知道这个框架什么时候会变成 Python 里最好的,感觉可以拼一下?喵。

https://github.com/duangsuse-valid-projects/TkGUI
今天终于可以早点睡了……(而且以后几天都不会有出产,真可惜)
下面来列举一些 Python 的 GUI 工具/框架,从 PyPI 找的

https://github.com/alejandroautalan/pygubu
Pygubu is a RAD tool to enable quick and easy development of user interfaces for the Python's tkinter module inspired by Glade. (UI Designer)

https://pypi.org/project/sgui/
A simple GUI library for Python, wrapper around Tkinter In the future, backends for other languages like [pyside2](http://wiki.qt.io/Qt_for_Python) may be added.
mainBox = sgui.VBox(window)
sgui.Label(mainBox, string = "Text")

(我也一样!反正我是真想加GTK的后端,因为它好看啊,但不好写...)

https://pypi.org/project/ttkwidgets/
A collection of widgets for Tkinter’s ttk extensions by various authors (updated)

https://pypi.org/project/uielem/
wrapper over Tkinter for more Pythonic UI building
uiroot = UI(Tk, name='root', title='Kanban', children=[UI(Button, text='Add item', command=add)])
uiroot.makeelem()
uidict["root"].mainloop()

不太好看,不过我估计这个作者纯元编程封装很省力。(还好咱加了代码生成后也元编程了,而且还0抽象开销+代码生成本身无需重复代码,动态类型才叫Pythonic。嘿嘿)

https://pypi.org/project/tkintertoy/
Tkintertoy was designed to be a easy to use GUI library based on Tkinter. It was intended for "young"
gui = Window()
gui.setTitle('My First Tkintertoy GUI!')
gui.addEntry('name', 'Type in your name')
gui.plot('name', row=0)

这个虽好但不喜欢,如果光说。 看后面有个严重减分项:
while True:
gui.waitforUser()
if gui.content: gui.set('welcome', 'Welcome ' + gui.get('name'))

如果从视图定义方式来看,类似 ImGui :
https://pypi.org/project/dearpygui/
add_text("Hello world")
add_button("Save", callback="save_callback")

https://github.com/dholm/simpleguitk/
http://www.codeskulptor.org/

SimpleGUITk is a wrapper for the CodeSkulptor SimpleGUI API using TkInter

frame = simplegui.create_frame("Home", 300, 200)
frame.add_button("Click me", click)
frame.set_draw_handler(draw)

支持浏览器环境和 paint 事件,加分!

https://github.com/TaylorSMarks/FinGUI

A Pythonic Wrapper for Tkinter
from fingui import Entry
e = Entry()
e.set('Hello World!') # no need to call mainloop

感觉对全局环境和 mutate(set) 方法的依赖太严重,不作评价

https://bitbucket.org/svenrahmann/geniegui/src/master/geniegui.py
Python GUI generator. Automatically generate tkinter GUI applicatons from argparse objects.
有意思。但没有实例和截图的项目别人是不会看的。

https://pypi.org/project/tkup/
tkup is a thin wrapper around standard Tkinter widgets, allowing you to write code that visually reflects the widget hierarchy, helps you use normal Tkinter in a streamlined way.

这个开发者的思想和我一样都是定义式,但他选的方式我不太喜欢,毕竟 vararg 是几乎什么语言都有的,但 with (类似try-with-resource但有__enter__事件) 可不是哪都能移植,而且它还必须用副作用构造控件树

https://github.com/Mandera/generalgui
Extends and simplifies tkinter functionality with built-in QoL improvements.
是基于 App, Page, Element 的 Tkinter 封装,它重命名了一些控件并且简化封装grid等,不是所有控件都支持。

https://github.com/duangsuse-valid-projects/TkGUI
Declarative tkinter wrapper for Python, features quick prototype and (dynamic type, "implicit") codegen.

我最喜欢的当然是自己造的了…… 以后codegen完善了就能缓存结果降低开销(zero cost abstraction! 虽然是Python...),而且支持更多 GUI 框架后可以跨语言代码生成, 虽然估计不会再动codegen部分

https://github.com/Akuli/teek
Teek is a pythonic and user-friendly alternative to tkinter

Teek 是把 tkinter 整个重写了一遍,而且从 event loop 支持了视图的异步变动, TkGUI 从里面抄了不少东西,不过没抄不区分 Tk main 和 Toplevel 窗口的,之前我觉得没必要不区分(所以只能从 main 窗口 quit 什么的...),以后如果重写我会接受平等窗口的概念 (不像 Tk 到处 master slave ,呵呵)

https://uiutil.readthedocs.io/en/latest/summary.html dead?
duangsuse::Echo
真无语了,吃饭去
昨天晚上想了一下,发现其实只是一个小地方早就有bug,现在暴露出来了而已。 #Python #gui #cs
完成后我会进一步拆分出 ui/widgets/utils 模块以方便未来的 GTK 支持 ,还会加入 grid(row(a, b, c) ) 控件。(如果以后能加入 Glade/PyGUBU XML 的 compiler 就更好了,但纯DSL也不错)

因为 Tk 的 Frame 没法 scroll 而无法选择用类似DOM的appendChild替换ListView ,因为不想写 "Adapter" 什么的所以讨厌类似 Model/View 的设计模式(当然Qt的MV也是很巧妙的,兼顾了 index+delegate) ,想了一会用受管的 "View" 也不一定难看: ListView<String> { Text(it) } 这样不就是定义式且和 DOM 的 ul/div 一样容易了么... 而且一样可以用 DSL 风格批量创建初始项 (不愧是最赞的 Kotlin ,写什么都好看,设计哲学甩 Ruby 半条街 Python 两条街 ❤️) (老实说 Python 创造时也是蛮有抱负的,还有现在被菜鸟挤爆的"Pythonic": import this ,当然它火所以质量下降也不能怪它,可是到现在我真的欣赏的也只因为它是唯一支持 layout 缩进语义的工业语言,我觉得好语言不应该可以表达出烂代码///)

不过,其实我并不喜欢 Python (而且 Py 支持的 vararg kwargs 现在 Ruby 也支持了) , 虽然它写的代码简洁无需 enddel [:] global nonlocal 之类的东西太难看了,有些简化命名我也不太欣赏,面向对象模型也和 JS 的一样迷
但这次利用在 Py 里无重复为定义式框架实现 codegen ,和多backend 但无需自有抽象的 (embed.)DSL 也的确让我看到了动态类型的一些好处,如果你只想省时间的话

其实编译期和运行期也不是相互孤立的,在动态语言里,从解释实现的角度他们很可能混在一起无法区分;
但如果你的程序有代码生成的特性,就会发现如果把编译期和运行期结合在一起,很多看起来在"编译期"无法得出的数据(比如 flatten 一个嵌套结构),其实都是可以"静态"拿到的,因为编译期就是代码生成程序的运行期,而编译期和运行期区分的本质在于对数据的依赖(例如无副作用的函数有常量参数就可以编译期计算;或属 input() 的运行期数据),而并非"它是不是常量"(见C++ constexpr) (但C++弄得太麻烦)。

这一点有不少框架都用到了。比如几乎被历史抛弃的 Butterknife... 其实就可以用 annotation processor 和 syntax tree 的 reflect 做到动态生成绑定 inner class ,但它们做的都不如这次写的 Python 隐式 codegen 明显,咱只是把 call/callNew/invoke 和 setAttr/setItem 操作给替换一下就实现了全框架定义式转表述式、降低抽象开销的目的。(因为 Python 本身就没有编译期无需分割出codegen代码用Visitor访问语法树 而只用最小化的"给某被引一个名字"从而"完美兼容constexpr式计算"而已,顺便: Codegen 类本身也是可复用的,虽然我对这一点抱疑。)

有的时候代码生成这种扩展特性不是必须的,但实现它们也有利于对框架功能的理解(虽然我懒得标注类型...顺便:其实我觉得 string:String 完全应该用 :String 替换的,讨厌余赘表达,emm),正如我在写 ParserKt 的时候除了必要的 read 还配对定义了 show 操作一样。(这在 Kotlin lib 里真不常见,因为它是"函数式语言的专利",但我觉得关键在于定义式的高层建模思想,不强求写出实现法 可读性、可扩展性都会更好)
草,所以这个到底是什么鬼,花了我40分钟调试 因为不知道为什么结果不和我预期的一致,后来才发现是有个赋值…… 应该说这些赋值真是麻烦
This media is not supported in your browser
VIEW IN TELEGRAM
目前 codegen 已经完全 works 了,也修复了一些其它的小bug ,现在准备做 code cache 和跑分
https://github.com/Experimenter/py-gtk3-codegen/blob/master/py-gtk3-codegen.py #Python #GTK
这是一个 Python GObjects 的事件模板自动代码生成(它还支持嵌套,不过咱的 codegen 加个 _indent 变量然后用递归栈改写它就也实现嵌套了)
它只支持特定的 tags: ,用的当然是 [ for in if ] 生成式啦(啊好怀念Haskell里的写法
['GtkEntry','GtkTextView','GtkComboBox','GtkComboBoxEntry','GtkProgressBar',\
'GtkCheckbox','GtkRadioButton','GtkSpinButton','GtkCalendar','GtkToolBar',\
'GtkStatusbar','GtkFileChooserButton','GtkFontButton','GtkHScale','GtkVScale','GtkTreeView']]


input,text,comboBox,scrollBar+progressBar,checkBox,radioButton(理论应该只有radioButtonBox),spinBox,scale,treeView 和 askOpen/askSave 咱都是有的
calendar,ToolBar,StatusBar,fontButton 咱没有,毕竟 Tk 的控件系统现在已经不标准了(坏家伙)
话说 Python 的解析器感觉好难写啊,要处理的 layout 情况那么多... 要支持"\"消换行,括号还能带开启新缩进的 #ce
https://github.com/BlackHC/implicit_lambda 刚才,好像是第二次遇到类似的实现。

这个其实很简单嘛:
class ImplicitLambda:
def __init__(self, code): self.code = code
def wrap(self, code): return ImplicitLambda(code)
def _op(self, op, x): return self.wrap(self.code+op+repr(x))
def __add__(self, x): return self._op("+", x)
def __call__(self, value): return eval(self.code)(value)
_ = ImplicitLambda("lambda x: x")

list(map(_+1, [1,2,3])) #[2, 3, 4]

还是因为我不会用 Python 元编程(那需要理解它那和 JavaScript 一样混乱的面向对象模型,不像 Ruby define_method 和hooks那么简单),不然元方法可以立刻定义
当然如果用解释器模式一层一层剥开树形结构也可以做(但我觉得对这个 DSL 性能其实不重要

之前设计绝句编程语言的时候(别喷我和王垠一样谈自己没实现过的编程语言,它仅作为设计也是真正有价值的),我也考虑过添加类似 Haskell 的 sectioning: map (+1) [1,2,3] 这种:
建行(1、2、3)去映为「+1」 ,这被称为中缀链。可后来我把它换成 局限于中缀表达式/无参访问或中后缀算符引用的 block 了 ( 此行去映为「它+1」 ) ,不会像 Haskell 一样把隐式参数「它」省略掉,我超喜欢这种人类可读的设计的。哈哈。
duangsuse::Echo
目前 codegen 已经完全 works 了,也修复了一些其它的小bug ,现在准备做 code cache 和跑分
🤔 说起来, #Python 的开发者们也真是怪纯的,不喜欢用这些杂七杂八的小技巧。
我到 GitHub 搜 "Python codegen"&lang=python ,得到的七页结果没一个是生成 Python 代码的,要么是模板系统:
https://github.com/mattduan/codegen
https://github.com/AlexFinder/CodeGen
要么是特定的模板化代码生成器:
https://github.com/siggame/Creer

看起来好像大家并不知道 Python 的动态类型可以结合上代码生成,被用来替换语言内建的调用和成员访问语法(callNew,invoke,getAttr),从而在实现原有语义的同时做到生成代码以内联铺平内部式DSL,做到零开销抽象一样。

还有数个 Swagger REST API defs file 的生成实现…… 对了,其实我觉得 Swagger 也太纯真了,都没有受到函数式大佬们的污染,因为它"优化"后也只是支持 YAML 的缩进来"简写"深层嵌套结构而已。
我之前写过类似 Swagger 的玩意,它用的 DSL 完全不需要你写出每个参数的 - name:"WTF" - type: xxx,与之相比 Swagger 那 YAML 语法简直就像所有调用参数都要求 kwarg 的 Python 一样冗长……

其实我很好奇为什么 Swagger 有那么多语言的 codegen 实现、有那么多人实现这些实现,却没有一个人想着怎么优化它的“源语言”并提交给Swagger社区呢?(猜过分点,还是有人设计了但太烂所有没采用呢emmm)

其实这个算法并不复杂,甚至不一定可以被称为「算法」(我一直相信是因为自己智商欠缺才要那么多时间才弄好的),那么为什么没有其他工程派人士弄出一样的东西来呢? 😟
我想可能是因为那些程序员平时不使用定义式风格,所以他们不会想办法进一步设计更广阔,以至于跨语言、跨底层框架的代码复用;如果有,那就是人太少了,或者没人同时了解一些编译原理入门(相对更专业的常量折叠/回填而言)习惯。

我真的是个定义式编程迷,我设计过的所有复用库都不包含复杂的逻辑/数字/几何/数据结构/树图算法(尽管我做梦都想),但它们通通具有定义式的编程 API — 多数是用 vararg 尽可能在构造时就完成配置而不用如 .addXXX 的变更调用。尽管我一点也不愿意写 Haskell 和 Scala / Scheme(respect for its s-expr.) 等格调品味超高的(纯)函数式编程语言,函数式对我的影响我没照本宣科的接受,逼自己思考它们眼中的问题或是尝试实现它们那令人困惑的命名/建模方法。当然我知道放弃不值得炫耀,但这使我找到了不同于函数式但比函数式更易读、易维护的接口建模风格,就是 Kotlin 的风格和设计哲学,用于解决问题的东西就应该在平衡下解决尽可能多的问题、并且从不会制造其它问题。 #statement #design

当然如果你写代码只是为了弄出一个 "working" 的东西,或者觉得因为自己足够聪明所以 “重构甚至重写是码农做的事”、 “调试是愚蠢的”、 “把自己所知道的明确举例讲明白是为蠢人费力的无聊事” ,那就想不到你所想不到但的确可以实现的东西了。
This media is not supported in your browser
VIEW IN TELEGRAM
在修复了 TreeWidget.TreeItem 的 id 问题后(但它的tuple第一项就只限str了 和用UUID的效果差别大),终于又完成对 Scale(slider) 的 TTk interval 支持移植(原版不支持的特性) ,我添加了一个简单的roundInterval查找算法解决这个库里的显示不准确问题,但目前还没能完成纵向的渲染(有一部分原因是它的代码质量太差了!水平线以下!害得我没时间写 code object cache)
This media is not supported in your browser
VIEW IN TELEGRAM
虽然我写得很累,但我觉得应该改正下自己的坏脾气。 别人的代码即便不好,也是可以帮忙更改的。 虽然混乱的代码给我造成了麻烦,但他们设计逻辑也是很累的,代码质量不好不能全怪他们,也怪环境不好。