5
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

The Zen of Python を文字列で取得する方法

Posted at

実行環境
Python 3.12

はじめに

The Zen of Python は python インタプリタ上で

import this

と打つと表示される、おなじみの文章です。

全文は以下の通り。

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!

さて、この文章を文字列で取得して、変数に格納するにはどうしたらよいでしょうか。

Web ページから拾ってくるのは無しです。

私の場合、ついつい、

SyntaxError
zen = import this

とか、

SyntaxError
print(import this, file='zen.txt')

などと、おかしいと分かりつつも試してしまいました。

もちろん SyntaxError になります。

では落ち着いて、インポートしている this.py の中身を見てみましょう。

this.py のパスは下のコードで分かります。

this.__file__

以下、this.py の中身です。

this.py
s = """Gur Mra bs Clguba, ol Gvz Crgref

Ornhgvshy vf orggre guna htyl.
Rkcyvpvg vf orggre guna vzcyvpvg.
Fvzcyr vf orggre guna pbzcyrk.
Pbzcyrk vf orggre guna pbzcyvpngrq.
Syng vf orggre guna arfgrq.
Fcnefr vf orggre guna qrafr.
Ernqnovyvgl pbhagf.
Fcrpvny pnfrf nera'g fcrpvny rabhtu gb oernx gur ehyrf.
Nygubhtu cenpgvpnyvgl orngf chevgl.
Reebef fubhyq arire cnff fvyragyl.
Hayrff rkcyvpvgyl fvyraprq.
Va gur snpr bs nzovthvgl, ershfr gur grzcgngvba gb thrff.
Gurer fubhyq or bar-- naq cersrenoyl bayl bar --boivbhf jnl gb qb vg.
Nygubhtu gung jnl znl abg or boivbhf ng svefg hayrff lbh'er Qhgpu.
Abj vf orggre guna arire.
Nygubhtu arire vf bsgra orggre guna *evtug* abj.
Vs gur vzcyrzragngvba vf uneq gb rkcynva, vg'f n onq vqrn.
Vs gur vzcyrzragngvba vf rnfl gb rkcynva, vg znl or n tbbq vqrn.
Anzrfcnprf ner bar ubaxvat terng vqrn -- yrg'f qb zber bs gubfr!"""

d = {}
for c in (65, 97):
   for i in range(26):
       d[chr(i+c)] = chr((i+13) % 26 + c)

print("".join([d.get(c, c) for c in s]))

パッと見だと The Zen of Python ぽいですが、よく見るとぜんぜん違います。

英語ではなく別の言語なのかもと思いましたが、そうだとしてもどう発音していいのか想像できない単語が並んでいます。

少なくとも、アルファベットの羅列が s という変数に格納されていことが分かりました。

その下には謎の for 文と print() があります。

鋭い人はこの段階で気づくのかもしれませんが、私は安直に ChatGPT に聞いてしまいました。

という経緯なんですが、今回は ChatGPT が教えてくれた The Zen of Python を文字列で取得する2つの方法を紹介します。

方法1. 出力を差し替えてキャプチャする

1つ目は以下のコードによる方法です。

import this
import io
import sys

# 標準出力を一時的にキャプチャする
buffer = io.StringIO()
sys_stdout = sys.stdout
sys.stdout = buffer

# Zen of Python を出力
import this

# 標準出力を元に戻す
sys.stdout = sys_stdout

# 文字列として取得
zen_string = buffer.getvalue()
ChatGPT による詳しい説明はこちら(コピペ)

1. import this

import this

これは 「Zen of Python」(Pythonの設計哲学)が書かれたイースターエッグモジュールです。

このモジュールをインポートすると、自動的に標準出力に Zen の格言が表示されます。

ただし、この時点ではまだ何もキャプチャしていません。

2. import ioio.StringIO()

import io
buffer = io.StringIO()
  • io.StringIO()文字列をメモリ上にファイルのように扱えるオブジェクトを作ります。
  • このオブジェクトに「出力された内容」を一時的に書き込ませることで、あとで getvalue() を使ってその内容を取り出すことができます。

