阅读视图

发现新文章,点击刷新页面。
🔲 ☆

我用 AI 造新語

我想,应该有很多人和我一样,都尝试过让 AI 来创建一门新语言吧。今天来分享一下我和 AI 深度对话后的产物——Nusila。你可以把它当作无聊时的戏作,亦可以用这门语言来创作自己的科幻小说。

起因是我给 AI 投喂了这样一个设定:

假设人类殖民外星,这个外星上的人类打算独立,他们想要统一用同一门语言,但是各个民族都支持用自己民族的语言,大家没有谈拢,于是他们打算设计一门新语言来解决争端。这门语言应该没有各种语言的历史包袱,它应该是现代的、成年人易学的、无发音特权阶层的语言。同时考虑到各民族的情感,借词时可以考虑从各种语言里面参考一下。

经过多轮逻辑审计和“语言宪法”的约束,我们最终确定了一套逻辑严密、类似编程代码的粘着语架构。

这个语言名字也是 AI 命名的,根据构词法来理解,Nu- 是新的意思,-sila 是语言,所以 Nusila 的意思就是新语言。


一、 语言宪法:新世界共识架构

《Nusila 简明宪法》不仅是语法书,更是这个虚构社会的“底层协议”。

立宪宣言:在 Nusila 中,没有含糊其辞,没有阶级枷锁。每一个音节都是为了让思想更自由地在星际间传递。

第一章:核心哲学

  • 中立性:Nusila 旨在消除历史包袱,不偏袒任何地球母语。
  • 易学权:成年人必须能在 3 个月内掌握交流,逻辑性永远优于习惯性

第二章:语音铁律

  • 极简音位:全语仅限 11 个辅音 (p, t, k, m, n, s, f, h, l, w, y) 与 5 个元音 (a, e, i, o, u)。
  • 辅元(CV)结构:每个音节必须是“一辅一元”(如 Mi, Sa)。严禁辅音堆叠,严禁以辅音收尾,词根内部也必须严格遵守 CV-CV。
  • 一符一音:拼写与发音绝对 100% 对应。

第三章:语法逻辑

  • 零例外原则:100% 规则化,不存在任何“不规则变位”。
  • 词性激活接口:词根必须通过后缀 -a (名), -i (动), -o (形) 激活。
  • 双元音防火墙:第一个出现的双元音(如 ai, oi)是词根与语法的分界线,实现流式解析。

第四章:词汇与平权

  • 绝对平权:取消性别、阶级代词。
  • 生物/技术界限:代词强制区分生物智能 Lo (或 Lona) 与机器智能 Ma (或 Loma),确保生存指令安全。
  • 群体边界:区分包含式“咱们”(Miyu) 与排除式“我们”(Milo)。

第五章:多模态输出

Nusila 天生支持四种接口:拉丁接口(速记)、音节方块(几何视觉文字)、线性特征码(二进制流)和战术手势(真空/无声通讯)。


二、 语言细节:积木式构词

词根与后缀

Nusila 的词根是静态的,必须通过接口“激活”:

  • -a:名词化标记 -> Mita-a (眼睛/视线)
  • -i:动词化标记 -> Mita-i (看)
  • -o:形容词化标记 -> Mita-o (视觉的)
  • -u:副词化标记 -> Mita-u (视觉上地)

动词详解

Nusila 的动词后缀挂载顺序严格固定,像函数调用一样精准:

[词根] + [接口 -i] + [语态] + [体] + [语气] + [时态]

功能分类 后缀 (CV) 含义
语态 Voice -lo / -ki / -ye 被动 / 使动 / 相互(自复)
体 Aspect -sa / -se 完成 (■) / 进行 (≈)
语气 Mood -pi / -mu / -ka 可能 (?) / 想要 (♥) / 必须 (!)
时态 Tense -pa / -nu / -fi 过去 («) / 现在 (·) / 将来 (»)

极限压力测试:

Mitailoyekapinu:意为“(咱们)可能不得不被迫互相观察了”。

Mita (看) - i (动) - lo (被) - ye (互相) - ka (必须) - pi (可能) - nu (现在)


三、 句法:核心信息优先

定语后置

名词永远在前,形容词在后(如:Wafaa samao,水 洁净的)。

  • 抗噪性:在极端环境下,先听到“水”比先听到“洁净的”更能让大脑快速定位。
  • 流式处理:大脑不需要缓存形容词,读到哪,理解到哪。

状语的前置与后置

副词接口 -u 的位置决定了语义侧重:

  • 前置(动词前):强调动作的方式或性质Mi fusu-u sapai-nu (我快速地宣告)。
  • 后置(句尾):强调动作的结果或程度Mi sapai-nu fusu-u (我宣告得很快)。

