Pythonistaのようなコード:慣用的なPython(パート1)

Kaa, the Python





これは、David Goodgerの記事「本物のPythonistのようにコードを書く:Pythonのイディオム」の翻訳の続きです。



翻訳の開始終了





最初の部分、貴重なコメント、肯定的なコメントを評価してくれたすべてのhabrayuzerに感謝します。 エラーを考慮に入れようとしましたが、再び建設的な議論を楽しみにしています。










可能な限り使用(1)





良い:



 dのキーの場合:
    印刷キー






悪い:

 d.keys()のキーの場合:
    印刷キー




これは、キー()メソッドを持つすべてのオブジェクトにも適用されます。





可能な限り使用(2)





ただし、辞書を変更する場合は.keys()が必要です



 d.keys()のキーの場合:
     d [str(キー)] = d [キー]




d.keys()は、辞書キーの静的リストを作成します。 そうしないと、例外「RuntimeError:dictionary changed size during iteration」(辞書のサイズが反復中に変更されました)が発生します。



dict.has_key()よりもdictでキーを使用する方が正しいです:



 #これを行う:
 dのキーの場合:
     ... d [キー]で何かをする

 #しかし、これは好きではありません:
 d.has_key(キー)の場合:
     ... d [キー]で何かをする


このコードは、inを演算子として使用します。



辞書メソッドを取得





多くの場合、使用する前にデータを辞書に取り込む必要があります。



これを行う単純な方法:



 navs = {}
データの(ポートフォリオ、エクイティ、ポジション):
    ポートフォリオがnavsにない場合:
         navs [ポートフォリオ] = 0
     navs [ポートフォリオ] + =ポジション*価格[株式]




dict.get(キー、デフォルト)はチェックを回避します:



 navs = {}
データの(ポートフォリオ、エクイティ、ポジション):
     navs [portfolio] =(navs.get(portfolio、0)
                        +ポジション*価格[株式])




これはより正確です。



辞書メソッドsetdefault(1)





ここで、非静的辞書の要素の値を初期化する必要があります。各要素はリストで表されます。 ここに別の素朴な方法があります:



可変ディクショナリの要素の初期化:

株式= {}
データの(ポートフォリオ、エクイティ):
    株式ポートフォリオの場合:
        株式[ポートフォリオ] .append(株式)
    その他:
        株式[ポートフォリオ] = [株式]


dict.setdefault(キー、デフォルト)は、これをより効率的に機能させます。



株式= {}
データの(ポートフォリオ、エクイティ):
     equities.setdefault(ポートフォリオ、[])。append(
                                         エクイティ)


dict.setdefault()は、「get、or install and get」(「get、or set&get」)と同等です。 または、「必要に応じて設定してから取得」(「必要に応じて設定してから取得」)。 これは、辞書キーの計算が困難な場合、またはキーボードからの入力が長い場合に特に効果的です。



dict.setdefault()に問題がある場合のみ、それが必要かどうかに関係なく、デフォルト値が常に計算されるということです。 これは、デフォルト値の計算が高価な場合に重要です。



デフォルト値の計算が難しい場合は、defaultdictクラスを使用する方が便利な場合があります。これについては簡単に検討します。



辞書メソッドsetdefault(2)





ここで、setdefaultメソッドがどのように個別に使用される式になるかを確認します。



 navs = {}
データの(ポートフォリオ、エクイティ、ポジション):
     navs.setdefault(ポートフォリオ、0)
     navs [ポートフォリオ] + =ポジション*価格[株式]




setdefault辞書メソッドはデフォルト値を返しますが、ここでは無視します。 初期化されていない辞書要素に値を割り当てるsetdefaultの副作用をバイパスします。



defaultdict



Python 2.5の新機能。



defaultdictは、collectionsモジュールの一部としてPython 2.5で登場しました。 defaultdictは、次の2つの点を除いて、通常の辞書と同じです。





defaultdictを取得する2つの方法を次に示します。



コレクションをインポートする
 d = collections.defaultdict(...)


コレクションからインポートdefaultdict
 d = defaultdict(...)




