地獄のパむ゜ン


最近、面癜い、トリッキヌ、そしお奇劙なJavaScriptの䟋に぀いお曞きたした 。 今ではPythonの番です。 高床なむンタヌプリタヌ型蚀語であるPythonには、倚くの䟿利なプロパティがありたす。 しかし、䞀芋したずころ䞀郚のコヌドの結果が明らかでない堎合がありたす。


以䞋は、Pythonでの予期しない動䜜の䟋を収集し、内郚で䜕が起こるかを議論する楜しいプロゞェクトです。 いく぀かの䟋は、実際のWTFのカテゎリに属しおいたせん、しかし、それらはあなたが避けたい蚀語の興味深い特城を瀺しおいたす。 これはPythonの内郚の仕組みを孊ぶ良い方法だず思いたす。興味を持っおいただければ幞いです。


既に経隓豊富なPythonプログラマヌである堎合、倚くの䟋はあなたによく知られおいるかもしれたせんし、それらに頭を悩たせるずき、それらの堎合に懐かしささえ匕き起こすかもしれたせん:)


内容



䟋の構造


泚䞊蚘の䟋はすべお、察話型Python 3.5.2むンタヌプリタヌでテストされおおり、説明で特に指定されおいない限り、すべおのバヌゞョンの蚀語で動䜜するはずです。


䟋の構造


いく぀かの愚かな芋出し


 # . #   ... 

結果Pythonバヌゞョン


 >>> _ ,   

オプション予期しない結果の1行の説明。


説明



PSコマンドラむンでこれらの䟋を読むこずもできたす。 wtfpythonにwtfpython npmパッケヌゞをむンストヌルするだけで、


 $ npm install -g wtfpython 

コマンドラむンでwtfpythonを実行するず、このコレクションが$PAGER開きたす。


#TODOpypiパッケヌゞを远加しお、コマンドラむンで読み取りたす。


䟋


行スキップ


結果


 >>> value = 11 >>> valu = 32 >>> value 11 

ワット


泚この䟋を再珟する最も簡単な方法は、ファむル/シェルにコピヌしお貌り付けるこずです。


説明


䞀郚のUnicode文字はASCIIず同じように芋えたすが、むンタヌプリタヌによっお異なりたす。


 >>> value = 42 #ascii e >>> valu = 23 #cyrillic e, Python 2.x interpreter would raise a `SyntaxError` here >>> value 42 

たあ、どういうわけか怪しい...


 def square(x): """        . """ sum_so_far = 0 for counter in range(x): sum_so_far = sum_so_far + x return sum_so_far 

結果Python 2.x


 >>> square(10) 10 

100ではないでしょうか
泚結果を再珟できない堎合は、シェルでmixed_tabs_and_spaces.pyファむルを実行しおみおください。


説明



結果Python 3.x


 TabError: inconsistent use of tabs and spaces in indentation 

ハッシュケヌキの時間


1。


 some_dict = {} some_dict[5.5] = "Ruby" some_dict[5.0] = "JavaScript" some_dict[5] = "Python" 

結果


 >>> some_dict[5.5] "Ruby" >>> some_dict[5.0] "Python" >>> some_dict[5] "Python" 

PythonはJavaScriptの存圚を砎壊したしたか


説明



凊理時間の䞍䞀臎


 array = [1, 8, 15] g = (x for x in array if array.count(x) > 0) array = [2, 8, 22] 

結果


 >>> print(list(g)) [8] 

説明



反埩䞭に蟞曞を倉換する


 x = {0: None} for i in x: del x[i] x[i+1] = None print(i) 

結果


 0 1 2 3 4 5 6 7 

はい、 8回実行されお停止したす。


説明



反埩䞭にリストアむテムを削陀する


 list_1 = [1, 2, 3, 4] list_2 = [1, 2, 3, 4] list_3 = [1, 2, 3, 4] list_4 = [1, 2, 3, 4] for idx, item in enumerate(list_1): del item for idx, item in enumerate(list_2): list_2.remove(item) for idx, item in enumerate(list_3[:]): list_3.remove(item) for idx, item in enumerate(list_4): list_4.pop(idx) 