逻辑连接词 (H-族)

为了避免和语法后缀冲突,逻辑词统一由 H 开头:

  • Ha(和), He(但), Ho(因), Hu(或), Hi(若)。
  • Te / Tu:逻辑括号。用 Te 开启从句,Tu 关闭,彻底解决长句嵌套歧义。

四、 数字与疑问系统

数字系统 (0-9)

单音节设计,兼顾全球权重与抗噪辨识度:

Ne(0), Mo(1), Wo(2), Ta(3), Fo(4), Wu(5), Lu(6), Si(7), Ti(8), Ku(9)。

疑问体系 (Wa- 通配符)

采用“通配符原位原则”,不改变语序:

  • Wapona (谁 = 疑问+人)
  • Wamota (什么 = 疑问+物)
  • Wanuta (何时 = 疑问+时间)
  • We (是否 = 句首是非问助词)

五、 AI 沟通时产生的词汇

类别 成员
代词 Mi (我), Yu (你), Lo (人), Ma (机)
逻辑 Ha (和), He (但), Ho (因), Hi (若), Ke/So (所以/那么)
词根 Pona (人), Mosa (机), Sila (语), Nuta (时)
词根 Wafa (水), Foha (能), Loka (位), Lifa (自), Nufa (独), Falo (错)

结语:Yu Faloinu!

事实上,在 AI 设计语言的过程中,他自己经常不遵守我们定下的宪法,总是要我提醒他。对于 AI 犯错,我们在 Nusila 中就可以说:Yu Faloinu。Yu 是指你,falo 是词根错误,i 表示动词,nu 表示正在进行,合起来就是你正在犯错。

独立宣言

Milo sapai-nu Nufaa 我们宣告独立


后续如果我还有兴趣的话,可能需要建立一个 GitHub 仓库来记录了。

🔲 ☆

丟失的表達欲

錢鍾書說我們常把自己的寫作衝動誤認為自己的寫作才能,我倒以為這很好,因為我自己連寫作的衝動都沒有了。不談寫作,只是隨便說點什麼亦鮮矣。博客有兩年沒有更新了,社交網絡經常好幾個月一言不發,也不怎麼與人聊天,越發自閉了。

這當然很不好。可是究竟要說點什麼呢,又感覺沒什麼好說的。我也試過寫點週記,談談一週見聞或所做之事,卻往往不見下一週。大抵因為下一週乏善可陳,於是不了了之。不然嘗試寫一下月記?

細細思索,這兩年是不是沒做什麼事呢?

不然。

  • 在開源項目上,我將 Authlib 的 JOSE 功能拆分出來生成了 joserfc 這個庫,斷斷續續已經發佈到了 1.2.2 版本。
  • 設計了一個 Sphinx 的主題 Shibuya,上面的 joserfc 的文檔就是用的這個主題。
  • Typlog 在重新設計 V4,目前自測中。

以前,我還會寫文章介紹一下我的項目。現在這些項目我竟沒有去介紹一下,想想真是不應該。

除了介紹自己的項目,還能寫點什麼呢?近來有什麼所思所想,又有什麼洞見或者觀察?似乎沒有。這大約就是所謂的咸魚人生吧。意識到了,似乎就應該翻一下身,來曬曬另一面。

🔲 ☆

個人域名郵箱免費方案

Cloudflare Email Routing 這項服務推出來有一段時間了。今日,我將個人郵箱 (me@lepture.com) 從 Google Workspace 轉到了 Cloudflare Email Routing,每月節省了 6 美金。

我們知道 Cloudflare Email Routing 可以接收郵件然後轉發到你指定的另一個郵箱,但是並不能發送郵件。這樣的話,我們就不能使用自己的個人域名郵箱了。所以要搭配一個方案,讓我們可以用自己的域名發郵件。所以我另外註冊了一個 Gmail 來發郵件。

下面是我遷移的整個流程:

備份郵件

首先我們需要備份個人域名郵箱里的郵件,如果你沒有什麼重要的郵件的話,也可以不備份。不過最好還是備份一下。這裡我選擇將郵件導入到我新註冊的 Gmail 里。如果你已經有一個 @gmail.com 的郵箱了,這一步可以省略。不過我還是註冊了一個全新的 Gmail,這樣比較清爽。

進入 Gmail 的設置裡面,選擇 Accounts and Import,在下面可以找到 Check mail from other accounts,點擊 Add a mail account。在彈出的對話框里輸入自己的郵箱,按照引導會進入填寫 POP 服務的頁面。

