Pythonに切り替えるプログラマーが覚えておくべきこと

むかしむかし、学生時代に、私はパイソンに噛まれましたが、潜伏期間が遅れ、私は真珠のプログラマーになったことが判明しました。







しかし、ある時点で真珠は使い果たされ、私はPythonを取り上げることに決めました。最初に何かをして、このタスクに必要なものを見つけました。その後、何らかの体系的な知識が必要であり、いくつかの本を読んだことに気付きました:









言語の基本的な微妙さを理解するのに非常に適しているように見えましたが、 スロットに言及したことは覚えていませんが、これが本当に必要な機能であることはわかりませんそれはすべて状況に依存します。







その結果、私はpythonの機能に関するいくつかのメモを蓄積しました。これは、他の言語からpythonに移行したい人に役立つと思われます。







Pythonのインタビューでは、辞書のキーとなるもの(またはx = yield y



意味)など、実際の開発に関連しないものについて十分な質問が頻繁に行われることに気付きました。数字または文字列のみ、そうでないユニークなケースでは、ドキュメントを読んで、これを尋ねる理由を理解できますか? インタビュー対象者が知らないことを見つけるには? そのため、最終的には誰もがこの特定の質問に対する答えを覚えてしまい、機能しなくなります。







3.5以降のバージョンのバージョンが重要であると考えます(2番目のPythonを長い間忘れるとき来ました) これは安定版Debianのバージョンです。つまり、他のすべての場所には最新バージョンがあります)







私はまったくPythonの達人ではないので、ある種の愚かさを突然凍結した場合、コメントで訂正してくれることを願っています。







タイピング



Pythonは動的に型付けされた言語です。 実行時に型の一致をチェックします。次に例を示します。







 cat type.py a=5 b='5' print(a+b)
      
      





実行する:







 python3 type.py ... TypeError: unsupported operand type(s) for +: 'int' and 'str'
      
      





ただし、プロジェクトが静的型付けの必要性に成熟している場合、pythonはmypy



静的アナライザーを使用してこのような機会を提供します。







 mypy type.py type.py:3: error: Unsupported operand types for + ("int" and "str")
      
      





確かに、すべてのエラーがこの方法でキャッチされるわけではありません。







 cat type2.py def greeting(name): return 'Hello ' + name greeting(5)
      
      





mypyはここでは誓いませんが、実行中にエラーが発生するため、現在のバージョンのpythonは関数引数のタイプを指定するための特別な構文をサポートしています。







 cat type3.py def greeting(name: str) -> str: return 'Hello ' + name greeting(5)
      
      





そして今:







 mypy type3.py type3.py:4: error: Argument 1 to "greeting" has incompatible type "int"; expected "str"
      
      





変数とデータ



Pythonの変数はデータを保存せず、それらを参照するだけで、データは可変(可変)および不変(不変)です。

これにより、ほぼ同じ状況でデータのタイプに応じて異なる動作が発生します。たとえば、次のコードです。







 x = 1 y = x x = 2 print(y)
      
      





変数x



y



が異なるデータを参照するという事実につながります。







 x = [1, 2, 3] y = x x[0] = 7 print(y)
      
      





いいえ、 x



y



は同じリストへのリンクのままです(ただし、 コメントに記載されているように、例はあまり成功していませんが、私はまだうまくいっていません)、Pythonの方法でis



演算子で確認できます(Javaの作成者は永遠に良い睡眠を失ったと確信しています)私はPythonでこの演算子を見つけたときに恥から)。







行はリストのように見えますが、それらは不変のデータ型です。つまり、文字列自体は変更できず、新しいもののみを作成できますが、元のデータは変更されませんが、変数に異なる値を割り当てることができます:







 >>> mystr = 'sss' >>> newstr = mystr #       >>> mystr[0] = 'a' ... TypeError: 'str' object does not support item assignment >>> mystr = 'ssa' #    >>> newstr #         'sss'
      
      





文字列といえば、その耐性のために、ループに追加または追加することで文字列の非常に大きなリストを連結することはあまり効果的ではない場合があります(特定のコンパイラ/バージョンの実装によって異なります)。通常、このような場合には、少し予想外:







 >>> str_list = ['ss', 'dd', 'gg'] >>> 'XXX'.join(str_list) 'ssXXXddXXXgg' >>> str = 'hello' >>> 'XXX'.join(str) 'hXXXeXXXlXXXlXXXo'
      
      





まず、メソッドが呼び出される行はセパレーターになり、考えられるような新しい行の始まりではなく、次に、リスト(反復可能なオブジェクト)を渡す必要があります。これは反復可能なオブジェクトでもあり、シンボル化されるためです。 。







