Pythonの隠し機能[終了]


1419

Pythonプログラミング言語のあまり知られていないが便利な機能は何ですか?

  • Pythonコアへの回答を制限してください。
  • 回答ごとに1つの機能。
  • ドキュメントへのリンクだけでなく、機能の例と短い説明を提供します。
  • タイトルを最初の行として使用して、フィーチャにラベルを付けます。

回答へのクイックリンク:

回答:


740

比較演算子の連鎖:

>>> x = 5
>>> 1 < x < 10
True
>>> 10 < x < 20 
False
>>> x < 10 < x*10 < 100
True
>>> 10 > x <= 9
True
>>> 5 == x > 4
True

場合は、あなたがそれをやって考えている1 < xと出てくるこれは、Trueそれから、と比較しないTrue < 10でもある、True何が起こるか本当にないこと、そして何も、それは本当にに翻訳しています(。最後の例を参照)1 < x and x < 10、およびx < 10 and 10 < x * 10 and x*10 < 100、あまりタイピングとそれぞれに用語は一度だけ評価されます。


121
それはとても役に立ちます。すべての言語の標準である必要があります。残念ながらそうではありません。
stalepretzel 2008年

8
同様にfalseを返すいくつかの例を追加する必要があります。例>>> 10 <x <20 False
ShoeLace

19
これは他の比較演算子にも当てはまります。そのため、([5]の5がTrueのような)コードがFalseであることに人々が驚かされる場合があります(ただし、最初にそのようなブール値に対して明示的にテストすることは、Pythonではありません)。
マイル

19
良いですが、 'in'や '='のような同等の優先度に注意してください。「A in B == C in D」は、((A in B)および(B == C)および(C in D))を意味しますが、これは予期しないものです。
Charles Merriam、

15
Azafe:Lispの比較は当然このように機能します。解釈する他の(合理的な)方法がないため、これは特別なケースではありません(< 1 x 10)。あなたも同じように、単一の引数に適用することができます(= 10)cs.cmu.edu/Groups/AI/html/hyperspec/HyperSpec/Body/...
ケン

512

Python正規表現解析ツリーを取得して、正規表現をデバッグします。

正規表現はpythonの優れた機能ですが、それらをデバッグするのは面倒な場合があり、正規表現を間違えるのは簡単すぎます。

幸い、Pythonは、文書化されていない実験的な隠しフラグre.DEBUG(実際には128)をに渡すことにより、正規表現解析ツリーを出力できますre.compile

>>> re.compile("^\[font(?:=(?P<size>[-+][0-9]{1,2}))?\](.*?)[/font]",
    re.DEBUG)
at at_beginning
literal 91
literal 102
literal 111
literal 110
literal 116
max_repeat 0 1
  subpattern None
    literal 61
    subpattern 1
      in
        literal 45
        literal 43
      max_repeat 1 2
        in
          range (48, 57)
literal 93
subpattern 2
  min_repeat 0 65535
    any None
in
  literal 47
  literal 102
  literal 111
  literal 110
  literal 116

構文を理解したら、エラーを見つけることができます。私たちは、私が脱出するのを忘れたことはあり見ることができます[]では[/font]

もちろん、コメント付きの正規表現など、必要なフラグと組み合わせることができます。

>>> re.compile("""
 ^              # start of a line
 \[font         # the font tag
 (?:=(?P<size>  # optional [font=+size]
 [-+][0-9]{1,2} # size specification
 ))?
 \]             # end of tag
 (.*?)          # text between the tags
 \[/font\]      # end of the tag
 """, re.DEBUG|re.VERBOSE|re.DOTALL)

3
正規表現を使用してHTMLを解析するのは遅くて面倒です。組み込みの「html」パーサーモジュールでさえ、正規表現を使用して作業を完了しません。そして、htmlモジュールが気に入らない場合は、ホイールを再発明することなく作業を行うXML / HTMLパーサーモジュールがたくさんあります。
BatchyX 2010年

出力構文に関するドキュメントへのリンクはすばらしいでしょう。
Personman 2010

1
これは実験的なものではなく、Pythonの公式部分である必要があります... RegExは常にトリッキーであり、起こっていることを追跡できることは本当に役に立ちます。
Cahit

460

列挙する

イテレート可能オブジェクトをenumerateでラップすると、アイテムがインデックスとともに生成されます。

例えば:


>>> a = ['a', 'b', 'c', 'd', 'e']
>>> for index, item in enumerate(a): print index, item
...
0 a
1 b
2 c
3 d
4 e
>>>

参照:


56
これがPythonリストについて話すチュートリアルでは日常的に取り上げられていないことに驚いています。
ドラえもん

45
そして、今までずっと私はこのようにコーディングしていました:for i in range(len(a)):...次に、a [i]を使用して現在のアイテムを取得します。
フェルナンドマーティン

4
@Berry Tsakala:私の知る限りでは、これは廃止されていません。
JAB、

23
これは素晴らしいです。xrange(len(a))のi:は、私の最も好きでないpythonイディオムです。
Personman 2010

15
「列挙内の項目(iについて:列挙は、任意のインデックスではなく、必要に応じて0実施例から開始することができるリスト、1 =開始):I、項目印刷」は0、1から列挙を開始する
dmitry_romanov

419

ジェネレーターオブジェクトの作成

あなたが書くなら

x=(n for n in foo if bar(n))

ジェネレータを取り出してxに割り当てることができます。今それはあなたができることを意味します

for n in x:

これの利点は、必要な場合に必要となる中間ストレージが不要になることです。

x = [n for n in foo if bar(n)]