Sync emails
Add mail account

按照官方文檔,你需要填寫的信息:

  • 用戶名:你的郵箱
  • 密碼:你的郵箱密碼
  • POP 服務器:pop.gmail.com
  • 端口:995
  • 要求 SSL:是

Important

你也許無法成功添加郵箱賬戶。這裡可能會出現錯誤提示:

Server denied POP3 access for the given username and password.

我們需要先開啓個人域名郵箱(Google Workspace Gmail)里的 POP3 功能。到你的個人郵箱設置里,選擇 Forwarding and POP/IMAP,然後開啓 POP 服務。

Enable POP

但是可能還是無法成功,這是因為 Gmail 的安全機制導致的。雖然官方文檔里說密碼使用郵箱的登錄密碼就可以了,但其實不行。這裡有兩個解決方案:

  1. 使用 App password
  2. 修改賬戶安全等級

在下面的章節里會介紹如何創建 App password,這裡先介紹一下修改賬戶安全等級。因為我們這個 Google workspace 賬戶最終是要銷戶的,所以修改賬戶安全等級並沒有什麼影響。進入賬戶安全中心,激活 Less secure app access 即可。

Less secure app access

再次嘗試添加 POP 郵箱賬戶,應該就會成功了。你需要等待一段時間才能備份完所有郵件。也許睡一覺,明天再繼續?

開啓 Cloudflare Email Routing

當郵件備份完後就可以開啓 Cloudflare Email Routing 了。進入 Cloudflare,選擇你的域名,進入 Email Routing 設置。

Email Routing

比如你註冊的 Gmail 叫 example@gmail.com,你的個人域名郵箱是 me@example.com,上面的表單可以填寫:

  • Custom address: me
  • Destination: example@gmail.com

然後根據 Cloudflare 的提示,三步後就可以開啓 Cloudflare Email Routing 了。現在,當別人發郵件給 me@example.com 時,你的 example@gmail.com 郵箱就會收到郵件了。

個人域名發件人

最後我們需要讓發件人使用我們自己的域名。這一步與上面的備件郵件有些類似。進入 Gmail 的設置中心,選擇 Accounts and Import。在 Send mail as 里選擇添加一個新郵箱。

Send mail as

比如我添加自己的郵箱 me@lepture.com,根據提示一步一步走,會進入最後的 SMTP 服務器設置:

使用 AWS SES

Warning

如果你還沒有開通 AWS SES,建議試試其他 SMTP,比如 Alibaba Direct Mail。因為 AWS SES 默認為 sandbox 環境,需要申請才能開通生產環境,但是有可能申請不通過。

之前介紹的 Gmail SMTP 方案(在文章最下面)沒有 DKIM 驗證,會導致郵件進入垃圾箱。我們可以使用其他的 SMTP 服務來發送郵件。比如 AWS SES,因爲 SES 會提供每個月 3000 封免費郵件,這對於個人用戶來説絕對夠用了。

首先你需要注冊一個 AWS 賬戶,這裏就不介紹了。注冊後,到 SES Dashboard 裏面添加自己的域名,比如我的:

SES

下一步,設置 DNS,讓 SES 支持 DKIM 認證。你將需要設置類似如下的 CNAME。注意,在 Cloudflare 裏面設置 CNAME 時要關閉 Proxy

Setup DNS

接下來,我們為這個域名創建一個 SMTP 登錄賬戶:

Create SMTP credentials

只需要一步一步跟著 AWS 的步驟來,你就能創建出 SMTP 登錄賬戶和密碼。之後,再將這個 SMTP 賬戶登記到 Gmail 裏面就可以了。

Add AWS SES SMTP credentials

我們需要設置:

  1. SMTP Server: email-smtp.us-west-2.amazonaws.com
  2. Port: 465
  3. Username:AWS SMTP Username
  4. Password:AWS SMTP Password

完成後,可以在設置頁面里將個人域名郵箱設置為默認發件人。

另外,你還可以設置一下 MAIL FROM 域名,如果沒有設置的話,收件人會看到你發的郵件 mailed-by: us-west-2.amazonses.com

MAIL FROM

使用其他 SMTP

除了 AWS SES,還有其他 SMTP 服務選擇。比如 SendGrid,比如 Alibaba Direct Mail。

  • SendGrid 提供每天 100 封免費郵件。
  • Alibaba Direct Mail 每個阿里雲主帳戶每日可獲 200 封免費郵件發送額度。

測試

最後,我們使用自己的域名郵箱發送一封郵件試試。下面是我收到的測試郵件示例:

Received email

可以看到,SPF、DKIM 都成功了。


