21. 式や文中の空白文字
n 関数呼び出しの引数リストをはじめる開き括弧の直前:
• # 正しい: spam(1)
• # 間違い: spam (1)
n インデックスやスライスの開き括弧の直前:
• # 正しい: dct['key'] = lst[index]
• # 間違い: dct ['key'] = lst [index]
n 代入(や他の)演算子を揃えるために、演算子の周囲に1つ以上のスペースを
入れる:
• # 正しい:
x = 1
y = 2
long_variable = 3
余計な空白文字を使うのはやめましょう
• # 間違い:
x = 1
y = 2
long_variable = 3
• これは間違い!!!
x=1
y=2
if a>0 and b<0:
z = 2*y + 4/b
• 正しくは
x = 1
y = 2
if a > 0 and b < 0:
z = 2 * y + 4 / b
演算子前後の空白は「余計
な空白」ではない!
22. 守るべき命名規約
nこんな名前は嫌だ
• 単一の文字 'l' (小文字のエル)、'O' (大文字のオー)、'I'(大文字のアイ) を決して
変数に使わないでください。
• フォントによっては、これらの文字は数字の1や0と区別が付かない場合があり
ます。'l'(小文字のエル) を使いたくなったら、'L' を代わりに使いましょう。
nフォントにはこだわれ
フォント:Arial/Helvetica
class TestMyAdd(unittest.TestCase):
def test_add(self):
val = myadd(1, 2)
self.assertEqual(3, val)
def test_add_pp(self):
val = myadd(2, 6)
self.assertTrue(val > 0)
def myadd(l, I):
if l > 0 and I > 0:
return l + I
if l < 0 and I < 0:
return l + I
Arial/Helveticaは使わない!
• プロポーショナルフォントだから揃わない
• lとI,0とOが紛らわしい
23. 守るべき命名規約
nこんな名前は嫌だ
• 単一の文字 'l' (小文字のエル)、'O' (大文字のオー)、'I'(大文字のアイ) を決して
変数に使わないでください。
• フォントによっては、これらの文字は数字の1や0と区別が付かない場合があり
ます。'l'(小文字のエル) を使いたくなったら、'L' を代わりに使いましょう。
nフォントにはこだわれ
フォント:Times / Times New Roman
class TestMyAdd(unittest.TestCase):
def test_add(self):
val = myadd(1, 2)
self.assertEqual(3, val)
def test_add_pp(self):
val = myadd(2, 6)
self.assertTrue(val > 0)
def myadd(l, I):
if l > 0 and I > 0:
return l + I
if l < 0 and I < 0:
return l + I
Timesは使わない!
• プロポーショナルフォントだから揃わない
• そもそもセリフ系のフォントでコーディングしない
24. 守るべき命名規約
nこんな名前は嫌だ
• 単一の文字 'l' (小文字のエル)、'O' (大文字のオー)、'I'(大文字のア
イ) を決して変数に使わないでください。
• フォントによっては、これらの文字は数字の1や0と区別が付かない場合があ
ります。'l'(小文字のエル) を使いたくなったら、'L' を代わりに使いま
しょう。
nフォントにはこだわれ
フォント:Courier
class TestMyAdd(unittest.TestCase):
def test_add(self):
val = myadd(1, 2)
self.assertEqual(3, val)
def test_add_pp(self):
val = myadd(2, 6)
self.assertTrue(val > 0)
def myadd(l, I):
if l > 0 and I > 0:
return l + I
if l < 0 and I < 0:
return l + I
Courierはまだまし
• 等幅フォントだから揃ってOK
• まだ0とOが紛らわしい
25. 守るべき命名規約
nこんな名前は嫌だ
• 単一の文字 'l' (小文字のエル)、'O' (大文字のオー)、'I'(大文字のアイ)
を決して変数に使わないでください。
• フォントによっては、これらの文字は数字の1や0と区別が付かない場合があり
ます。'l'(小文字のエル) を使いたくなったら、'L' を代わりに使いましょ
う。
nフォントにはこだわれ
フォント:Consolas (win)
class TestMyAdd(unittest.TestCase):
def test_add(self):
val = myadd(1, 2)
self.assertEqual(3, val)
def test_add_pp(self):
val = myadd(2, 6)
self.assertTrue(val > 0)
def myadd(l, I):
if l > 0 and I > 0:
return l + I
if l < 0 and I < 0:
return l + I
Consolasならよし
• 等幅フォントだから揃ってOK
• 0とOの区別がつく
26. 守るべき命名規約
nこんな名前は嫌だ
• 単一の文字 'l' (小文字のエル)、'O' (大文字のオー)、'I'(大文字のア
イ) を決して変数に使わないでください。
• フォントによっては、これらの文字は数字の1や0と区別が付かない場合があ
ります。'l'(小文字のエル) を使いたくなったら、'L' を代わりに使いま
しょう。
nフォントにはこだわれ
フォント:Menlo (mac)
class TestMyAdd(unittest.TestCase):
def test_add(self):
val = myadd(1, 2)
self.assertEqual(3, val)
def test_add_pp(self):
val = myadd(2, 6)
self.assertTrue(val > 0)
def myadd(l, I):
if l > 0 and I > 0:
return l + I
if l < 0 and I < 0:
return l + I
Menloならよし
• 等幅フォントだから揃ってOK
• 0とOの区別がつく
27. 守るべき命名規約
nこんな名前は嫌だ
• 単一の文字 'l' (小文字のエル)、'O' (大文字のオー)、'I'(大文字のア
イ) を決して変数に使わないでください。
• フォントによっては、これらの文字は数字の1や0と区別が付かない場合があ
ります。'l'(小文字のエル) を使いたくなったら、'L' を代わりに使いま
しょう。
nフォントにはこだわれ
フォント:Source Code Pro
class TestMyAdd(unittest.TestCase):
def test_add(self):
val = myadd(1, 2)
self.assertEqual(3, val)
def test_add_pp(self):
val = myadd(2, 6)
self.assertTrue(val > 0)
def myadd(l, I):
if l > 0 and I > 0:
return l + I
if l < 0 and I < 0:
return l + I
Source Code Proならよし
• 等幅フォントだから揃ってOK
• 0とOの区別がつく
28. 守るべき命名規約
nこんな名前は嫌だ
• 単一の文字 'l' (小文字のエル)、'O' (大文字のオー)、'I'(大文字のア
イ) を決して変数に使わないでください。
• フォントによっては、これらの文字は数字の1や0と区別が付かない場合があ
ります。'l'(小文字のエル) を使いたくなったら、'L' を代わりに使いま
しょう。
nフォントにはこだわれ
フォント:Source Code Pro
class TestMyAdd(unittest.TestCase):
def test_add(self):
val = myadd(1, 2)
self.assertEqual(3, val)
def test_add_pp(self):
val = myadd(2, 6)
self.assertTrue(val > 0)
def myadd(l, I):
if l > 0 and I > 0:
return l + I
if l < 0 and I < 0:
return l + I
Source Code Proならよし
• 等幅フォントだから揃ってOK
• 0とOの区別がつく
自分でフォントをインストールしよう
• プログラミングが捗りすぎる!コーディングに
最適なフォント12選
• 少しでもコーディングするなら“コーディング用
フォント”を導入しよう
• Top Programming Fonts
33. docker composeの準備
起動する
$ cd 11_01_formatting
$ docker compose build
$ docker compose up -d
確認する
$ docker compose ps
停止する
$ docker compose down
34. チェッカーとフォーマッタ
nチェッカー
• 規約に沿っているかどうかをチェック
• Python用PEP8チェッカー
• flake8, pylint, pycodestyle
nフォーマッター
• 規約に沿ったコードに修正
• 別名:beautifier, prettier
• 修正をformattingやbeautificationとも言う
• Python用PEP8フォーマッター
• autopep8, black, yapf
規約を守っていない
イマイチなコード
def myfunc(x, y):
z= 2*x - y
return z
def myfunc_2(a):
for i in range(5):
myfunc( a[i],a[i + 1] )
def myfunc_3(a):
for i in range(5):
myfunc(a[ i ], a[i+ 1])
def main():
a=[1,2,3,4,5]
for _ in range(100):
myfunc_2(a)
for _ in range(300):
myfunc_3 (a)
if __name__ == '__main__':
main()
35. $ docker compose exec mypython flake8 main.py
main.py:4:6: E225 missing whitespace around operator
main.py:4:9: E226 missing whitespace around arithmetic operator
main.py:9:1: E303 too many blank lines (3)
main.py:11:16: E201 whitespace after '('
main.py:11:21: E231 missing whitespace after ','
main.py:11:30: E202 whitespace before ')'
main.py:13:1: E302 expected 2 blank lines, found 1
main.py:15:18: E201 whitespace after '['
main.py:15:20: E202 whitespace before ']'
main.py:15:27: E225 missing whitespace around operator
main.py:19:6: E225 missing whitespace around operator
main.py:19:9: E231 missing whitespace after ','
main.py:19:11: E231 missing whitespace after ','
main.py:19:13: E231 missing whitespace after ','
main.py:19:15: E231 missing whitespace after ','
main.py:21:8: E111 indentation is not a multiple of 4
main.py:23:8: E111 indentation is not a multiple of 4
main.py:23:16: E211 whitespace before '('
$
Flake8によるコードチェック
チェックするファイ
ル名(指定しなけれ
ばpwdのファイルをす
べて)
36. $ docker compose exec mypython flake8 --show-source main.py
main.py:4:6: E225 missing whitespace around operator
z= 2*x - y
^
main.py:4:9: E226 missing whitespace around arithmetic operator
z= 2*x - y
^
main.py:9:1: E303 too many blank lines (3)
def myfunc_2(a):
^
main.py:11:16: E201 whitespace after '('
myfunc( a[i],a[i + 1] )
^
main.py:11:21: E231 missing whitespace after ','
myfunc( a[i],a[i + 1] )
^
main.py:11:30: E202 whitespace before ')'
myfunc( a[i],a[i + 1] )
^
main.py:13:1: E302 expected 2 blank lines, found 1
Flake8によるコードチェック
対応するソー
ス行を表示
37. autopep8によるフォーマッティング
修正前のコード 修正後のコード
def myfunc(x, y):
z = 2 * x - y
return z
def myfunc_2(a):
for i in range(5):
myfunc(a[i], a[i + 1])
def myfunc_3(a):
for i in range(5):
myfunc(a[i], a[i + 1])
def main():
a = [1, 2, 3, 4, 5]
for _ in range(100):
myfunc_2(a)
for _ in range(300):
myfunc_3(a)
if __name__ == '__main__':
main()
def myfunc(x, y):
z= 2*x - y
return z
def myfunc_2(a):
for i in range(5):
myfunc( a[i],a[i + 1] )
def myfunc_3(a):
for i in range(5):
myfunc(a[ i ], a[i+ 1])
def main():
a=[1,2,3,4,5]
for _ in range(100):
myfunc_2(a)
for _ in range(300):
myfunc_3 (a)
if __name__ == '__main__':
main()
67. docker composeの準備
起動する
$ cd 11_02_obfuscation
$ docker compose build
$ docker compose up -d
確認する
$ docker compose ps
停止する
$ docker compose down
68. def myfunc(x, y):
z = 2*x - y
return z
def myfunc_2(a):
result = []
for i in range(5):
result.append(myfunc(a[i], a[i + 1]))
return result
def myfunc_3(a):
result = []
for i in range(5):
result.append(myfunc(a[i], a[i + 1]))
return result
def main():
a = [1, 2, 3, 4, 5, 6]
result = []
for _ in range(100):
result.extend(myfunc_2(a))
def n(x,y):
B=range
E=print
o=sum
z=2*x-y
return z
def P(a):
C=[]
for i in B(5):
C.append(n(a[i],a[i+1]))
return C
def H(a):
C=[]
for i in B(5):
C.append(n(a[i],a[i+1]))
return C
def T():
a=[1,2,3,4,5,6]
C=[]
for _ in B(100):
C.extend(P(a))
pyminifierの結果
docker compose exec mypython pyminifier --obfuscate-builtins --obfuscate main.py > main.obs.py
まだ読める
69. pyobfuscateの結果
読めない...?
docker compose exec mypython pyobfuscate -i main.py > main.obs.py
def myfunc(x, y):
z = 2*x - y
return z
def myfunc_2(a):
result = []
for i in range(5):
result.append(myfunc(a[i], a[i + 1]))
return result
def myfunc_3(a):
result = []
for i in range(5):
result.append(myfunc(a[i], a[i + 1]))
return result
def main():
a = [1, 2, 3, 4, 5, 6]
result = []
for _ in range(100):
result.extend(myfunc_2(a))
oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo
oooooooooo =
"xUrwqqTNfOoJyaMUpmtJnidmcaIEoJLkMmzlVLyeABdgivVIvnwXXWOlYuJWxIsUurKRNUeGGGEcbzl"
IlIIIlIllIIIIllIIlIlIIlIlIIIIIIlllllIIlIllIIlIlllIIIlllIllIIIIlIIIIIlIIlIIllIIIllIIllIII
lllIIllI = 871
AAaaAAAAAAaaaAaaAAaAaaaaAaaaaAAaAAaaaaaAaaaAAaAaAAAAaAAaaAAAaaaaAaAaAAAaaaAaAAaaaaAaAAAA
aAaAaA = 467
l92 = "EJzsVneoODfWOzyIyoAxftCdOpiPPfhaDpgfrhskQWPzKJZcTRdVLAXcYmOQIubPmqnfRFVFwBnRycJ"
aAAAaaaAaaAaAaaaAAaAaaaaAAaAAaAaaaAAAaAAAaAaAaaAAaaaAaAAAaAaAaaAAAaAAaAAAaaaaaAaaaAAaaAa
Aa = "gDypupGxpWeekIQHmuWGBWWDwZaQebOEqzdLVIgdbYUCMXcFViegYYcghZMUQRzeShFfjKEDgROWesn"
d1683520267749028788 =
"PpUxLRzwcmlsYLXdHPAfeBMZlSyRXZCjeHHmzpMCjYrrXXNoWUkztBpqZlZyJRtfTAKKEknLYenmUOg"
X86 = 487
tttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt =
"KpvKamIbTiuUCkRarRHuPrPSyxFGsoSTmVbTCmEmHuLiemmyyWMCBhLjsKabJeeRBsTzsXQFMQYhdAf"
k82 = "MXKTtzWXLzaFrCGPXFWQbtkbDnJQIArMDbizyTIHKUkfBjXMkwUuBVykfoumSJFEmsVPQZZoqLmQZlt"
gggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg =
"bCNmYIZMgRdpYAamdhhzmkNpdUobnMvNRXzLYKfZwmaFxOgyRjtylSxnGtcYVlddyzcvBWPoxswhpwR"
lIIIlIIllllllIlllIIlIlIlIllIIllllllllllIIIIIllIIIlIlIlIIlIIllIlIlIIlIIlIlIlIll = 525
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB = 130
AAAaaaAAaaAAAAAaAaaaAaaAAAAAAaAaaaAaAAaaaAaaAaAaAaaaAAaaaAaAAAaaaAAAaAaAaa =
"LvytqzgdnykIOztMqkAXAMtkZgyukklBhrfzYlkHKcWHIbBvcvVUgZKxwrcFokoUEvkRqcYkYoohHmD"
AaAAAaaaaAaAaAaaAaAaaAaaaAaAaaaaAaaAAaAAAaAAaAaAaAaaAAaAaaAAaaaaAAAaAaaA = 252
voUQpSVTHMbtlAISqZwetKnkUePETXwGKSKdvJtrJxbIhiMmbqTqGxchnWGBOewivYHNEYNSYpehppd70 = 99
IlIIIllIlIlllIllllIllIlIIlIIllllIIIlllIlIlIIlllIlIIlIIIIIIlllIIlIlII = 414
IIIllIllIllIlIlIllIllIlIIlIIIlIIlIIIlIlIIIlIIllIlIllIlIlllIlIIllIl =
"QeDpOELsHZgwdeJWbCeHuwODdybAydXpQlwUvmjvHTNyZZIBqGbiixSrQkdMTZnnMPgaIgoIUQvWWML"
U168352026774849364 = 192
S62 = "zqNYnZzbElmhDfthMMykorqeBjgeNKPndANhDYyuujvaCgFyvPUzTBFSsxjLbCckbAGoSFLvhsyqZjc"
AAaaAAaAaaAaaaaAaAaaaaaAaAAaaaaAAAAAAaAAAAaAaaaAaaaaaaaAaaAA = 281
F58 = 622
v168352026774831856 =
"VEbAlmlWXjnCjuQWuJNYxWntwrAcITqnJLQjsBWCdDlATDpgTUZuCQSOjpbQYinuvXkFgFkebaHHAMH"
...
70. pyobfuscateの結果
途中から読める
docker compose exec mypython pyobfuscate -i main.py > main.obs.py
def myfunc(x, y):
z = 2*x - y
return z
def myfunc_2(a):
result = []
for i in range(5):
result.append(myfunc(a[i], a[i + 1]))
return result
def myfunc_3(a):
result = []
for i in range(5):
result.append(myfunc(a[i], a[i + 1]))
return result
def main():
a = [1, 2, 3, 4, 5, 6]
result = []
for _ in range(100):
result.extend(myfunc_2(a))
IIlIIlIllIIl =
"UgUzfycOkxWVxMWDYPvadsgGBdQKJAQfDYMFFZmgFUcIoGKiLqQIbTSjOOeRlusHDufwZUTkYGWCenC"
llIIllllII = 112
aAAaAaaA = 612
CCCCCC = 634
lIIl = "wnaMMWLpZvypOpawfxkhcfVxvrUewstjYreHuEsxvdaQsYFFFUjFTfdlHyBkGfQxMPfdkiBqLiOiXjZ"
Il = 365
def myfunc(x, y):
MgaaqKaFzoDiOvPcpWdaDqsSpJWlSGtmhpFkXVbIinIrHKdtRtNRnTgQuNOEKprzfyNoyxivOTwfaWy4 =
2*x - y
return
MgaaqKaFzoDiOvPcpWdaDqsSpJWlSGtmhpFkXVbIinIrHKdtRtNRnTgQuNOEKprzfyNoyxivOTwfaWy4
def
myfunc_2(MgaaqKaFzoDiOvPcpWdaDqsSpJWlSGtmhpFkXVbIinIrHKdtRtNRnTgQuNOEKprzfyNoyxivOTwfaWy
4):
aA = []
for i in range(5):
aA.append(myfunc(MgaaqKaFzoDiOvPcpWdaDqsSpJWlSGtmhpFkXVbIinIrHKdtRtNRnTgQuNOEKpr
zfyNoyxivOTwfaWy4[i],
MgaaqKaFzoDiOvPcpWdaDqsSpJWlSGtmhpFkXVbIinIrHKdtRtNRnTgQuNOEKprzfyNoyx¥
ivOTwfaWy4[i + 1]))
return aA
def
myfunc_3(MgaaqKaFzoDiOvPcpWdaDqsSpJWlSGtmhpFkXVbIinIrHKdtRtNRnTgQuNOEKprzfyNoyxivOTwfaWy
4):
aA = []
for i in range(5):
aA.append(myfunc(MgaaqKaFzoDiOvPcpWdaDqsSpJWlSGtmhpFkXVbIinIrHKdtRtNRnTgQuNOEKpr
zfyNoyxivOTwfaWy4[i],
MgaaqKaFzoDiOvPcpWdaDqsSpJWlSGtmhpFkXVbIinIrHKdtRtNRnTgQuNOEKprzfyNoyx¥
ivOTwfaWy4[i + 1]))
return aA
72. $ docker compose exec mypython pyarmor gen main.py
INFO Python 3.11.3
INFO Pyarmor 8.1.9 (trial), 000000, non-profits
INFO Platform linux.x86_64
INFO search inputs ...
INFO find script main.py
INFO find 1 top resources
INFO start to generate runtime files
INFO target platforms {'linux.x86_64'}
INFO write dist/pyarmor_runtime_000000/pyarmor_runtime.so
INFO patch runtime file
INFO generate runtime files OK
INFO start to obfuscate scripts
INFO process resource "main"
INFO obfuscating file main.py
INFO write dist/main.py
INFO obfuscate scripts OK
$
PyArmorによる難読化
難読化するファイル名
難読化の指定
生成される
配布用 (dist)
の難読化
コードと実
行用ライブ
ラリ
73. PyArmorによる難読化
main.py dist/main.py
def myfunc(x, y):
z = 2*x - y
return z
def myfunc_2(a):
result = []
for i in range(5):
result.append(myfunc(a[i], a[i + 1]))
return result
def myfunc_3(a):
result = []
for i in range(5):
result.append(myfunc(a[i], a[i + 1]))
return result
def main():
a = [1, 2, 3, 4, 5, 6]
result = []
for _ in range(100):
result.extend(myfunc_2(a))
for _ in range(300):
result.extend(myfunc_3(a))
print(sum(result))
if __name__ == '__main__':
main()
# Pyarmor 8.1.9 (trial), 000000, non-profits, 2023-05-
07T13:16:44.854501
from pyarmor_runtime_000000 import __pyarmor__
__pyarmor__(__name__, __file__,
b'PY000000¥x00¥x03¥x0b¥x00¥xa7¥r¥r¥n¥x80¥x00¥x01¥x00¥x08
¥x00¥x00¥x00¥x04¥x00¥x00¥x00@¥x00¥x00¥x00¥xb9¥x0b¥x00¥x0
0¥x12¥t¥x04¥x00¥xe6¥x12¥xb4¥x7f2¥xb7[ ;5¥xb2¥xc0Rg¥x0ba¥
x00¥x00¥x00¥x00¥x00¥x00¥x00¥x00¥xc0¥x91¥xca1uF¥x93¥x98N¥
xaa¥x92Uh¥xe8¥x07Vo@¥xa2¥x04¥xe9¥xa7;¥x1eq¥xc5¥xc7¥x02¥x
e2¥x95¥xc7¥x12$3V?]¥xa5¥x05¥xe0¥x94¥x828¥x886D¥xaaY¥nS¥x
81G)Q¥xb8¥xcb¥xa4¥xff¥x86¥x03K¥x14S¥xa1¥x00¥x12¥x99[/¥x9
av¥x1dCa¥x1e¥xc7¥xa9¥xc3¥x9d¥xc97¥x16¥xbf¥x89¥xb6¥xaa¥xb
4¥xfdT¥r¥xe4WA?¥xc8N¥x83<S¥x9fZoU¥xcb5tf¥xa1¥xbe¥x07¥xf6
¥xd8¥x1b¥xec¥xec¥x8dx¥xe6¥x01¥xe6¥xb3¥x0e¥x18¥x9c¥xb1¥xc
4=¥x94¥xdd@¥xc5fH¥x9f¥xddR¥xc5¥x1ew"VL¥x9b¥xe2¥x93¥xdc¥x
db¥x0e¥xf4d¥x85u[¥xe0¥xcc¥xeaX¥x8e¥xf0¥xf1%¥x87¥xb3¥xb1¥
xa5¥x02¥xf1¥xaa¥x1e¥xf8¥xceL¥x8c¥x0e¥x1f¥x1c¥xe8¥xd2¥xcf
¥x1a¥x96F¥x13¥x02¥x01vdH¥xa6NU¥x18¥x14,h¥x18¥xe9¥x87¥x1f
{¥xa1¥xd9k¥xc4¥x98p¥xfd¥xd9GB{UtO¥x1f¥xd0¥xf4V¥x1aZ¥x11^
~¥xa4¥xa9?g¥xb2K¥xeec¥x05:¥xd7K¥xeb¥x14J¥xcb¥xb7¥xecC¥xd
a¥xbc¥xa2$¥x1d¥xb9¥xcc¥xdcy¥xaf¥x04¥x12¥xb6¥xf8¥x18¥xf8n
¥x8eY6¥x9f=¥xff¥x1eR¥xa1]V¥xb6?¥x0c¥¥¥xff¥x88-¥xbe¥x12
制約:付属ライブラリが必要
• OSやPythonのバージョンが
変わると実行できない
• dockerを使えば解決
• この制約はコンパイルと同じ
• pyarmorならライセンス期
限が来たら実行できなく
することもできる