場合によっては、これにより速度が大幅に向上することがあります。

多くのifステートメントをジェネレーターの最後に追加して、基本的にネストされたforループを複製できます。

>>> n = ((a,b) for a in range(0,2) for b in range(4,6))
>>> for i in n:
...   print i 

(0, 4)
(0, 5)
(1, 4)
(1, 5)

ネストされたリスト内包表記を使用することもできますか?
shapr 2009

54
特に注目すべきは、メモリのオーバーヘッドの節約です。値はオンデマンドで計算されるため、リスト内包の結果全体をメモリに保持することはできません。これは、後でリスト内包の一部のみを反復する場合に特に望ましいです。
saffsd 2009年

19
これは特に「隠された」イモではありませんが、ジェネレータオブジェクトを巻き戻すことができなかったのに対し、リストを何度でも繰り返すことができるという事実も注目に値します。
2010

13
ジェネレーターの「巻き戻しなし」機能により、混乱が生じる可能性があります。具体的には、ジェネレーターの内容をデバッグ用に出力し、後でそれを使用してデータを処理する場合、機能しません。データは生成され、print()によって消費されます。その後、通常の処理では使用できません。リスト内包表記は完全にメモリに格納されるため、これはリスト内包表記には適用されません。
johntellsall 2010年

4
同様の(dup?)回答:stackoverflow.com/questions/101268/hidden-features-of-python/…ただし、ここでリンクした回答は、ジェネレーターのパワーに関する非常に優れたプレゼンテーションについて言及していることに注意してください。ぜひチェックしてみてください。
DenilsonSáMaia

353

iter()は呼び出し可能な引数を取ることができます

例えば:

def seek_next_line(f):
    for c in iter(lambda: f.read(1),'\n'):
        pass

iter(callable, until_value)この関数は、繰り返し呼び出すcallableとまではその結果が得られuntil_value返されます。


Pythonの初心者として、lambdaここでキーワードが必要な理由を説明していただけますか?
SiegeX 2011

ラムダなしの@ SiegeX、f.read(1)は、iter関数に渡される前に評価(文字列を返す)されます。代わりに、ラムダは無名関数を作成してiterに渡します。
jmilloy 2011

339

変更可能なデフォルト引数に注意してください

>>> def foo(x=[]):
...     x.append(1)
...     print x
... 
>>> foo()
[1]
>>> foo()
[1, 1]
>>> foo()
[1, 1, 1]

代わりに、「指定されていません」を示すセンチネル値を使用して、デフォルトとして希望する変更可能な変数に置き換えます。

>>> def foo(x=None):
...     if x is None:
...         x = []
...     x.append(1)
...     print x
>>> foo()
[1]
>>> foo()
[1]

39
これは間違いなく、厄介な隠し機能の1つです。私は時々それに遭遇しました。
Torsten Marek

77
これは、デフォルトの引数が関数の属性であるタプルに含まれていることを知ったときに、はるかに理解しやすくなりましたfoo.func_defaults。タプルであることは不変です。
Robert Rossney、2009年

2
@grayger:defステートメントが実行されると、その引数はインタープリターによって評価されます。これにより、コードオブジェクト(関数のスイート)に名前が作成(または再バインド)されます。ただし、デフォルトの引数は、定義時にオブジェクトとしてインスタンス化されます。これはデフォルトのオブジェクトのどの場合にも当てはまりますが、オブジェクトが変更可能である場合にのみ重要です(可視のセマンティクスを公開します)。関数のクロージャでそのデフォルトの引数名を再バインドする方法はありませんが、呼び出しでオーバーライドしたり、関数全体を再定義したりできます)。
ジム・デニス

3
@Robertはもちろん引数タプルは不変である可能性がありますが、それが指すオブジェクトは必ずしも不変であるとは限りません。
poolie 2010

16
初期化を少し短くするための簡単なハック:x = xまたは[]。2行のifステートメントの代わりにそれを使用できます。
デイブマンコフ

317

ジェネレータ関数に値を送信します。たとえば、次の機能があります。

def mygen():
    """Yield 5 until something else is passed back via send()"""
    a = 5
    while True:
        f = (yield a) #yield a and possibly get f in return
        if f is not None: 
            a = f  #store the new value

あなたはできる:

>>> g = mygen()
>>> g.next()
5
>>> g.next()
5
>>> g.send(7)  #we send this back to the generator
7
>>> g.next() #now it will yield 7 until we send something else
7

同意した。:)のPythonの隠された機能の厄介な例として、レッツ・御馳走この
ラファウDowgird

89
他の言語では、この魔法の装置は「変数」と呼ばれていると思います。
finnw 2009

5
コルーチンはコルーチンである必要があり、ジェネレーターも混合せずに、それ自体もコルーチンでなければなりません。メガグレートリンクとこれについての話と例はこちら:dabeaz.com/coroutines
u0b34a0f6ae

31
@finnw:この例では、変数に似たものを実装しています。ただし、この機能は他の多くの方法で使用できます...変数とは異なります。オブジェクト(特にPythonのcallメソッドを実装するクラス)を使用して同様のセマンティクスを実装できることも明らかです。
ジム・デニス

4
これは、コルーチンを一度も見たことがない(そしておそらく理解できない)人々にとって、取るに足らない例です。合計変数のオーバーフローのリスクなしに移動平均を実装する例は良い例です。
Prashant Kumar

313

スコープを示すために空白を使用したくない場合は、次のコマンドを発行してCスタイルの{}を使用できます。

from __future__ import braces

122
それは悪だ。:)
ジェイソン・ベイカー