下面是使用 Gmail SMTP 的方案,請謹慎使用。

Warning

這個方案有缺陷,沒有 DKIM 認證,只能保證 SPF pass。

這裏我們可以直接使用當前的 Gmail 賬戶,比如 example@gmail.com

smtp.png

我們需要設置:

  1. SMTP Server: smtp.gmail.com
  2. Port: 587
  3. Username:你的 Gmail 郵箱(就是你當前在用的這個郵箱)
  4. Password:等一下,這裡需要創建一個 App password

在上面的最後一步需要填寫一個密碼,由於 Gmail 的安全機制,你不能直接填寫賬戶密碼,這裡需要使用一個 App password。

  1. 進入賬戶安全中心
  2. 激活兩步驗證(2-Step Verification):
2-Step Verification

激活後,進入 2-Step Verification,在頁面的最下面有一個 App passwords,進入後創建一個 Mail 的 App password 即可。

App passwords

然後在密碼填寫框里使用這個生成的密碼即可。完成後,可以在設置頁面里將個人域名郵箱設置為默認發件人。

🔲 ☆

Fireside 遷移記

上周「婊醬FM」打算遷移到 Typlog,他們之前使用 Fireside 托管,但是賬戶已經過期,RSS 不能訪問,又未能找到 Fireside 的導出功能。於是將賬戶密碼告知我,委託我來處理。我卻是不信 Fireside 沒有導出功能的,結果是真的找不到。

但是我卻發現了 Fireside 有一個 Hiatus Mode,可以用 $5 來托管播客,方便遷移:

Hiatus Mode

告知「婊醬FM」確實需要再續費一個月才能方便遷移到 Typlog,但是可以使用這個 Hiatus Mode 來減少費用。申請後,兩個工作日依舊沒有反應,再次申請,還是沒有反應。賬戶信用卡已更新,但是賬戶依舊是 Suspended 狀態。不知道 Fireside 是否沒有人在工作,無法激活賬戶。

這樣等下去也不是辦法。據說互聯網是有記憶的(當然大國只有 404),也許可以在其他地方找回數據。先到互聯網檔案館尋找,未能找到。

再搜索,找到一個叫 Listen Notes 的地方,似乎可以一用。頁面解析起來不太方便,但是這個網站是有 API 的,遂去申請,可惜需要填寫太多資料,還不知道 API 里是否有 Typlog 所需要的全部資料。便先放在一邊,再找找別的地方,實在不行再回來申請 API key。

最終從 Breaker 處獲取到了所有數據:

Breaker
Breaker Network

將數據從 Network 里複製出來,剩下的便很簡單了,寫上幾行 Python 腳本,將數據整理成 Typlog 需要的格式導入到 Typlog 里便可以了。Fireside 那裡,即使賬戶已經過期,只要知道音頻文件的地址,音頻文件依然是可以訪問的,所以還是可以將音頻文件抓取到 Typlog 的存儲里。

這裡不得不說,Typlog 還是做得不錯的。從一開始就做了導出功能,即使賬戶過期了,網站不可訪問,導出功能依舊可用。

🔲 ☆

談談獨立播客

昨天發佈了一個中文獨立播客的項目,在 Twitter 上說了一句,不曾想應者雲集。愚頗為惶恐,怕是要解釋一番了,談一談什麼是獨立播客

我原先便有做一個播客列表的想法,不過是推薦一下使用 Typlog 的播客用戶,順便給 Typlog 做點宣傳。然而二零一九年春夏之交國內播客的異動打斷了我的方案,與其只推薦 Typlog 上的播客,何如推薦中文獨立播客。

愚聽播客並不算多,初始不過列舉三四個,幸得眾人共襄,今已數十者矣。好壞暫且不論,至少都滿足了「獨立域名」這一條件,當是時所立之唯一准則。此番定義怕是很難讓人信服,然而「這可以算是獨立播客的一個不完美但有效的定義」。

Jesse Chan 言

獨立 = 創作過程不受限制、影響。

這是要從內容本身出發去判斷的,真正「獨立」的內容會散髮出獨一無二的氣質。

愚非賢者,不敢斷言何為真正獨立的內容,亦不可能聽遍所有節目。這裡取「獨立域名」一條皆因中國播客審查之過,假使播客並沒有自己的域名,而是使用喜馬拉雅、荔枝等,其便不至於被蘋果除名,因為這些國內平台已經幫忙審查過了。

當前情形,愚不可能去評判播客內容之優劣。止以域名論之,何也?假使播客 RSS 地址不能自己控制,全仰仗平台,平台說刪就刪,何談獨立?而有了自己的域名,即使使用別人提供的服務,想移走時便可以移走,可對 RSS 地址做重定向。至少在這一點上算得獨立了。