結果


 >>> list_1 [1, 2, 3, 4] >>> list_2 [2, 4] >>> list_3 [] >>> list_4 [2, 4] 

結果が埗られた理由を知っおいたすか[2, 4] 


説明



なぜそれが起こったのか[2, 4] 



行末のバックスラッシュ


結果


 >>> print("\\ some string \\") >>> print(r"\ some string") >>> print(r"\ some string \") File "<stdin>", line 1 print(r"\ some string \") ^ SyntaxError: EOL while scanning string literal 

説明



巚倧な糞を䜜ろう


これはたったくWTFではありたせんが、いく぀かのクヌルなこずだけであり、泚意する必芁がありたす:)


 def add_string_with_plus(iters): s = "" for i in range(iters): s += "xyz" assert len(s) == 3*iters def add_string_with_format(iters): fs = "{}"*iters s = fs.format(*(["xyz"]*iters)) assert len(s) == 3*iters def add_string_with_join(iters): l = [] for i in range(iters): l.append("xyz") s = "".join(l) assert len(s) == 3*iters def convert_list_to_string(l, iters): s = "".join(l) assert len(s) == 3*iters 

結果


 >>> timeit(add_string_with_plus(10000)) 100 loops, best of 3: 9.73 ms per loop >>> timeit(add_string_with_format(10000)) 100 loops, best of 3: 5.47 ms per loop >>> timeit(add_string_with_join(10000)) 100 loops, best of 3: 10.1 ms per loop >>> l = ["xyz"]*10000 >>> timeit(convert_list_to_string(l, 10000)) 10000 loops, best of 3: 75.3 µs per loop 

説明



文字列連結むンタヌプリタヌの最適化


 >>> a = "some_string" >>> id(a) 140420665652016 >>> id("some" + "_" + "string") # Notice that both the ids are same. 140420665652016 # using "+", three strings: >>> timeit.timeit("s1 = s1 + s2 + s3", setup="s1 = ' ' * 100000; s2 = ' ' * 100000; s3 = ' ' * 100000", number=100) 0.25748300552368164 # using "+=", three strings: >>> timeit.timeit("s1 += s2 + s3", setup="s1 = ' ' * 100000; s2 = ' ' * 100000; s3 = ' ' * 100000", number=100) 0.012188911437988281 

説明



はい、存圚したす


forルヌプのelse節 。 兞型的な䟋


  def does_exists_num(l, to_find): for num in l: if num == to_find: print("Exists!") break else: print("Does not exist") 

結果


 >>> some_list = [1, 2, 3, 4, 5] >>> does_exists_num(some_list, 4) 

ありたす


 >>> does_exists_num(some_list, -1) 

存圚したせん。


䟋倖凊理のelse句 。 䟋


 try: pass except: print("Exception occurred!!!") else: print("Try block executed successfully...") 

結果


 Try block executed successfully... 

説明



isそうではisたせん


この䟋は非垞に広く知られおいたす。


 >>> a = 256 >>> b = 256 >>> a is b True >>> a = 257 >>> b = 257 >>> a is b False >>> a = 257; b = 257 >>> a is b True 

説明


isず==の違い



 >>> [] == [] True >>> [] is [] # These are two empty lists at two different memory locations. False 

256は既存のオブゞェクトですが、 257はそうではありたせん
Pythonを起動するず、-5〜256の数倀がメモリに割り圓おられたす。 これらは頻繁に䜿甚されるため、準備を敎えおおくこずをお勧めしたす。


https://docs.python.org/3/c-api/long.htmlから匕甚


珟圚の実装では、-5〜256のすべおの数倀に察しお敎数オブゞェクトの配列がサポヌトされおいるため、この範囲からintを䜜成するず、既存のオブゞェクトぞのリンクが取埗されたす。 したがっお、倀を1に倉曎できるはずです。しかし、この堎合、Pythonの動䜜は予枬䞍胜になるず思われたす。 :-)

 >>> id(256) 10922528 >>> a = 256 >>> b = 256 >>> id(a) 10922528 >>> id(b) 10922528 >>> id(257) 140084850247312 >>> x = 257 >>> y = 257 >>> id(x) 140084850247440 >>> id(y) 140084850247344 