37
>>> from __future__ import中かっこファイル "<stdin>"、1行目SyntaxError:チャンスではありません:P
ベンジャミンW.スミス

40
それは冒涜です!
バークD.デミール

335
ここに構文上の間違いがあると思いますが、「from __past__ import braces」ではないでしょうか?
ビルK

47
__cruft__インポートブレース
フィリップBオルダム

305

スライス演算子のステップ引数。例えば:

a = [1,2,3,4,5]
>>> a[::2]  # iterate over the whole list in 2-increments
[1,3,5]

特殊なケースx[::-1]は、「x反転」の便利なイディオムです。

>>> a[::-1]
[5,4,3,2,1]

31
私の意見では、reversed()関数の方がはるかに明確です。>>> list(reversed(range(4)))[
3、2、1、0

3
次に、「このia文字列」[::-1]をより適切に記述する方法を教えてください。逆転しても役に立たないようです
ベリーTsakala 2009年

24
reverse()の問題は、イテレータを返すことです。そのため、逆のシーケンスのタイプ(タプル、文字列、リスト、ユニコード、ユーザータイプ...)を保持したい場合は、それを元に戻す追加の手順が必要です。 。
ラファウDowgird

6
def reverse_string(string):return string [::-1]
pi。

4
@piあなたが持っている通りにreverse_stringを定義するのに十分知っているなら、[::-1]をコードに残して、その意味と適切な感じに慣れることができると思います。
physicsmichael 2010年

289

デコレータ

デコレーターを使用すると、機能やメソッドを別の関数にラップして、機能を追加したり、引数や結果を変更したりすることができます。

例はprint_args、修飾された関数の引数を呼び出す前に出力するデコレーターを示しています。

>>> def print_args(function):
>>>     def wrapper(*args, **kwargs):
>>>         print 'Arguments:', args, kwargs
>>>         return function(*args, **kwargs)
>>>     return wrapper

>>> @print_args
>>> def write(text):
>>>     print text

>>> write('foo')
Arguments: ('foo',) {}
foo

54
デコレーターを定義するときは、@ decoratorでデコレーターを装飾することをお勧めします。イントロスペクションを行うときに関数のシグネチャを保持するデコレータを作成します。詳細はこちら:phyast.pitt.edu/~micheles/python/documentation.html
サーワート

45
これはどのように隠された機能ですか?
Vetle、2008年

50
まあ、ほとんどの単純なPythonチュートリアルには含まれていません。Pythonを使い始めてから長い間、偶然見つけました。それは私が隠し機能と呼ぶもので、ここの他のトップの投稿とほとんど同じです。
DzinX 2008年

16
質問者は「Pythonプログラミング言語のあまり知られていないが便利な機能」を求めています。「あまり知られていないが便利な機能」をどのように測定しますか?これらの応答のどれが隠された機能なのですか?
Johnd、2009年

4
@vetlerここにあるもののほとんどはほとんど「隠されています」。
ハンフリーボガート

288

for ... else構文(http://docs.python.org/ref/for.htmlを参照)

for i in foo:
    if i == 0:
        break
else:
    print("i was never 0")

「else」ブロックは、breakが呼び出されない限り、通常はforループの最後に実行されます。

上記のコードは次のようにエミュレートできます。

found = False
for i in foo:
    if i == 0:
        found = True
        break
if not found: 
    print("i was never 0")

218
for / else構文は扱いにくいと思います。ループの本体が実行されない場合、else句を実行する必要があるかのように「感じ」ます。
codeape、2008年

14
ああ。見たことない!しかし、私はそれが少し誤った名称であると言わなければなりません。ブレークが決して実行しない場合にのみ、elseブロックが実行されることを誰が期待しますか?codeapeに同意します。空のfooに対してはelseが入力されているようです。
ダレン・トーマス

52
キーワードは最終的にそうでなければならないようです
ジャアロ09年

21
最終的に例外ですが、そのスイートが常に実行される方法ですでに使用されています。

7
間違いなく 'else'であってはなりません。'then'か何か、そしてループが一度も実行されなかったときのための 'else'かもしれません。
Tor Valamo

258

2.5以降、dictsには、__missing__不足しているアイテムに対して呼び出される特別なメソッドがあります。

>>> class MyDict(dict):
...  def __missing__(self, key):
...   self[key] = rv = []
...   return rv
... 
>>> m = MyDict()
>>> m["foo"].append(1)
>>> m["foo"].append(2)
>>> dict(m)
{'foo': [1, 2]}

また、ほとんど同じように機能しますが、既存の項目ではなく引数なしで関数を呼び出す、dictサブクラスがcollections呼び出されdefaultdictます。

>>> from collections import defaultdict
>>> m = defaultdict(list)
>>> m["foo"].append(1)
>>> m["foo"].append(2)
>>> dict(m)
{'foo': [1, 2]}

そのようなサブクラスを期待しない関数に渡す前に、そのようなディクテーションを通常のディクテーションに変換することをお勧めします。多くのコードはd[a_key]、KeyErrorを使用およびキャッチして、新しいアイテムをdictに追加するアイテムが存在するかどうかを確認します。


10
私はsetdefaultを使用することを好みます。m = {}; m.setdefault( 'foo'、1)
グレーな2009

22
@graygerはこれを意味していましたm={}; m.setdefault('foo', []).append(1)
クリスティアンCiupitu

1
ただし、defaultdictを渡すと非常に便利な場合があります。たとえば、デフォルトでは空のリストであるため、関数は値を反復処理し、追加のコードなしで未定義のキーに対して機能します。
マリアン

3
defaultdictは、キーが欠落していない限りデフォルトオブジェクトを作成しないため、setdefaultよりも状況によっては優れています。setdefaultは、それが欠落しているかどうかに関係なくそれを作成します。デフォルトのオブジェクトを作成するのにコストがかかる場合、これはパフォーマンスに影響を与える可能性があります-すべてのsetdefault呼び出しを変更するだけで、1つのプログラムからまともなスピードアップが得られました。
Whatang

2
defaultdictsetdefault他の場合の方法よりも強力です。たとえば、カウンターの場合- dd = collections.defaultdict(int) ... dd[k] += 1d.setdefault(k, 0) += 1
Mike Graham

247

インプレース値スワッピング

>>> a = 10
>>> b = 5
>>> a, b
(10, 5)

>>> a, b = b, a
>>> a, b
(5, 10)

割り当ての右側は、新しいタプルを作成する式です。割り当ての左側は、その(参照されていない)タプルを名前aとに直ちにアンパックしbます。

割り当て後、新しいタプルは参照されず、ガベージコレクションのマークが付けられ、値がバインドされabスワップされます。

データ構造に関するPythonチュートリアルセクションで述べたように、

複数の割り当ては、実際にはタプルのパッキングとシーケンスのアンパッキングの組み合わせにすぎないことに注意してください。


1
これは従来の方法よりも多くの実メモリを使用しますか?スワップ変数を1つだけではなくタプルを作成しているので、私はそう思います
Nathan

75
それはより多くのメモリを使用しません。使用量は少ないです。私はそれを両方の方法で記述し、バイトコードを逆コンパイルしました。コンパイラーは最適化しました。disの結果は、varsを設定してからROT_TWOingを行っていることを示しています。ROT_TWOは、「最上位の2つのスタック変数を入れ替える」ことを意味します...実際にはかなりおしゃれです。
ロイヤル、

5
また、うっかりしてPythonの別の優れた機能を指摘します。これは、コンマで区切るだけで暗黙的に項目のタプルを作成できることです。
asmeurer 2010

3
Dana the Sane:Pythonでの代入は式ではなくステートメントなので、=の方が優先度が高い(つまり、a、(b = b)、aと解釈された)場合、式は無効になります。
hbn 2011年

5
これは私がここで読んだ最も隠された機能です。いいですが、すべてのPythonチュートリアルで明示的に説明されています。
チアゴチャベス'25年

235

読みやすい正規表現

Pythonでは、正規表現を複数の行に分割し、一致に名前を付け、コメントを挿入できます。

詳細な構文の例(DiveからPythonへ):

>>> pattern = """
... ^                   # beginning of string
... M{0,4}              # thousands - 0 to 4 M's
... (CM|CD|D?C{0,3})    # hundreds - 900 (CM), 400 (CD), 0-300 (0 to 3 C's),
...                     #            or 500-800 (D, followed by 0 to 3 C's)
... (XC|XL|L?X{0,3})    # tens - 90 (XC), 40 (XL), 0-30 (0 to 3 X's),
...                     #        or 50-80 (L, followed by 0 to 3 X's)
... (IX|IV|V?I{0,3})    # ones - 9 (IX), 4 (IV), 0-3 (0 to 3 I's),
...                     #        or 5-8 (V, followed by 0 to 3 I's)
... $                   # end of string
... """
>>> re.search(pattern, 'M', re.VERBOSE)

名前の一致の例(正規表現HOWTOから)

>>> p = re.compile(r'(?P<word>\b\w+\b)')
>>> m = p.search( '(((( Lots of punctuation )))' )
>>> m.group('word')
'Lots'

re.VERBOSE文字列リテラル連結のおかげで、使用せずに詳細に正規表現を書くこともできます。

>>> pattern = (
...     "^"                 # beginning of string
...     "M{0,4}"            # thousands - 0 to 4 M's
...     "(CM|CD|D?C{0,3})"  # hundreds - 900 (CM), 400 (CD), 0-300 (0 to 3 C's),
...                         #            or 500-800 (D, followed by 0 to 3 C's)
...     "(XC|XL|L?X{0,3})"  # tens - 90 (XC), 40 (XL), 0-30 (0 to 3 X's),
...                         #        or 50-80 (L, followed by 0 to 3 X's)
...     "(IX|IV|V?I{0,3})"  # ones - 9 (IX), 4 (IV), 0-3 (0 to 3 I's),
...                         #        or 5-8 (V, followed by 0 to 3 I's)
...     "$"                 # end of string
... )
>>> print pattern
"^M{0,4}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$"

7
Pythonの機能を本当に検討するかどうかはわかりませんが、ほとんどのREエンジンには詳細オプションがあります。
ジェレミーバンクス

18
はい。ただし、grepやほとんどのエディターでは実行できないため、多くの人はそれが存在することを知りません。他の言語にも同等の機能があるという事実は、それをPythonの有用でほとんど知られていない機能にしないわけではありません
Mark Ba​​ker

7
最適化された正規表現がたくさんある大規模なプロジェクト(読み取り:人間向けではなく、マシン向けに最適化されています)で、弾丸を噛み、それらすべてを詳細な構文に変換しました。これで、新しい開発者をプロジェクトに紹介することがはるかに簡単になりました。これからは、すべてのプロジェクトに冗長REを適用します。
バークD.デミール

私はむしろ言いたい:数百= "(CM | CD | D?C {0,3})"#900(CM)、400(CD)など。言語にはすでに名前を付ける方法があります。コメントを追加する方法、および文字列を組み合わせる方法。言語がすでに完全にうまく機能しているものに、なぜここで特別なライブラリ構文を使用するのですか?Perlisのエピグラム9に直接反するようです
ケン

3
@ケン:正規表現は常に直接ソースにあるとは限りません。設定または構成ファイルから読み取ることができます。コメントまたは追加の空白(読みやすくするため)を許可することは、非常に役立ちます。

222

関数引数の解凍

*およびを使用して、関数の引数としてリストまたは辞書をアンパックできます**

例えば:

def draw_point(x, y):
    # do some magic

point_foo = (3, 4)
point_bar = {'y': 3, 'x': 2}

draw_point(*point_foo)
draw_point(**point_bar)

リスト、タプル、辞書はコンテナとして広く使用されているため、非常に便利なショートカットです。


27
*スプラット演算子としても知られています
ガブリエル

3
私はこの機能が好きですが、pylintは悲しくありません。
スティーブンポールガー

5
ピリントの助言は法律ではない。もう1つの方法は、apply(callable、a​​rg_seq、arg_map)であり、2.3以降は非推奨です。
Yann Vernier

1
pylintのアドバイスは法律ではないかもしれませんが、それは良いアドバイスです。このようなことをやり過ぎるデバッグコードは、まさに地獄です。元の投稿者のメモにあるとおり、これは便利なショートカットです。
Andrew、

2
私はこれがコードで一度使用されているのを見て、それが何をするのか疑問に思いました。残念ながら、「Python **」でグーグル検索するのは困難です
Fraser Graham

205

コードファイルの先頭で適切なコーディング宣言を使用する場合、ROT13はソースコードの有効なエンコーディングです。

#!/usr/bin/env python
# -*- coding: rot13 -*-

cevag "Uryyb fgnpxbiresybj!".rapbqr("rot13")

10
すごい!バイト文字列が文字どおりに取得される方法に注意してください。ただし、Unicode文字列はデコードされます:trycevag h"Uryyb fgnpxbiresybj!"
u0b34a0f6ae

12
残念ながら、py3kから削除されます
mykhal

9
これはアンチウイルスをバイパスするのに適しています。
L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳

96
それはエンコーディングとは何の関係もありません。ウェールズ語で書かれた単なるPythonです。:-P
Olivier Verdier

33
Ph'nglui mglw'nafh Cthulhu R'lyeh wgah'nagl fhtagn!
Manuel Ferreria、2010

183

完全に動的な方法で新しいタイプを作成する

>>> NewType = type("NewType", (object,), {"x": "hello"})
>>> n = NewType()
>>> n.x
"hello"

これはまったく同じです

>>> class NewType(object):
>>>     x = "hello"
>>> n = NewType()
>>> n.x
"hello"

おそらく最も役立つものではありませんが、知っておくと便利です。

編集:新しいタイプの名前を修正しました。ステートメントNewTypeとまったく同じになるようにする必要がありますclass

編集:機能をより正確に説明するようにタイトルを調整しました。


8
これには、JIT ORMなどの有用性の可能性がたくさんあります
Mark Cidade

8
動的入力に基づいてHTMLフォームクラスを生成するために使用します。非常に素晴らしい!
pi。

15
注:すべてのクラスは実行時に作成されます。したがって、 'class'ステートメントを条件内または関数内で使用できます(クラスのファミリーまたはクロージャーとして機能するクラスの作成に非常に役立ちます)。「タイプ」がもたらす改善は、動的に生成された属性(またはベース)のセットを適切に定義する機能です。
不気味な

1
type( ''、(object、)、{'x': 'blah'})
bluehavana

3
コードインジェクションに非常に役立ちます。
Avihu Turzion

179

コンテキストマネージャと " with"ステートメント

PEP 343で導入でたコンテキストマネージャーは、一連のステートメントのランタイムコンテキストとして機能するオブジェクトです。

この機能は新しいキーワードを利用するため、段階的に導入されています。Python2.5では、 __future__。ディレクティブを。Python 2.6以降(Python 3を含む)では、デフォルトで使用可能です。

「with」ステートメントを使用しました非常に便利な構成だと思うのでます。簡単なデモをます。

from __future__ import with_statement

with open('foo.txt', 'w') as f:
    f.write('hello!')

ここで舞台裏で起こっていることは、「with」ステートメントが特別な__enter____exit__ファイルオブジェクトのメソッドとメソッドをことです。例外の詳細は__exit__、withステートメント本体から例外が発生した場合にも渡され、そこで例外処理を実行できます。

これは、この特定のケースであなたのために何をするかは、実行が範囲外にあるときにファイルが閉じられることを保証することです withが正常に発生したか例外がスローされたかに関係なくスイートられることです。これは基本的に、一般的な例外処理コードを抽象化する方法です。

これの他の一般的な使用例には、スレッドによるロックやデータベーストランザクションなどがあります。


3
futureからインポートしたコードレビューは承認しません。これらの機能は便利なものよりも可愛く、通常はPythonの初心者を混乱させるだけです。
有料オタク

6
はい、ネストされたスコープやジェネレータなどの「かわいい」機能は、何をしているのかを知っている人に任せた方がよいでしょう。そして、Pythonの将来のバージョンとの互換性を希望する人。ネストされたスコープとジェネレータの場合、Pythonの「将来のバージョン」はそれぞれ2.2と2.5を意味します。withステートメントの場合、Pythonの「将来のバージョン」は2.6を意味します。
クリスB.

10
これは言うまでもないかもしれませんが、Python v2.6以降では今後からインポートする必要はありません。withがファーストクラスのキーワードになりました。
フィッツジェラルドスティール

25
2.7では、複数にすることができますwiths:) with open('filea') as filea and open('fileb') as fileb: ...
オースティンリチャードソン

5
@オースティン私はその構文を2.7で動作させることができませんでした。これは、しかし、仕事がなかった: with open('filea') as filea, open('fileb') as fileb: ...
WIM

168

辞書にはget()メソッドがあります

辞書には「get()」メソッドがあります。d ['key']を実行してもkeyが存在しない場合は、例外が発生します。d.get( 'key')を実行すると、 'key'がない場合はNoneが返されます。2番目の引数を追加して、Noneの代わりにそのアイテムを取得できます。例:d.get( 'key'、0)。

数字の加算などに最適です。

sum[value] = sum.get(value, 0) + 1


39
また、setdefaultメソッドをチェックアウトします。
ダレントーマス

27
また、collections.defaultdictクラスをチェックアウトします。
jfs 2008年

8
Python 2.7以降、または3.1以降を使用している場合は、コレクションモジュールのCounterクラスを確認してください。docs.python.org/library/collections.html#collections.Counter
エリアスザマリア

ああ、これまでずっとやってきたget(key, None)Noneデフォルトで提供されていることを知りませんでした。
ジョーダンライター

152

記述子

これらは、Pythonのコア機能全体の背後にある魔法です。

ドットアクセスを使用してメンバー(xyなど)を検索すると、Pythonは最初にインスタンスディクショナリでメンバーを検索します。見つからない場合は、クラスディクショナリで検索します。クラスディクショナリで見つかった場合、オブジェクトは記述子プロトコルを実装し、それを返すだけでなく、Pythonがそれを実行します。記述子は、実装するすべてのクラスである__get____set__または__delete__方法を。

記述子を使用して独自の(読み取り専用)バージョンのプロパティを実装する方法は次のとおりです。

class Property(object):
    def __init__(self, fget):
        self.fget = fget

    def __get__(self, obj, type):
        if obj is None:
            return self
        return self.fget(obj)

組み込みのproperty()と同じように使用します。

class MyClass(object):
    @Property
    def foo(self):
        return "Foo!"

記述子はPythonで使用され、プロパティ、バインドされたメソッド、静的メソッド、クラスメソッド、スロットなどを実装します。それらを理解することで、以前はPythonの「癖」のように見えていた多くのものが現在の方法である理由が簡単にわかります。

Raymond Hettingerには私よりもはるかに優れた説明行う優れたチュートリアルがあります。


これはデコレータの複製ですよね!?(stackoverflow.com/questions/101268/...
gecco

2
いいえ、デコレータと記述子はまったく異なりますが、サンプルコードでは記述子デコレータを作成しています。:)
Nick Johnson

1
これを行うために他の方法は、ラムダである:foo = property(lambda self: self.__foo)
ピート・ピーターソン

1
@PetePetersonはい、しかしpropertyそれ自体は記述子で実装されており、それが私の投稿のポイントでした。
Nick Johnson、

142

条件付き割り当て

x = 3 if (y == 1) else 2

これは、「yが1の場合はxに3を割り当て、それ以外の場合は2をxに割り当てる」というように動作します。かっこは必ずしも必要ではありませんが、読みやすくするためにかっこが好きです。より複雑なものがある場合は、チェーンすることもできます。

x = 3 if (y == 1) else 2 if (y == -1) else 1

ある時点では少し行き過ぎです。

if ... elseを任意の式で使用できることに注意してください。例えば:

(func1 if y == 1 else func2)(arg1, arg2) 

ここで、yが1の場合はfunc1が呼び出され、それ以外の場合はfunc2が呼び出されます。どちらの場合も、対応する関数は引数arg1とarg2で呼び出されます。

同様に、以下も有効です。

x = (class1 if y == 1 else class2)(arg1, arg2)

ここで、class1とclass2は2つのクラスです。


29
割り当ては特別な部分ではありません。同様に簡単に次のようなことができます:if 3(y == 1)else 2を返します
Brian

25
その代替方法は、Pythonを難読化したのを初めて目にしたものです。
クレイグマックイーン

3
カイルブルックス:その場合、ブール演算子は短絡しません。bool(3)== Falseの場合のみ2を評価します。
RoadieRich 2009

15
この逆スタイルのコーディングは私を混乱させます。x = ((y == 1) ? 3 : 2)私にはもっと理にかなっているようなもの
mpen 09/10/20

13
@マークの正反対を感じます、Cスタイルの三項演算子は常に私を混乱させました、間違った条件で評価されるのは右側または中央ですか?私はPythonの3値構文を優先しています。
ジェフリーハリス

141

Doctest:ドキュメントと単体テストを同時に行います。

Pythonのドキュメントから抜粋した例:

def factorial(n):
    """Return the factorial of n, an exact integer >= 0.

    If the result is small enough to fit in an int, return an int.
    Else return a long.

    >>> [factorial(n) for n in range(6)]
    [1, 1, 2, 6, 24, 120]
    >>> factorial(-1)
    Traceback (most recent call last):
        ...
    ValueError: n must be >= 0

    Factorials of floats are OK, but the float must be an exact integer:
    """

    import math
    if not n >= 0:
        raise ValueError("n must be >= 0")
    if math.floor(n) != n:
        raise ValueError("n must be exact integer")
    if n+1 == n:  # catch a value like 1e300
        raise OverflowError("n too large")
    result = 1
    factor = 2
    while factor <= n:
        result *= factor
        factor += 1
    return result

def _test():
    import doctest
    doctest.testmod()    

if __name__ == "__main__":
    _test()

6
doctestのは確かに冷却されているが、私は本当にあなたが何かが例外上げる必要があることをテストに入力する必要があり、すべての嫌なもの嫌い
TMを。

60
Doctestは過大評価され、ドキュメントを汚染します。setUp()なしでスタンドアロン関数をテストする頻度はどれくらいですか?
有料オタク

2
誰がdoctestにセットアップできないと言っていますか?コンテキストを生成locals()してdoctestに返す関数を記述しますdo locals().update(setUp())= D
Jiaaro

12
スタンドアロン関数がsetUpを必要とする場合、関連のないものから切り離したり、クラスに配置したりする可能性が高くなります。その後、クラスdoctest名前空間をクラスメソッドdoctestで再利用できるため、setUpに少し似ており、DRYのみで読み取り可能です。
Andy Mikhaylenko、2010

4
「スタンドアロン関数をどのくらいの頻度でテストしますか」-たくさん。ファサードを決定するとき、doctestはしばしば設計プロセスから自然に生まれます。
Gregg Lind

138

名前付きフォーマット

%-formattingは辞書を使用します(%i /%sなどの検証も適用します)。

>>> print "The %(foo)s is %(bar)i." % {'foo': 'answer', 'bar':42}
The answer is 42.

>>> foo, bar = 'question', 123

>>> print "The %(foo)s is %(bar)i." % locals()
The question is 123.

また、locals()も辞書であるため、ディクショナリとして単に渡すだけで、ローカル変数から%置換を取得できます。これは眉をひそめると思いますが、物事を簡素化します。

新しいスタイルのフォーマット

>>> print("The {foo} is {bar}".format(foo='answer', bar=42))

60
段階的に廃止され、最終的に文字列のformat()メソッドに置き換えられます。
コンスタンティン

3
名前付きフォーマットは、コンテキストの変数名なしでフォーマット文字列を表示する傾向があるため、翻訳者にとって非常に便利です
pixelbeat

2
Python 3.0.1で動作するように見えます(print呼び出しの前後に括弧を追加する必要があります)。
Pasi Savolainen、

9
ハッシュ、ハァッ?どこから来たのかわかります。
shylent 2009年

11
%sのフォーマットは段階的に廃止されません。str.format()は確かにもっとPythonicですが、単純な文字列置換では実際には10倍遅くなります。%sのフォーマットはまだベストプラクティスであると私は信じています。
Kenneth Reitz、2010

132

さらに多くのpythonモジュール(特にサードパーティのモジュール)を追加するには、ほとんどの人がPYTHONPATH環境変数を使用しているようです。または、サイトパッケージディレクトリにシンボリックリンクまたはディレクトリを追加しています。別の方法は、*。pthファイルを使用することです。公式のPythonドキュメントの説明は次のとおりです。

「[pythonの検索パスを変更する]最も便利な方法は、Pythonのパス上にあるディレクトリ、通常は... / site-packages /ディレクトリにパス構成ファイルを追加することです。パス構成ファイルの拡張子は.pthです。 、および各行にはsys.pathに追加される単一のパスが含まれている必要があります(新しいパスはsys.pathに追加されるため、追加されたディレクトリのモジュールは標準モジュールを上書きしません。つまり、このメカニズムを使用できません標準モジュールの固定バージョンをインストールします。)」


1
setuptoolsからのsite-packagesディレクトリにあるその.pthファイルとこのアイデアとの間の接続を作成したことはありません。驚くばかり。
dave paola 10/07/14

122

例外のelse句:

try:
  put_4000000000_volts_through_it(parrot)
except Voom:
  print "'E's pining!"
else:
  print "This parrot is no more!"
finally:
  end_sketch()

else ...句を使用すると、try ...句にコードが追加されていないため、try ... exceptステートメントで保護されているコードで発生しなかった例外を誤ってキャッチすることがなくなります。

http://docs.python.org/tut/node10.htmlを参照してください


8
+1これは素晴らしいです。例外ブロックに入らずにtryブロックが実行されると、elseブロックに入ります。そしてもちろん、finallyブロックが実行されます
inspectorG4dget

「else」がそこにある理由がついにわかりました!ありがとう。
taynaron

continueを使用する方が理にかなっていますが、既に使用されていると思います;)
PawełPrażakDec