針對蘋果國內播客政策,我以為有如下解決方案:

  1. 保留現有獨立域名的 RSS 作為國際版播客,同時提供一個喜馬拉雅或荔枝等 RSS 作為特色社會主義版。
  2. 加倍鼓勵用户使用泛用型播客客戶端,如 Castro、Pocket Casts、 Overcast 等。
🔲 ☆

PyCon JP 2018 記

PyCon Japan 2018 剛剛結束。會議場地位於大田區,離我住處偏遠,於押上轉一趟車全程大抵一時半,倒不是怨言,整體感受挺不錯的。這次亦有在 PyCon 做一點分享,話題為 The Modern OAuth 2.0,正是最近在寫的《摩登 OAuth 2.0》系列。

分享

我自己偏愛概念類的分享,以傳播為主,這次的分享亦是順帶推廣自己的項目 Authlib。下面的視頻大抵從 15:00 開始,英語口語不好講話不太流利(國語口語也不好),但是還算講清楚了。

The modern OAuth 2.0

另外 slide 可見 SpeakerDeck

體驗

這次參加 PyCon JP 算是偶然,來日本第三年了才第一次參加。報名後才發現原來講者亦要買票的,這卻是第一次聽說,查了一下,一般 PyCon 確實都要買票,但是可以申請補助。

中途並沒有人來聯繫,也沒有提前要 slide,所以一直拖到演講前一天才寫完。也正是這一天,PyCon 開始前的一天,主辦方終於有一個活動了,邀請了工作人員、贊助商、講者去晚餐。餐廳有點搞笑,將 PyCon 寫成了 TyCon——Welcome TyCon 樣。人很多,沒有自我介紹,就瞎聊,日語不太會,只能找人講講英語,我又不太會社交,有點尷尬。不過好歹還認識了幾人。

Welcome TyCon

這次 PyCon JP 規模很大,除了早上的 Keynote 沒有並行外(住太遠趕上不 keynote),下午場的演講都是 6 個場次並行的,參會者可以自行挑選。當然,我只能挑選英文場的去聽了,可選擇項就少了。

收穫

PyCon JP 這邊有蠻多台灣 PyCon 過來的志願者,有好些人差不多每個地方的 PyCon 都會去,還挺驚奇的。跟台灣的朋友聊了聊,畢竟講國語比較輕鬆,決定明年去台灣宣傳一下。

我自己的分享結束後,亦收到了幾張名片,可惜我自己沒有印名片。有一位大約是想找我做點什麼,不過好像名片弄丟了,沒辦法聯繫了。還有一位馬爾代夫來的先生邀請我去給他們團隊做一個短期的培訓,看名片上的網址還帶 gov 難道是政府人員?倒是可以考慮一下,順便去度個假,得找個空閒時間。

感想

日本這邊辦得比中國要好。首先是議題,什麼樣的都有,有適合初學者聽的,有適合中高級聽的,有公司的有社區的,比較多樣。中國的看起來都是架構師,感覺像是 Summit(峰會),而不是 Conference,話題太過厚重。PyCon 還是要多元一些,要有對初學者友好的話題。

另外一點,PyCon JP 和其他地方的聯繫比較多,比如 PyCon 台灣、印尼、新加坡等,國際化比較好。問了一下在場的人,大家都沒聽過 PyCon 中國,以為中國沒有。正巧我分享完後有北京 PyCon 的人聯繫我(我沒有時間去),幫他要了 PyCon 日本、台灣、印尼的主席們的聯繫方式,希望 PyCon 中國能走出來與其他地方多多聯繫。

預祝十月的 PyCon 中國順利。

🔲 ⭐

夜思

寫一首小詩送給你:

玉兔隱長夜,寒蟬聒青堤。
睹物思君意,憑欄空悲淒。
杯淺迷人眼,相見何遲遲。

🔲 ☆

Structure of a Flask Project

Flask itself is very flexible. It has no certain pattern for a project folder structure, which is very good for experienced developers to organize things in their own favors. However, people new to Flask will get confused, they need some guide on it, and usually they are going to find something works but not good (or even bad).

I didn't know such a problem until someone reported an issue to Authlib. And I can't understand the problem either. Then another person explained it to me with a project structure, I finally got it. I was terrified that lots of posts, guide, boilerplates are backward importing modules from project root __init__.py:

# project/__init__.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()

def create_app():
    app = Flask(__name__)
    db.init_app(app)

# project/auth/models.py
from .. import db

class User(db.Model):
    # define columns