むンタヌプリタヌはそれほどスマヌトではなく、実行時にy = 257は倀257敎数を既に䜜成したこずを理解しおいなかったため、メモリ内に別のオブゞェクトを䜜成したす。


aずbは、同じ行に同じ倀を持぀初期化䞭に同じオブゞェクトを参照したす。


 >>> a, b = 257, 257 >>> id(a) 140640774013296 >>> id(b) 140640774013296 >>> a = 257 >>> b = 257 >>> id(a) 140640774013392 >>> id(b) 140640774013488 


is not ... is (not ...)


 >>> 'something' is not None True >>> 'something' is (not None) False 

説明



ルヌプ内の関数は同じ結果を返したす。


 funcs = [] results = [] for x in range(7): def some_func(): return x funcs.append(some_func) results.append(some_func()) funcs_results = [func() for func in funcs] 

結果


 >>> results [0, 1, 2, 3, 4, 5, 6] >>> funcs_results [6, 6, 6, 6, 6, 6, 6] 

some_funcをfuncsに远加する前に、各反埩のx倀が異なる堎合、すべおの関数は6を返したした。


 //OR >>> powers_of_x = [lambda x: x**i for i in range(10)] >>> [f(2) for f in powers_of_x] [512, 512, 512, 512, 512, 512, 512, 512, 512, 512] 

説明



 funcs = [] for x in range(7): def some_func(x=x): return x funcs.append(some_func) 

結果


 >>> funcs_results = [func() for func in funcs] >>> funcs_results [0, 1, 2, 3, 4, 5, 6] 

ロヌカルスコヌプからのルヌプ倉数の挏掩


1。


 for x in range(7): if x == 6: print(x, ': for x inside loop') print(x, ': x in global') 

結果


 6 : for x inside loop 6 : x in global 

ただし、 xスコヌプ倖のルヌプに察しお定矩されおいたせん。


2。


 # This time let's initialize x first x = -1 for x in range(7): if x == 6: print(x, ': for x inside loop') print(x, ': x in global') 

結果


 6 : for x inside loop 6 : x in global 

3。


 x = 1 print([x for x in range(5)]) print(x, ': x in global') 

結果Python 2.xの堎合


 [0, 1, 2, 3, 4] (4, ': x in global') 

結果Python 3.xの堎合


 [0, 1, 2, 3, 4] 1 : x in global 

説明



䞉目䞊べ、最初の詊行でXが勝぀


 # Let's initialize a row row = [""]*3 #row i['', '', ''] # Let's make a board board = [row]*3 

結果


 >>> board [['', '', ''], ['', '', ''], ['', '', '']] >>> board[0] ['', '', ''] >>> board[0][0] '' >>> board[0][0] = "X" >>> board [['X', '', ''], ['X', '', ''], ['X', '', '']] 

しかし、3぀のXは割り圓おたせんでしたか


説明


この芖芚化は、 row倉数が初期化されたずきにメモリで䜕が起こるかを説明しおいたす。


画像


board rowを乗算しお初期化されるず、これはメモリ内で発生したす board[0] 、 board[1]およびboard[2]各芁玠は、 row指定された同じリストぞのリンクです。


画像


可倉のデフォルト匕数に泚意しおください


 def some_func(default_arg=[]): default_arg.append("some_string") return default_arg 

結果


 >>> some_func() ['some_string'] >>> some_func() ['some_string', 'some_string'] >>> some_func([]) ['some_string'] >>> some_func() ['some_string', 'some_string', 'some_string'] 

説明



 def some_func(default_arg=[]): default_arg.append("some_string") return default_arg 

結果


 >>> some_func.__defaults__ #This will show the default argument values for the function ([],) >>> some_func() >>> some_func.__defaults__ (['some_string'],) >>> some_func() >>> some_func.__defaults__ (['some_string', 'some_string'],) >>> some_func([]) >>> some_func.__defaults__ (['some_string', 'some_string'],) 



Source: https://habr.com/ru/post/J337364/


All Articles