This page looks best with JavaScript enabled

Pythonを1行で破壊する

 ·   ·  ☕ 3 min read  ·  🐶 odanny · 👀... views

前書き

ふと Python をぶち壊したくなる衝動に駆られませんか?ぼくはたまにあります。

この記事では、1行でカンタンに Python を破壊する方法を紹介します。


まず「破壊」を定義する

どのような状態を「破壊された」とするかは、人それぞれだと思います。今回は次の2つの条件を満たす状態とします。

  1. import でモジュールをインポートできない
  2. Python の組み込み関数が使えない

組み込み関数が使えないのでprint()range()が使用できず、インポートもできないので外部のモジュールを活用できません。そもそもexit()できないので、インタプリタを閉じることもできなくなります。最低限とは言え、十分破壊できたと言えるのではないでしょうか。


実際に1行で破壊する

まずPythonを立ち上げます。バージョンは 3.6.5 で Windows 10 上で動かしています。

1
2
$ python
Python 3.6.5 (v3.6.5:f59c0932b4, Mar 28 2018, 17:00:18) [MSC v.1900 64 bit (AMD64)] on win32

次の1行を実行すると壊れます。

1
>>> globals()['__builtins__']=0

壊れたか確認する

まず import してみます。

1
2
3
4
>>> import numpy
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: __import__ not found

エラーが出ます。次に組み込み関数を使ってみます。

1
2
3
4
>>> print("Hello world")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'int' object is not subscriptable    

もう Hello world すらできなくなりました。諦めてインタプリタを終了しましょう。

1
2
3
4
>>> exit()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'int' object is not subscriptable

終了もできません。お疲れさまでした。


解説

公式ドキュメント によると、Python 3 において、組み込み関数globals()は次のようなものです。

現在のグローバルシンボルテーブルを表す辞書を返します。これは常に現在のモジュール (関数やメソッドの中では、それを呼び出したモジュールではなく、それを定義しているモジュール) の辞書です。

インタプリタを起動した直後に呼び出してみます。

1
2
>>> globals()
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>}

色々と入っていますね。組み込み関数たちは __buildins__ に格納されています。例えばみんな大好きprint()は、次のように呼び出すこともできます。

1
2
>>> globals()[ '__builtins__'].print("Hello world")
Hello world

普段使うimportも実は build in function です。ドキュメントにも記載があります。

注釈

これは importlib.import_module() とは違い、日常の Python プログラミングでは必要ない高等な関数です。

この関数は import 文により呼び出されます。 (builtins モジュールをインポートして builtins.__import__ に代入することで) この関数を置き換えて import 文のセマンティクスを変更することができますが、同様のことをするのに通常はインポートフック (PEP 302 参照) を利用する方が簡単で、かつデフォルトのインポート実装が使用されていることを仮定するコードとの間で問題が起きないので、このやり方は 強く 推奨されません。 __import__() を直接使用することも推奨されず、 importlib.import_module() の方が好まれます。

推奨されないらしいですが、みんな大好きimport numpy as npは次のようにも書けます。

1
2
3
4
>>> np = globals()[ '__builtins__']. __import__('numpy', globals(), locals(), [], 0)
>>> np.random.rand(10)
array([0.87607603, 0.26654224, 0.51837326, 0.18879567, 0.01763507,
       0.88341288, 0.30957649, 0.80696796, 0.38944628, 0.92909331])

つまり、組み込み関数が保持されているglobals()['__buildins__']を適当な値で上書きすれば破壊できるというわけでした。


感想

役に立つ場面はないと思います。

Share on

odanny
WRITTEN BY
odanny
自作キーボードはまり中