ブロック:Python2の古いバージョンにあなたが両方の他のを持っていないことに注意してください:そして最後に:同じ試しのための条項
ケビン・ホーン

1
@PawełPrażak、Kevin Hornが述べたように、この構文はPythonの最初のリリース後に導入されたものであり、新しい予約キーワードを既存の言語に追加することは常に問題があります。これが、既存のキーワードが通常再利用される理由です(最近のC ++標準では「auto」を参照)。
コンスタンティン

114

例外の再発生

# Python 2 syntax
try:
    some_operation()
except SomeError, e:
    if is_fatal(e):
        raise
    handle_nonfatal(e)

# Python 3 syntax
try:
    some_operation()
except SomeError as e:
    if is_fatal(e):
        raise
    handle_nonfatal(e)

エラーハンドラ内に引数のない「raise」ステートメントは、元のトレースバックをそのままにして例外を再発生させるようにPythonに指示し、「ああ、ごめん、ごめん、私はそれをキャッチするつもりはありませんでした、ごめん、ごめんなさい。 」

元のトレースバックを印刷、保存、またはいじる場合は、sys.exc_info()を使用して取得できます。Pythonのように印刷するには、「traceback」モジュールを使用します。


申し訳ありませんが、これはほとんどすべての言語でよく知られている一般的な機能です。
Lucas S.