変数はリンクであるため、元のオブジェクトを壊さないようにオブジェクトのコピーを作成するのは非常に普通ですが、落とし穴があります- コピー機能は1レベルのみをコピーします。これは明らかにこの名前の関数から期待されるものではないため、 deepcopy



使用しdeepcopy









ここで説明したように、コレクションにスカラーが乗算されると、コピーに関する同様の問題が発生する可能性があります







範囲



スコープのトピックはおそらく別の記事に値しますが、SOには良い答えがあります。

要するに、スコープはレキシカルであり、可視性の6つの領域があります-関数本体、クロージャー、モジュール、クラス本体、組み込みPython関数とリスト内の変数、およびその他のインクルード内の変数。

微妙な点があります-デフォルト変数は字句的にネストされた名前空間で読み取り可能ですが、変更にはそれぞれ1レベル高いまたはグローバルな可視性の変数を変更するために特別なnonlocal



およびglobal



キーワードの使用が必要です。







たとえば、次のようなコード:







 x = 7 print(id(x)) def func(): print(id(x)) return x print(func())
      
      





1つのグローバル変数で動作し、これは次のとおりです。







 x = 7 print(id(x)) def func(): x = 1 print(id(x)) return x print(func()) print(x)
      
      





既にローカルのものを生成します。

私の観点からすると、これはあまり良くありません。原則として、関数内での非ローカル変数の使用は、関数のパブリックインターフェイス、そのシグネチャの一部です。つまり、明示的に宣言し、関数の最初に表示する必要があります。 また、キーワードはあまり有益ではありません-グローバル関数の定義のようなglobal



音ですが、実際にはuse global



use global



することを意味しuse global









Pythonでは、多くの言語で行われているように、プログラムが開始する必須のエントリポイントはありませんが、モジュールレベルで書かれたすべてのものが順番に実行されますが、モジュールレベルの変数はグローバル変数であるため、私の観点からは良い習慣ですmain()



関数にメインコードを詰め込み、その後にファイルの最後で呼び出します。







 if __name__ == '__main__': main()
      
      





この条件は、ファイルがスクリプトとして呼び出され、モジュールとしてインポートされない場合に機能します。







関数の引数



Pythonは、関数の引数(位置引数、名前付き引数、およびそれらの組み合わせ)を定義するための素晴らしい機会を提供します。







しかし、引数がどのように渡されるかを理解する必要があります-なぜなら Pythonでは、すべての変数はデータへのリンクであり、転送は参照によるものと推測できますが、特殊性があります-リンク自体は値によって渡されます 参照により可変値を変更できます。







 def add_element(mylist): mylist.append(3) mylist = [1,2] add_element(mylist) print(mylist)
      
      





実行する:







 python3 arg_modify.py [1, 2, 3]
      
      





ただし、関数内の元のリンクを上書きすることはできません。







 def try_del(mylist): mylist = [] return mylist mylist = [1,2] try_del(mylist) print(mylist)
      
      





ソースリンクは生きていて機能しています:







 python3 arg_kill.py [1, 2]
      
      





引数のデフォルト値を設定することもできますが、覚えておくべき非自明なことが1つあります。デフォルト値は関数を定義するときに一度計算されるため、未変更のデータをデフォルト値として渡す場合や、変数データまたは動的な値、結果は少し予想外です:







可変データ:







 cat arg_list.py def func(arg = []): arg.append('x') return arg print(func()) print(func()) print(func())
      
      





結果:







 python3 arg_list.py ['x'] ['x', 'x'] ['x', 'x', 'x']
      
      





動的な値:







 cat arg_now.py from datetime import datetime def func(arg = datetime.now()): return arg print(func()) print(func()) print(func())
      
      





私達は得る:







 python3 arg_now.py 2018-09-28 10:28:40.771879 2018-09-28 10:28:40.771879 2018-09-28 10:28:40.771879
      
      





OOP



PythonのOOPは非常に興味深いものです(一部のプロパティには価値があります)が、これは大きなトピックですが、OOPに精通しているサピエンスは彼が望むすべてのもの(またはハブで見つける)をグーグルで検索するかもしれないので、繰り返しは意味がありませんが、Pythonは少し: -異なる哲学がマシン賢くプログラマ、およびは脅威ではないということです(UPD より Pythonのデフォルトは他の言語のアクセス修飾子には普通ではありませんので、):メソッド名のランタイムを変更する2つの下線を(追加することによって実装プライベートメソッドはOAPCではありません スレッド)それを使用する機会、そして何もしない保護された1アンダースコア(それは)ちょうど命名規則です。

通常の機能を欠いている人は、そのような機会をpythonにもたらす試みを探すことができます。いくつかのオプション( langpython-access )は私によってグーグルで検索されましたが、私はそれらをテストも研究もしませんでした。