3. 標準出力を差し替え

sys_stdout = sys.stdout
sys.stdout = buffer
  • sys.stdout は Python の print文や、モジュールが出力する標準出力の行き先です(通常はコンソール)。
  • これを buffer に差し替えることで、「出力内容を画面に表示する代わりに、StringIO に書き込む」ようになります。
  • sys_stdout = sys.stdout で元の出力先を退避しておき、あとで元に戻す準備をしています。

4. import this を再度実行

import this
  • このとき、Zen of Python が標準出力に書き出されますが、sys.stdoutbuffer に差し替えてあるので、その出力はすべて buffer に蓄積されます

5. 標準出力を元に戻す

sys.stdout = sys_stdout
  • 出力先を元に戻します。これで print などが再びコンソールに表示されるようになります。

6. キャプチャした内容を取り出す

zen_string = buffer.getvalue()
  • StringIOgetvalue() を使って、これまでに蓄積された文字列(Zen of Python) を取り出します。

まとめ

この方法では、「import this によって出力される内容を、通常の print と同じようにキャプチャして文字列として扱う」ことが可能です。

こんなときに便利:

  • Zen of Python をGUIで表示したい
  • Webアプリ内でテキスト表示したい
  • 出力をログファイルに書き出したい など

これは私には思いつけない方法で、いい勉強になりました。

io とか sys を使いこなせるとスマートですね。

方法2. this.s に格納された暗号を復号する

import this

# Zen of Python を復号して文字列として取得
zen_string = ''.join(
    [this.d.get(c, c) for c in this.s]
)
ChatGPT による詳しい説明はこちら(コピペ)

🔍 背景の概要

Python の this モジュールは、実は Zen of Python の格言を「ROT13 という簡単な暗号方式」で隠しています。

このモジュールには、以下の2つの隠し要素があります:

名前 内容
this.s ROT13 で暗号化された文字列(Zen of Pythonの本文)
this.d ROT13 の変換テーブル(各文字を元に戻すための辞書)

🔠 ROT13 とは?

ROT13(Rotation by 13 letters)とは、アルファベットを13文字ずらす非常に単純な暗号です。

例:

  • AN
  • NA
  • BO
  • OB
  • …(Zまで)

この方法は、26文字の英字のみに作用します(数字や記号は変わりません)。

🔧 コードの意味とステップ解説

import this
  • ここで this.sthis.d にアクセスできるようになります。
zen_string = ''.join(
    [this.d.get(c, c) for c in this.s]
)

この1行は以下の処理をしています:

1. this.s から1文字ずつ取り出す

for c in this.s
  • 暗号化された文字列 this.s を1文字ずつ処理します。

2. this.d.get(c, c) で復号する

  • this.d は「ROT13 の変換辞書」で、c を復号した文字に変換します。
  • get(c, c) としているのは、変換対象ではない文字(空白・改行・記号など)はそのまま使うためです。

3. ''.join([...]) で文字列に結合

  • リストとして復号された文字をつなげて、Zen of Python の全文(プレーンテキスト)になります。

🎯 まとめ

この方法では、

  • this.s: 暗号化された格言
  • this.d: 文字変換の辞書(ROT13復号)

を使って、自力で復号して取得しています。

この手法の特徴は:

特徴 内容
安定性 出力ではなく、データを直接取得するため堅牢です。
応用性 Zen を加工・分析したいときに便利です。
小技感 Pythonのイースターエッグの裏側を覗いている感覚があります。

もし this.sthis.d の中身も見てみたい場合は、それぞれ print(this.s)print(this.d) で確認できますよ。


this.py に書かれている方法です。

ROT13 という暗号を使っているんですね。

The Zen of Python 以外で使う機会はないと思いますが、小ネタにはちょうどよいかもしれません。

おわりに

今回は、The Zen of Python を文字列で取得する方法を紹介しました。

import this みたいな隠しコマンドをイースターエッグって呼ぶんですね。

標準出力を取得するテクニックを知れたのは収穫でした。

5
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?