6
斜体のテキストに注意してください。raise e代わりに行う人もいますが、元のトレースバックは保持されません。
habnabit 2009年

12
おそらくもっと魔法のようで、これexc_info = sys.exc_info(); raise exc_info[0], exc_info[1], exc_info[2]と同等ですが、それらの値を変更できます(たとえば、例外のタイプやメッセージを変更します)
ianb

3
@Lucas S.さて、私はそれを知りませんでした、そしてここに書かれてうれしいです。
e-satis

私はここで自分の若さを示しているかもしれませんが、問題なくpython 2.7で常にpython 3構文を使用しています
wim

106

主なメッセージ:)

import this
# btw look at this module's source :)

暗号解読

禅のPython、ティム・ピーターズ

醜いよりも美しい方がいいです。
明示的は暗黙的よりも優れています。
シンプルは複雑よりも優れています。
複雑は複雑よりも優れています。
ネストよりもフラットの方が適しています。
疎は密よりも優れています。
読みやすさが重要です。
特別なケースは、ルールを破るほど特別なものではありません。
実用性は純粋さを上回りますが。
エラーがサイレントに渡ることはありません。
明示的に沈黙させない限り。
あいまいな状況に直面して、推測する誘惑を拒否してください。それを行うには、明白な方法が1つ(できれば1つだけ)あるはずです。
あなたがオランダ人でない限り、その方法は最初は明白ではないかもしれませんが。
今は決してないよりはましです。
多くの場合、今。
実装の説明が難しい場合は、悪い考えです。
実装が簡単に説明できる場合は、良いアイデアかもしれません。
名前空間は非常に魅力的なアイデアの1つです。もっと多くのことをしましょう。