The code itself will work, but when your projects grow, sooner or later you will face a cyclic dependencies problem. For instance, another extension requires to init with the User model:

# project/__init__.py
from flask_sqlalchemy import SQLAlchemy
from another_extension import AnotherExtension
from project.auth.models import User

db = SQLAlchemy()
ext = AnotherExtension(User)

Oops, a cyclic dependency occurs. Because auth.models is importing db from the root, root can not import User module. This is a common cyclic problem, not limited to Flask. It is easy to fix, but junior developers may find it very hard. So why not avoid such thing from the very begining? Actually, if you have read the official documentation, in application factories you can find this piece of code:

def create_app(config_filename):
    app = Flask(__name__)
    app.config.from_pyfile(config_filename)
    from yourapplication.model import db
    db.init_app(app)
    from yourapplication.views.admin import admin
    from yourapplication.views.frontend import frontend
    app.register_blueprint(admin)
    app.register_blueprint(frontend)
    return app

See, we put db in yourapplication.model.

I always keep this one certain rule when writing modules and packages:

Don't backward import from root __init__.py.

That's why I submitted a ticket to Flask as soon as I found this problem. People need a guide on folder structure. And here I'm going to share my suggestions. But think it yourself, don't treat mine as a golden rule.

Functional Based Structure

There are many ways to setup your project folder structure. One is by its function. For instance:

project/
  __init__.py
  models/
    __init__.py
    base.py
    users.py
    posts.py
    ...
  routes/
    __init__.py
    home.py
    account.py
    dashboard.py
    ...
  templates/
    base.html
    post.html
    ...
  services/
    __init__.py
    google.py
    mail.py
    ...

All things are grouped by its function. If it hehaves as a model, put it in models folder; if it behaves as a route, put it in routes folder. Build a create_app factory in project/__init__.py, and init_app of everything:

# project/__init__.py
from flask import Flask

def create_app()
    from . import models, routes, services
    app = Flask(__name__)
    models.init_app(app)
    routes.init_app(app)
    services.init_app(app)
    return app

Here is a trick by me. In official documentation, db of Flask-SQLAlchemy is registered in this way:

from project.models import db
db.init_app(app)

So my trick is define a init_app in every folder's __init__.py, and unify the init progress as one:

# project/models/__init__.py
from .base import db

def init_app(app):
    db.init_app(app)

# project/routes/__init__.py
from .users import user_bp
from .posts import posts_bp
# ...

def init_app(app):
    app.register_blueprint(user_bp)
    app.register_blueprint(posts_bp)    

# ...

App Based Structure

Another famous folder structure is app based structure, which means things are grouped bp application. For instance:

project/
  __init__.py
  db.py
  auth/
    __init__.py
    route.py
    models.py
    templates/
  blog/
    __init__.py
    route.py
    models.py
    templates/
...

Each folder is an application. This pattern is used by default in Django. It doesn't mean this pattern is better, you need to choose a folder structure depending on your project. And sometime, you will have to use a mixed pattern.

It is the same as above, we can init_app as:

# project/__init__.py
from flask import Flask

def create_app()
    from . import db, auth, blog
    app = Flask(__name__)
    db.init_app(app)
    auth.init_app(app)
    blog.init_app(app)
    return app

Configuration

Loading configuration would be another issue that many people find difficult, it is also a folder structure problem. I don't know how other people are doing, I'm just sharing my solution.

  1. Put a settings.py in project folder, treat it as static configuration.
  2. Load configration from environment variable.
  3. Update configration within create_app.

Here is a basic folder structure for configration:

conf/
  dev_config.py
  test_config.py
project/
  __init__.py
  settings.py
app.py

Define a create_app to load settings and environment variable:

# project/__init__.py
import os
from flask import Flask

def create_app(config=None)
    app = Flask(__name__)
    # load default configuration
    app.config.from_object('project.settings')
    # load environment configuration
    if 'FLASK_CONF' in os.environ:
        app.config.from_envvar('FLASK_CONF')
    # load app sepcified configuration
    if config is not None:
        if isinstance(config, dict):
            app.config.update(config)
        elif config.endswith('.py'):
            app.config.from_pyfile(config)
    return app

This FLASK_CONF is a python file path which contains configrations. It can be any name you want, e.g. your project is called Expanse, you can name it as EXPANSE_CONF.

I use this FLASK_CONF to load production configurations.


Again, Flask is very flexible, there is no certain patterns. You can always find your favors. These are just my suggestions, do not blind by anyone.

I don't like to write posts like this. But there are so many wrong guide, I hope this post can get a better SEO, so that bad posts don't mislead people.

🔲 ☆