以下は、辞書の各要素が空のリストとして初期化され、defaultdictで書き換えられた前の例です。



コレクションからインポートdefaultdict

株式= defaultdict(リスト)
データの(ポートフォリオ、エクイティ):
    株式[ポートフォリオ] .append(株式)


この場合、生成関数リストは空のリストを返します。



この例は、デフォルト値= 0で辞書を取得する方法を示しています。これには、生成関数intが使用されます。

 navs = defaultdict(int)
データの(ポートフォリオ、エクイティ、ポジション):
     navs [ポートフォリオ] + =ポジション*価格[株式]




それでもdefaultdictには注意してください。 適切に初期化されたdefaultdictからKeyError例外を取得することはできません。 特定のキーを確認する必要がある場合は、「dict in key」条件を使用できます。



辞書の編集と分析



以下は、2つのリスト(またはシーケンス)の辞書をコンパイルするための便利なテクニックです。1つはキーのリスト、もう1つは値のリストです。



 given = ['John'、 'Eric'、 'Terry'、 'Michael']
 family = ['Cleese'、 'Idle'、 'Gilliam'、 'Palin']


 pythons = dict(zip(与えられた、家族))


 >>> pprint.pprint(pythons)
 {「ジョン」:「クリーズ」、
  「マイケル」:「パリン」、
  「エリック」:「アイドル」、
  「テリー」:「ギリアム」}




もちろん、その逆は簡単です。



 >>> pythons.keys()
 ['ジョン'、 'マイケル'、 'エリック'、 'テリー']
 >>> pythons.values()
 ['Cleese'、 'Palin'、 'Idle'、 'Gilliam']




結果の.keys()および.values()の順序は、辞書辞書が作成されたときの要素の順序とは異なることに注意してください。 入力順は出力順とは異なります。 これは、辞書が本質的に乱れているためです。 ただし、辞書が呼び出し間で変更されていない場合、出力の順序は可能な限り一貫していることが保証されます(キーの順序は値の順序に対応します)。

有効性チェック





 #これを行う:#このようにしない:
 if x:if x == True:
    パスパス




これは、Pythonオブジェクト(またはブール値)を検証するエレガントで効率的な方法です。

チェックリスト:



 #これを行う:#このようにしない:
 if items:if len(items)!= 0:
    パスパス

                   #そして間違いなく:
                   if items!= []:
                      合格する




真実の意味





TrueおよびFalseという名前は、組み込みのブール型のインスタンスです。 Noneと同様に、それぞれ1つのインスタンスのみが作成されます。



本当
偽(== 0) 真(== 1)
""(空の文字列) ""( ""、 "anything")を除く任意の文字列
0、0.0 0以外の任意の数字(1、0.1、-1、3.14)
[]、()、{}、()を設定 空でないコンテナ([0]、(なし、)、[''])
なし 明らかに偽ではないほとんどすべてのオブジェクト




オブジェクトの真実の価値の例:



 >>>クラスC:
 ...合格
 ...
 >>> o = C()
 >>> bool(o)
本当
 >>> bool(C)
本当


(例: truth.pyを実行します。)



ユーザー定義のクラスインスタンスの有効性を制御するには、特別な__nonzero__または__len__メソッドを使用します。 クラスが長さのコンテナである場合は__len__を使用します。

クラスMyContainer(オブジェクト):

     def __init __(自己、データ):
         self.data = data

     def __len __(自己):
         "" "長さを返す。" ""
         return len(self.data)


クラスがコンテナでない場合は、__ nonzero__を使用します。



クラスMyClass(オブジェクト):

     def __init __(自己、値):
         self.value = value

     def __nonzero __(自己):
         "" "真理値(TrueまたはFalse)を返します。" ""
         #これは任意に複雑になる可能性があります。
         bool(self.value)を返します




Python 3.0では、組み込みのブール型との一貫性を保つために、__ nonzero__は__bool__に名前が変更されました。 互換性のために、このコードをクラス定義に追加します。



 __bool__ = __nonzero__




インデックスとアイテム(1)