1
なぜソースがそのように暗号化されたのでしょうか?それはただの楽しみでしたか、それとも他の理由がありましたか?
MiniQuark 2008

42
ソースの記述方法は禅に反します!
Hasen


2
/usr/lib/python2.6/this.pyを更新して、古いコードをこれで置き換えたprint s.translate("".join(chr(64<i<91 and 65+(i-52)%26 or 96<i<123 and 97+(i-84)%26 or i) for i in range(256)))ところ、見栄えがよくなりました!! :-D
Fortran 2009年

2
@MiniQuark:簡単な履歴レッスン:wefearchange.org/2010/06/import-this-and-zen-of-python.html

105

インタラクティブな通訳タブの補完

try:
    import readline
except ImportError:
    print "Unable to load readline module."
else:
    import rlcompleter
    readline.parse_and_bind("tab: complete")


>>> class myclass:
...    def function(self):
...       print "my function"
... 
>>> class_instance = myclass()
>>> class_instance.<TAB>
class_instance.__class__   class_instance.__module__
class_instance.__doc__     class_instance.function
>>> class_instance.f<TAB>unction()

また、PYTHONSTARTUP環境変数を設定する必要があります。


2
これは非常に便利な機能です。あまりにも多いので、私はそれを可能にするための簡単なスクリプト(プラス他のイントロスペクション機能強化のカップル)しました:pixelbeat.org/scripts/inpy
pixelbeat