三藩記

維西曆十月下旬,余赴美利堅公事。初入國,幾番盤查,始得入境也。至於翻箱倒櫃脫屣赤足亦平常事也,其嚴,甚於西朝鮮矣。余頗惡之。

余年少而家貧,無以直航,東京途次洛杉磯而適三藩。三藩多苦民,衣衫襤褸,幽幽然無所歸者,或蹲或坐或行於街市馬路也。又有果皮紙屑棄於地,臟亂差如是,不及扶桑多矣。三藩之民疑焉,每及問必答曰:扶桑乃發達國家之宗也。

余居三藩凡九日,得閒四天。

初。邀大學同窗共遊伯克利。伯克利者,加州大學分校也,是名校也。其聲名於外,世人但知伯克利,不聞加州大學也。會伯克利慶典,吹號者、擊鼓者、舞者、觀者、錯錯然聚首一地。余與同窗隨慶典行,聞其聲樂觀其歌舞,少女短着,或搔首或旋足或立於他人之肩,青春之謂也。余不得習業於伯克利,奚爲之?購伯克利衛衣,假之充數耳。

伯克利

再。適東原君赴蘋果公事,相約觀金門大橋。東原君驅車,載以出行,午食於天堂洲(Paradise Cay)泰國餐廳也。金門大橋者,蓋三藩名勝,客每至,必觀之也。余不敢自欺,隨波逐流耳。觀之以高山,觀之以近海,皆賴東原君相載也。其山皆灰黃而少植被,三藩環海,乾燥如斯,何爲之?

是夜,與諸君聚於聖荷西,有飯團、Loddit、梁海、東原等君。

金門大橋
海

三。央Bao君載余行射擊之樂也。其地近聖荷西,喚曰「靶宗」(TargetMaster)。余,中國人也,未嘗近手銃也。Bao君親攜槍支彈藥,銃二彈百,余與Bao君相次射之。其聲也巨,余每射,初必入靶,次則未必,皆因初射之聲懼也。

射擊
🔲 ☆

佐渡與阿賀町記

應該學一下車了,小明嘀咕道。他那時在火車上,臨時決定要去阿賀町住一晚。鐵道兩邊的稻田,多數只余枯黃的稻樁,他只偶爾抬頭瞥瞥,依舊回過來看著電腦終端里滾動的日誌,修改 Typlog 的代碼。下一站「馬下」,第一個播客節目看起來沒有問題了,小明不禁松了口氣伸了一個懶腰。

日本十一倒不放假,究竟在家呆久了,早想著出一趟遠門。原本計劃回國去新疆玩的,機票都買好了,因為辦美國簽證,護照還在美國大使館裡,不得不更改行程。去佐渡是臨時決定的,十一的早晨,感冒還未好,小明搭了電車去往秩父,打算坐一坐蒸汽機車,路途翻看地圖,見著西邊有一個離島,便想著不妨到島上一遊,由是選定了佐渡島。

這次又是一個人的旅行,小明倒也習以為常,往年亦多是一人旅,雲南游山水、西北逛沙漠、清邁騎摩托,倒是快活。亦不知是上了年紀,還是異國的孤獨,一個人出行時常會失了興致,又或許因為日本的精緻,失之疏蕩宏博,無法暢懷胸意。

佐渡一度算作流放犯人的蠻荒之地,及至金銀礦的發現,德川幕府置佐渡奉行所直領之。明治時亦曾置縣,現下稱市,屬新潟。小明於小木港入島,両津港離島,其間不過三天,山川人物歷史風貌只得一點淺薄的認識。

小木略顯荒涼,便是十一這樣的時節,到處都是中國人,這裡卻見不著幾個遊客,入境時還見著懸了中文橫幅,上書不地道的歡迎語——歡迎光臨來到佐渡。走在路上,時而可見廢棄的房屋,斑駁的牆壁,爬了一牆的藤蔓,破窗上的蛛網,網中央安靜的蜘蛛。天又陰沈沈的,飄著點細雨。尋找旅館的路上,去城山公園散步的路上,到處散漫著這份荒蕪的詩意。

房屋
蜘蛛

此番行程未曾預訂宿所。他在觀光案內所1翻閱信息,看到小木溫泉有一家「かもめ莊」便記下了。在小木遊蕩,找了一家日式料理店,點了一份天婦羅的定食作午餐。究竟背著旅行包,不太方便,飯後便去尋溫泉旅館了。