標準クラスの唯一のマイナス点は、 Danderメソッドのテンプレートコードです。私は個人的にattrsライブラリが好きです。

Pythonでは、関数やクラスを含むすべてのオブジェクトが、 関数によって( eval



を使用せずに)動的に作成できるため、言及する価値があります。

また、 メタクラスHabr )および記述子Habr )について読むこともできます。

覚えておく価値のある特性は、クラスとオブジェクトの属性が同じものではないことです。不変の属性の場合、属性は「シャドウイング」なので問題は発生しません。同じ名前のオブジェクトの属性は自動的に作成されますが、変更可能な属性の場合はできます予想されたものとはまったく異なります。







 cat class_attr.py class MyClass: storage = [7,] def __init__(self, number): self.number = number obj = MyClass(1) obj2 = MyClass(2) obj.number = 5 obj.storage.append(8) print(obj2.storage, obj2.number)
      
      





私達は得る:







 python3 class_attr.py [7, 8] 2
      
      





ご覧のobj2



変更され、 obj2



storage



変更されました。 この属性は( number



とは異なり)インスタンスに属していませんが、クラスに属します。







定数



アクセス修飾子の場合のように、Pythonは開発者を制限しようとしないため、標準的な方法で変更から保護されたスカラー変数を定義することはできません。大文字の名前を持つ変数は定数と見なす必要があるという単純な合意があります。

一方、Pythonにはタプルなどの不変のデータ構造があるため、configなどのグローバル構造を不変にし、依存関係を追加したくない場合は、 namedtupleを選択するのが適切ですが、型を記述するのに少し手間がかかります。私は、ドット表記の不変構造の代替実装-Box(frozen_boxパラメーターを参照)が好きです。

スカラー定数が必要な場合は、「コンパイル」の段階でアクセス制御を実装できます。つまり、 mypy、 exampledetailsをチェックします。







.sort()vsソート済み()



Pythonでリストをソートするには、2つの方法があります。 1つ目は、元のリストを変更して何も(なし)を返す.sort()



メソッドです。 これはできません:







 my_list = my_list.sort()
      
      





2番目は、 sorted()



関数です。この関数は、新しいリストを生成し、すべての反復可能なオブジェクトを処理できます。 SOで始まる情報が必要な人。







標準ライブラリ



通常、標準のPythonライブラリには一般的な問題に対する優れた解決策が含まれていますが、奇妙な点が十分にあるため、重要なことは価値があります。 確かに、一見奇妙に見えるものが最良の解決策であることが判明することもあります。すべての条件を知る必要があります(範囲については以下を参照)が、まだ奇妙な点があります。







たとえば、キットに付属するunittestユニットモジュールは、PythonやJavaのスマックとは関係ありません。そのため、 Pythonの作成者は 「Eveybodyはpy.testを使用しています...」と述べています。 非常に興味深いものですが、必ずしも適切ではない場合でも、 doctestモジュールが標準として付属しています。







提供されているurllibモジュールに 、サードパーティのリクエストモジュールのような美しいインターフェースはありません。







コマンドラインパラメータを解析するためのモジュールと同じ話-キットにバンドルされているargparseは脳のOOPのデモであり、 docoptモジュールは単なるスマートソリューションであるようです-究極の自己文書化! しかし、噂によると、docoptとクリックにもかかわらず、ニッチがあります。







デバッガーでも-私が理解しているように、バンドルされたpdbを使用する人は少なく、多くの選択肢がありますが、開発者の大半はipdbを使用しているようです 。これは、私の観点から、 デバッグラッパーモジュールを介して使用するのが最も便利です。

import ipdb;ipdb.set_trace()



代わりにimport ipdb;ipdb.set_trace()



import debug



import ipdb;ipdb.set_trace()



単純に記述できます。また、オブジェクトの便利な検査のためにseeモジュールを追加します。







標準のシリアル化モジュールを置き換えるために、 pickledillです 。ところで、これらのモジュールは外部システムでのデータ交換には適していません。 制御されていないソースから受け取った任意のオブジェクトを復元することは安全ではありません。そのような場合、json(RESTの場合)とgRPC (RPCの場合)があります。







標準の正規表現処理モジュールを置き換えるには、 reは、文字クラスala \p{Cyrillic}



など、あらゆる種類の追加機能を備えたregexモジュールを作成します。

ちなみに、pythonには、 パールオオムギに似た正規表現用の楽しいデバッガーはありませんでした。







ここに別の例があります-ファイル編集のインプレース部分で、標準ファイル入力モジュールのAPIの曲率と不完全性を修正するために、インプレースモジュールを作成しました。