43
IPythonは、これに加えて他の
素晴らしい

これは、pdbプロンプトでは通常のpythonプロンプトよりも便利でした(とにかくIPythonがその目的を果たすため)。ただし、これはpdbプロンプトでは機能しないようです。おそらく、pdbがタブ用に独自にバインドしているためです(これはあまり役に立ちません)。pdbプロンプトでparse_and_bind()を呼び出してみましたが、それでも機能しませんでした。IPythonでpdbプロンプトを取得する代わりに、より多くの作業が必要になるため、使用しない傾向があります。
haridsv 2010

2
@haridsv-- easy_install ipdb次に使用できますimport ipdb; ipdb.set_trace()
Doug Harris

1
OSXでは[そして私はlibeditを使用する他のシステムを想像します]あなたはしなければなりませんreadline.parse_and_bind ("bind ^I rl_complete")
Foo Bah

91

ネストされたリスト内包表記とジェネレータ式:

[(i,j) for i in range(3) for j in range(i) ]    
((i,j) for i in range(4) for j in range(i) )

これらはネストループコードの巨大なチャンクを置き換えることができます。


「for j in range(i)」-これはタイプミスですか?通常は、iとjの固定範囲が必要です。2D配列にアクセスしている場合、要素の半分を逃してしまいます。
Peter Gibson、