入力したテキストを単語のリストに保存するための注意深い方法を次に示します。



 >>> items = 'zero one two three'.split()
 >>>印刷アイテム
 [「ゼロ」、「1」、「2」、「3」]




要素を繰り返し処理したい場合、要素自体とそのインデックスの両方が必要だとしましょう:



                   -または-
 i = 0
アイテム内のアイテムの場合:for i in range(len(items)):
    印刷i、アイテム印刷i、アイテム[i]
     i + = 1




インデックスとアイテム(2):列挙





列挙関数は引数としてリストを取り、ペア(インデックス、アイテム)(番号、要素)を返します。



 >>>リストを印刷(列挙(アイテム))
 [(0、 'zero')、(1、 'one')、(2、 'two')、(3、 'three')]




enumerateは怠fullな関数であるため、完全な結果を得るためにリストに変換する必要があります。1回の呼び出しで1つの要素を生成します。 forループは、リストを反復処理し、パスごとに1つの結果を呼び出す場所です。 enumerateはジェネレーターの例です。これについては後で詳しく説明します。 printは一度に1つの結果を受け入れません。一般的な結果が必要なため、印刷する場合は明示的にジェネレーターをリストに変換する必要があります。



私たちのサイクルはもっと簡単になります:



 for(インデックス、アイテム)in enumerate(アイテム):
    印刷インデックス、アイテム


 #比較:#比較:
範囲内のiのインデックス= 0(len(アイテム)):
アイテムのアイテム:印刷i、アイテム[i]
    印刷インデックス、アイテム
    インデックス+ = 1




enumerateバリアントは、左側のメソッドよりも大幅に短くシンプルであり、読みやすく、理解しやすいです。



列挙関数が実際にイテレータを返す方法を示す例(ジェネレータはイテレータの一種です):

 >>>列挙(アイテム)
 <0x011EA1C0のオブジェクトを列挙>;
 >>> e =列挙(アイテム)
 >>> e.next()
 (0、「ゼロ」)
 >>> e.next()
 (1、 '1')
 >>> e.next()
 (2、「2」)
 >>> e.next()
 (3、「3」)
 >>> e.next()
トレースバック(最後の最後の呼び出し):
  ファイル「<stdin>」、1行目?
 StopIteration




他の言語には「変数」があります



他の多くの言語では、変数の割り当てによって値がセルに配置されます。



  int a = 1; 


a1box.png





セル「a」には整数1が含まれるようになりました。



同じ変数に別の値を割り当てると、セルの内容が置き換えられます。

  a = 2; 


a2box.png





セル「a」には整数2が含まれています。



ある変数を別の変数に割り当てると、値のコピーが作成され、新しいセルに配置されます。



  int b = a; 


b2box.png

a2box.png



「B」は整数2のコピーを持つ2番目のセルです。セル「a」には別のコピーがあります。



Pythonには「名前」があります



Pythonでは、「名前」または「識別子」はオブジェクトに付けられたラベル(タグ、ラベル)のようなものです。

  a = 1 


a1tag.png



ここでは、全体にラベル「a」が付いています。



「a」を再割り当てする場合、ショートカットを別のオブジェクトに移動するだけです。

  a = 2 


a2tag.png

1.png





これで、名前「a」がオブジェクト全体に付加されます2。

整数1のソースオブジェクトには、ラベル「a」がなくなりました。 彼はもう少し長生きするかもしれませんが、「a」という名前で彼を見つけることはできません。 オブジェクトにリンクまたはラベルがなくなると、メモリから削除されます。



ある名前を別の名前に割り当てる場合、既存のオブジェクトに別のラベルを付けるだけです。

  b = a 


ab2tag.png





「b」という名前は、「a」と同じオブジェクトに割り当てられた2番目のラベルです。



Pythonでは通常「変数」と言いますが(一般的には専門用語として受け入れられているため)、実際には「名前」または「識別子」を意味します。 Pythonでは、「変数」は名前付きセルではなく、値への参照です。



このチュートリアルからまだ何も受け取っていない場合は、Pythonで名前がどのように機能するかを理解してください。 明確な理解は間違いなく良い仕事をし、このようなケースを避けるのに役立ちます:

(何らかの理由で、サンプルコードがありません-約transl。)



デフォルトのパラメーター値





これは初心者がよく犯すよくある間違いです。 Pythonで十分な名前を理解していない場合でも、より高度なプログラマはそれを許可します。



 def bad_append(new_item、a_list = []):
     a_list.append(new_item)
     a_listを返す




ここでの問題は、空のリストであるa_listのデフォルト値は、関数の定義時にのみ計算されることです。 そうすれば、関数を呼び出すたびに、同じデフォルト値が得られます。 これを数回試してください:



 >>> bad_append( 'one')を印刷します
 ['one']


 >>> bad_append( 'two')を出力します
 ['one'、 'two']




リストは変更可能なオブジェクトであり、その内容を変更できます。 デフォルトのリスト(辞書またはセット)を取得する正しい方法は、関数宣言ではなく実行時に作成することです。



 def good_append(new_item、a_list =なし):
     a_listがNoneの場合:
         a_list = []
     a_list.append(new_item)
     a_listを返す




%文字列のフォーマット





Pythonでは、%演算子はCのsprintf関数のように機能します。



ただし、Cがわからない場合は、ほとんどわかりません。 一般に、テンプレートまたは形式を指定し、値を置き換えます。



この例では、テンプレートには2つのプレゼンテーション仕様が含まれています。「%s」は「文字列をここに挿入」を意味し、「%i」は「整数を文字列に変換してここに貼り付け」を意味します。 「%s」は、Pythonの組み込みstr()関数を使用してオブジェクトを文字列に変換するため、特に便利です。



置換値はパターンと一致する必要があります。 ここでは、2つの値がタプルにコンパイルされています。

名前= 'David'
メッセージ= 3
 text =( 'Hello%s、you have%i messages'
         %(名前、メッセージ))
印刷テキスト




結論:

こんにちはデビッド、メッセージが3つあります




詳細については、 Pythonライブラリリファレンス 、セクション2.3.6.2、「文字列のフォーマット操作」を参照してください。 ブックマークしてください!

まだ行っていない場合は、python.orgに移動し、HTMLドキュメント(.zipなど)をダウンロードして、マシンにインストールします。 あなたの指先で完全なガイダンスを持っている以上に便利なものはありません。



高度な%文字列フォーマット





多くの人は、文字列をフォーマットする他のより柔軟な方法があることを知りません:



辞書付きの名前:



値= {「名前」:名前、「メッセージ」:メッセージ}
 print( 'Hello%(name)s、you have%(messages)i'
        「メッセージ」%値)




ここでは、辞書で検索される置換値の名前を定義します。



冗長性に気づきましたか? 名前「name」と「messages」はローカルですでに定義されています

名前空間。 改善できます。

ローカル名前空間を使用した名前:

 print( 'Hello%(name)s、you have%(messages)i'
        'messages'%locals())




locals()関数は、ローカル名前空間で利用可能なすべての識別子の辞書を返します。



これは非常に強力なツールです。 これにより、テンプレート内の置換値の一致を心配することなく、必要に応じてすべての行をフォーマットできます。

しかし、注意してください。 (「大きな力で、大きな責任が伴います。」)外部に関連する文字列パターンでlocals()を使用する場合、呼び出し側にローカル名前空間を提供します。 それはあなたが知っていることだけです。

ローカル名前空間を確認するには:

 >>> pprint import pprintから
 >>> pprint(ローカル())


pprintも便利な機能です。 まだわからない場合は、彼女と遊んでみてください。 データ構造のデバッグがはるかに簡単になります!



高度な%文字列フォーマット





オブジェクトのインスタンスの属性の名前空間は、単なる辞書、self .__ dict__です。



インスタンス名前空間を使用した名前:



 print(「%(error_count)d個のエラーが見つかりました」
        %self .__ dict__)




同等ですが、以下よりも柔軟性があります:



印刷(「%d個のエラーが見つかりました」
        %self.error_count)




注:クラス__dict__のクラス属性。 名前空間の検索は、実際には辞書検索です。



翻訳の最後の部分。



All Articles