まあ、私はそのようなケースをたくさん考えます、私は複数に出くわすことさえあるので、注意して、あらゆる種類の素晴らしい有用なリストを見ることを忘れないでください、良い栄養士は彼の決定の最高の香りを持っていると思います、これはところで、別の議論のトピックです-私の気持ちによると(もちろん、このテーマに関する統計はなく、明らかにそうではありません)、Pythonの世界では専門家のレベルは平均を上回っています。多くの場合、良いソフトウェアはPythonで書かれているので、あなたがこれについてどう思うかコメントに書いてください







並行性と競争



Pythonは、並列プログラミングと競合プログラミングの両方に十分な機会を提供しますが、機能がないわけではありません。







並列処理が必要で、タスクで計算が必要なときにこれが発生する場合は、 マルチプロセッシングモジュールに注意する必要があります。







また、タスクに多くのIOの期待がある場合、pythonには、スレッドおよびgeventからasyncioに至るまで選択するための多くのオプションが用意されています。

これらのオプションはすべて使用に適しています(スレッドはより多くのリソースを必要とします)が、uvloopなどのあらゆる種類の機能のおかげで、asyncioが残りを徐々に絞り出しているように感じます。







誰かが気づいていない場合-pythonでは、スレッドは並列処理についてではありません、私はGILについて十分に話す能力がありませんが、このトピックには十分な資料がありますので、そのような必要はありません、覚えておくべき主なことはpythonのスレッドですCPythonでは)他のプログラミング言語とは異なる動作をします-それらは1つのコアでのみ動作します。つまり、実際の並列処理が必要な場合には適していませんが、I / Oを待っているとスレッドの実行が一時停止するため、使用できます 競争力のために。







その他の奇妙な点



Pythonでは、 a = a + b



必ずしもa += b



と同等でa = a + b



ません。







 a = [1] a = a + (2,3) TypeError: can only concatenate list (not "tuple") to list a += (2,3) a [1, 2, 3]
      
      





なぜそれがそうであるかを理解する時間を見つけるまで、私はそれをSOに送ります、彼らがそれをした理由の意味で、これは再び可変性についてです。







奇妙ではない奇妙な



一見すると、範囲の種類に正しい境界線が含まれていないのは奇妙に思えましたが、親切な人が学ぶ必要がある場所無視するように言ったので、すべてが非常に論理的であることがわかりました。







別の大きなトピックは丸めです(この問題はほとんどすべてのプログラミング言語に共通ですが)、あなたが好きなように丸めを使用することに加えて、数学の学校のコースで勉強した全員が浮動小数点数を表す問題がまだそれに重畳されているため、詳細な記事

大まかに言えば、学校の数学のための通常のハーフアップアルゴリズムの代わりに、 ハーフ イーブンアルゴリズムが使用されます。これは、統計分析の歪みの可能性を低減するため、IEEE 754標準で推奨されています。







また、なぜ-22//10=-3



なのか理解できませんでしたが、別の親切な人 、これは必然的に数学的な定義自体に続くことを指摘しました。負の数。

アクトン! さて、これは再び奇妙なことであり、私は何も理解していません。このスレッドを参照してください。







正規表現のデバッグ



そしてここで、Pythonの世界には、優れた真珠モジュールRegexp :: Debuggerビデオプレゼンテーション )に似た正規表現をインタラクティブにデバッグするためのツールはありません、もちろんたくさんのオンラインツールがあり、Windows独自のソリューションがありますが、私にとってはそうではありませんおそらくpythonバーを使用する価値があります。Pythonのrexeはpearl barとそれほど変わらないので、pearl barを所有していない人のために説明を書きます。







 sudo apt install cpanminus cpanm Regexp::Debugger perl -I ~/perl5/lib/perl5/ -E "use Regexp::Debugger; 'ababc' =~ /(a|b) b+ c/x"
      
      





真珠に不慣れな人でも、行を入力する必要がある場所と、正規表現がどこにあるかを理解できると思いますx



はpython re.VERBOSEに似たフラグです。

s



を押して、 ドキュメント内の使用可能なコマンドの詳細な説明である正規表現をステップ実行します







ドキュメント



pythonには、ロードされた関数(docstringから取得)のヘルプを取得できるヘルプ関数があり、関数の名前がパラメーターとして渡されます。







 $ python3 >>> help(help)
      
      





しかし、これは必ずしも便利な方法ではなく、多くの場合、pydocユーティリティを使用する方が便利です。







 pydoc3 urllib.parse.urlparse
      
      





このユーティリティを使用すると、キーワードで検索したり、HTMLドキュメントでローカルサーバーを実行することもできますが、後者はテストされていません。








All Articles