この例では、配列にアクセスしていません。このコードの唯一の目的は、内部範囲の式が外部範囲の式にアクセスできることを示すことです。副産物は、4> x> y> 0のようなペア(x、y)のリストです。
ラファウDowgird

2
微積分における二重積分、または二重合計のようなものです。
ユー

22
ここで覚えておかなければならない重要な点は、forステートメントの順序は、外側から内側に向​​かって、標準のforループで記述されると予想される順序で記述されることです。
sykora 2010年

2
sykoraのコメントに追加するには:内部forのとifのスタックから始めていると想像してくださいyield x。これをジェネレータ式に変換するには、x最初に移動して、すべてのコロン(およびyield)を削除し、全体を括弧で囲みます。代わりにリスト内包を作成するには、外側の括弧を角括弧で置き換えます。
ケンアーノルド

91

set組み込みの演算子のオーバーロード:

>>> a = set([1,2,3,4])
>>> b = set([3,4,5,6])
>>> a | b # Union
{1, 2, 3, 4, 5, 6}
>>> a & b # Intersection
{3, 4}
>>> a < b # Subset
False
>>> a - b # Difference
{1, 2}
>>> a ^ b # Symmetric Difference
{1, 2, 5, 6}

標準ライブラリリファレンスの詳細:セットタイプ


チュートリアルでは、一部はdocs.python.org/tutorial/datastructures.html#sets
XTL
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.