可巧還有房間。這一路皆是到了當地再找的,沒有中國遊客,又是工作日,大約因為這些緣故,總是有空房。一路的溫泉旅館,和室加早晚餐,算起來真是便宜,不過一萬多日元,最貴的一回還是去了阿賀町,倒不是佐渡島上的,也不過一萬五。早晚餐又豐富,他竟擔心起會發胖來,也是,來日本後重了十斤。

かもめ莊的老闆給了他一把雨傘,小明放過旅行包便出門散步了。

宿根木的公車卻沒有了,要到五點才有一班。他那麼喜歡破落的人,不能去宿根木的舊房子散步,頗覺遺憾。本來買了三日的公車券,看看小木的情形,車次那麼少,今日大約作廢了,只得在附近走走,坐坐たらい舟,爬城山公園,再去日和山咖啡館喝點東西。

たらい舟
城山公園

公車券要到第二日,去相川時才稍微用得多點。先是從小木坐到佐和田,於佐和田轉車去相川,到相川再坐了車去「佐渡金山」觀光。他在相川觀光案內所內查資料,問所內工作人員近處的溫泉旅館,大叔給他介紹,聽得不太懂的便用紙寫漢字,後來詢問了價格又幫他打電話給旅館,總算是確定了晚上的住所。他把包存在案內所,等公車去佐渡金山。

佐渡金山開放的坑道只有兩個,宗太夫坑與道游坑,另有別的坑是要預約的。如果只看一個坑的話,選宗太夫坑。道游坑乃明治時的現代坑,沒有太多感覺。宗太夫坑卻是幕府時期人工挖掘出的坑道,內里頗具巧工,有會動的人偶扮演當時的情景,或是轉水輪,或是敲石塊,又有做文書工作的。除卻工作情景,亦有洞內的生活再現。坑道長,一路乒乒乓乓,又有介紹工具人物的,不及細看。因為要趕著下一班公車回去,只能草草觀之。

後來才想到,如果能自己開車的話,宿根木也去得,金山坑道也可看得愜意。

回程時又去看過北澤浮游選礦場遺跡。到處都是爬山虎,綠的紅的,垂著飛碟般形狀不知名的建築上,對面卻只有綠色的,蓋滿了階梯。此處又有個技能傳承展示館,可以一睹織布的技藝。

相川
浮游選礦場遺跡
織布

晚間宿道游,其地不大,房間不多,卻皆是面海的,拉開窗簾便可見著。他回相川觀光案內所,所內的大叔幫他致電旅館,不一時便有旅館開車來接了。這家叫道游的旅館,溫泉池太小,沒有露天溫泉。かもめ莊的都有,還有桑拿房。不過都比不了在阿賀町住的福泉。

火車行到津川站,他在這一站下車。上車時刷的交通卡,這一站卻沒有刷卡口,到底是有多鄉下呀。翻看手機地圖,見到兩家溫泉旅館,他便選了福泉,因為看著似乎便宜點。

房間很大,臨窗有一處休息區,窗外便是阿賀野川。川水不息,反照著天空的藍,對面是山,長滿了杉樹,這時節還顯綠。福泉的露天溫泉亦是臨著阿賀野川,彷彿懸在山間,男湯的風景略遜於女湯,因為女湯沒人,過去參觀了一下。

相較起來,福泉的餐食亦是最豐富的。到底是新潟,產米的大縣,晚餐的天婦羅里居然有一例炸稻穗。說起來,新潟的米真是好吃,當時不覺得,他回家後才發覺,因為再吃家裡的米時覺得不好吃了。以前還覺得自己在家煮的米挺好吃的,過年時節回國吃過國內的米,這一對比便知道平日里自家煮的有多好吃了。這回佐渡與阿賀町的旅途才發覺,還有更好吃的米。

炸稻穗
炸稻穗天婦羅

到福泉時不過二點。辦了手續,旅店的姐姐領著他去房間,一路介紹各種設施,他到房間放了包,姐姐泡了茶,稍微休息一下便出門閒逛了。這姐姐會點英文,又有筆紙,聊起來還算順暢,他亦在越谷住過,小明便覺得親切了許多。

麒麟山公園卻在維護,進不得,來途的「狐の嫁入り屋敷」亦閉館,真是憾事。他在麒麟山邊望見城山橋下有個老奶奶在洗東西,一時好奇過去看看,原來是在洗板栗。兩個人便聊起了天,老奶奶提到冬天時特別誇張地直呼「怖い、怖い」,逗得他直笑。

洗板栗的老奶奶
洗板栗的老奶奶

後來聽說他一個人過來玩,並且一路都是一個人時,不免可憐起來。

阿賀町
阿賀町日常
  1. 日本各旅遊地一般都會有觀光案內所,離下車點都不遠的,建議去裏面查查旅遊信息。

❌