ライブラリと拡張機能に関するFAQ
図書館に関する一般的な質問
タスクXを実行するモジュールまたはアプリケーションを見つけるにはどうすればよいですか?
ライブラリリファレンスをチェックして、関連する標準ライブラリモジュールがあるかどうかを確認してください。 (最終的には、標準ライブラリの内容を学習し、この手順をスキップできるようになります。)
サードパーティのパッケージについては、 Python Package Index を検索するか、 Google または別のWeb検索エンジンを試してください。 「Python」に加えて、関心のあるトピックのキーワードを1つか2つ検索すると、通常、役立つものが見つかります。
math.py(socket.py、regex.pyなど)のソースファイルはどこにありますか?
モジュールのソースファイルが見つからない場合は、C、C ++、またはその他のコンパイル言語で実装された組み込みモジュールまたは動的にロードされたモジュールである可能性があります。 この場合、ソースファイルがないか、mathmodule.c
のようなCソースディレクトリのどこかにある可能性があります(Pythonパス上ではありません)。
Pythonには(少なくとも)3種類のモジュールがあります。
Python(.py)で記述されたモジュール。
Cで記述され、動的にロードされるモジュール(.dll、.pyd、.so、.slなど)。
Cで記述され、インタープリターにリンクされたモジュール。 これらのリストを取得するには、次のように入力します。
import sys print(sys.builtin_module_names)
UnixでPythonスクリプトを実行可能にするにはどうすればよいですか?
スクリプトファイルのモードは実行可能である必要があり、最初の行は#!
で始まり、その後にPythonインタープリターのパスが続く必要があります。
1つ目は、chmod +x scriptfile
またはおそらくchmod 755 scriptfile
を実行することによって実行されます。
2つ目は、さまざまな方法で実行できます。 最も簡単な方法は書くことです
#!/usr/local/bin/python
ファイルの最初の行として、Pythonインタープリターがプラットフォームにインストールされている場所のパス名を使用します。
Pythonインタープリターが存在する場所からスクリプトを独立させたい場合は、 env プログラムを使用できます。 Pythonインタープリターがユーザーの PATH
のディレクトリにあると仮定すると、ほとんどすべてのUnixバリアントは以下をサポートします。
#!/usr/bin/env python
CGIスクリプトに対してこれを行わないでください。 CGIスクリプトの PATH
変数は非常に小さいことが多いため、インタープリターの実際の絶対パス名を使用する必要があります。
時折、ユーザーの環境がいっぱいになり、 / usr / bin / env プログラムが失敗することがあります。 または、envプログラムがまったくありません。 その場合、次のハックを試すことができます(Alex Rezinskyによる):
#! /bin/sh
""":"
exec python $0 ${1+"$@"}
"""
マイナーな欠点は、これがスクリプトの__doc__文字列を定義することです。 ただし、追加することで修正できます
__doc__ = """...Whatever..."""
Python用のcurses / termcapパッケージはありますか?
Unixバリアントの場合:標準のPythonソースディストリビューションには、:source: `Modules` サブディレクトリにcursesモジュールが付属していますが、デフォルトではコンパイルされていません。 (これはWindowsディストリビューションでは利用できないことに注意してください– Windows用のcursesモジュールはありません。)
curses モジュールは、基本的なcurses機能に加えて、色、代替文字セットのサポート、パッド、マウスのサポートなど、ncursesおよびSYSVcursesからの多くの追加機能をサポートします。 これは、モジュールがBSDの呪いしかないオペレーティングシステムと互換性がないことを意味しますが、このカテゴリに分類される現在保守されているOSはないようです。
Windowsの場合: consolelibモジュールを使用します。
シグナルハンドラが機能しないのはなぜですか?
最も一般的な問題は、シグナルハンドラが間違った引数リストで宣言されていることです。 それはとして呼ばれます
handler(signum, frame)
したがって、次の2つのパラメータで宣言する必要があります。
def handler(signum, frame):
...
一般的なタスク
Pythonプログラムまたはコンポーネントをテストするにはどうすればよいですか?
Pythonには2つのテストフレームワークが付属しています。 doctest モジュールは、モジュールのdocstringで例を見つけて実行し、出力をdocstringで指定された期待される出力と比較します。
unittest モジュールは、JavaおよびSmalltalkテストフレームワークをモデルにした、より洗練されたテストフレームワークです。
テストを簡単にするには、プログラムで優れたモジュラー設計を使用する必要があります。 プログラムには、ほとんどすべての機能が関数またはクラスメソッドのいずれかにカプセル化されている必要があります。これにより、プログラムの実行速度が向上するという驚くべき楽しい効果が得られる場合があります(ローカル変数アクセスはグローバルアクセスよりも高速であるため)。 さらに、プログラムはグローバル変数の変更に依存することを避ける必要があります。これにより、テストがはるかに困難になるためです。
プログラムの「グローバルメインロジック」は、次のように単純な場合があります。
if __name__ == "__main__":
main_logic()
プログラムのメインモジュールの下部にあります。
プログラムが関数とクラスの動作の扱いやすいコレクションとして編成されたら、動作を実行するテスト関数を作成する必要があります。 一連のテストを自動化するテストスイートを各モジュールに関連付けることができます。 これは大変な作業のように聞こえますが、Pythonは非常に簡潔で柔軟性があるため、驚くほど簡単です。 「本番コード」と並行してテスト関数を作成することで、コーディングをより楽しく楽しくすることができます。これにより、バグや設計上の欠陥を早期に見つけることが容易になります。
プログラムのメインモジュールとなることを意図していない「サポートモジュール」には、モジュールのセルフテストが含まれる場合があります。
if __name__ == "__main__":
self_test()
複雑な外部インターフェースと相互作用するプログラムでさえ、Pythonで実装された「偽の」インターフェースを使用して、外部インターフェースが利用できない場合にテストされる可能性があります。
ドキュメント文字列からドキュメントを作成するにはどうすればよいですか?
pydoc モジュールは、Pythonソースコードのドキュメント文字列からHTMLを作成できます。 純粋にdocstringからAPIドキュメントを作成するための代替手段は、 epidoc です。 Sphinx には、docstringコンテンツを含めることもできます。
一度に1回キーを押すにはどうすればよいですか?
Unixバリアントには、いくつかの解決策があります。 cursesを使用してこれを行うのは簡単ですが、cursesは学ぶのにかなり大きなモジュールです。
スレッド
スレッドを使用してプログラムするにはどうすればよいですか?
_thread モジュールではなく、必ず threading モジュールを使用してください。 threading モジュールは、 _thread モジュールによって提供される低レベルのプリミティブの上に便利な抽象化を構築します。
Aahzには、彼のスレッドチュートリアルからの役立つスライドのセットがあります。 http://www.pythoncraft.com/OSCON2001/を参照してください。
私のスレッドはどれも実行されていないようです:なぜですか?
メインスレッドが終了するとすぐに、すべてのスレッドが強制終了されます。 メインスレッドの実行速度が速すぎて、スレッドが作業を行う時間がありません。
簡単な修正は、すべてのスレッドが終了するのに十分な長さのスリープをプログラムの最後に追加することです。
import threading, time
def thread_task(name, n):
for i in range(n):
print(name, i)
for i in range(10):
T = threading.Thread(target=thread_task, args=(str(i), i))
T.start()
time.sleep(10) # <---------------------------!
しかし、現在(多くのプラットフォームで)スレッドは並行して実行されていませんが、一度に1つずつ順番に実行されているように見えます! その理由は、前のスレッドがブロックされるまで、OSスレッドスケジューラが新しいスレッドを開始しないためです。
簡単な修正は、実行関数の開始に小さなスリープを追加することです。
def thread_task(name, n):
time.sleep(0.001) # <--------------------!
for i in range(n):
print(name, i)
for i in range(10):
T = threading.Thread(target=thread_task, args=(str(i), i))
T.start()
time.sleep(10)
time.sleep()の適切な遅延値を推測する代わりに、ある種のセマフォメカニズムを使用することをお勧めします。 1つのアイデアは、 queue モジュールを使用してキューオブジェクトを作成し、各スレッドが終了時にキューにトークンを追加し、メインスレッドがスレッドと同じ数のトークンをキューから読み取るようにすることです。
多数のワーカースレッド間で作業を分割するにはどうすればよいですか?
最も簡単な方法は、 concurrent.futures モジュール、特に ThreadPoolExecutor クラスを使用することです。
または、ディスパッチングアルゴリズムを細かく制御する場合は、独自のロジックを手動で作成できます。 queue モジュールを使用して、ジョブのリストを含むキューを作成します。 Queue クラスはオブジェクトのリストを維持し、キューにアイテムを追加する.put(obj)
メソッドと、それらを返す.get()
メソッドを備えています。 クラスは、各ジョブが1回だけ配布されるようにするために必要なロックを処理します。
簡単な例を次に示します。
import threading, queue, time
# The worker thread gets jobs off the queue. When the queue is empty, it
# assumes there will be no more work and exits.
# (Realistically workers will run until terminated.)
def worker():
print('Running worker')
time.sleep(0.1)
while True:
try:
arg = q.get(block=False)
except queue.Empty:
print('Worker', threading.current_thread(), end=' ')
print('queue empty')
break
else:
print('Worker', threading.current_thread(), end=' ')
print('running with argument', arg)
time.sleep(0.5)
# Create queue
q = queue.Queue()
# Start a pool of 5 workers
for i in range(5):
t = threading.Thread(target=worker, name='worker %i' % (i+1))
t.start()
# Begin adding work to the queue
for i in range(50):
q.put(i)
# Give threads time to run
print('Main thread sleeping')
time.sleep(5)
実行すると、次の出力が生成されます。
Running worker
Running worker
Running worker
Running worker
Running worker
Main thread sleeping
Worker <Thread(worker 1, started 130283832797456)> running with argument 0
Worker <Thread(worker 2, started 130283824404752)> running with argument 1
Worker <Thread(worker 3, started 130283816012048)> running with argument 2
Worker <Thread(worker 4, started 130283807619344)> running with argument 3
Worker <Thread(worker 5, started 130283799226640)> running with argument 4
Worker <Thread(worker 1, started 130283832797456)> running with argument 5
...
詳細については、モジュールのドキュメントを参照してください。 Queue クラスは機能的なインターフェースを提供します。
どのような種類のグローバル値の変更がスレッドセーフですか?
グローバルインタープリターロック(GIL)は、PythonVMで一度に1つのスレッドのみが実行されるようにするために内部的に使用されます。 一般に、Pythonはバイトコード命令間でのみスレッドを切り替えることを提案します。 sys.setswitchinterval()を介して切り替える頻度を設定できます。 したがって、各バイトコード命令、したがって各命令から到達するすべてのC実装コードは、Pythonプログラムの観点からはアトミックです。
理論的には、これは正確なアカウンティングにはPVMバイトコードの実装を正確に理解する必要があることを意味します。 実際には、「アトミックに見える」組み込みデータ型(int、list、dictなど)の共有変数に対する操作が実際に行われることを意味します。
たとえば、次の操作はすべてアトミックです(L、L1、L2はリスト、D、D1、D2はdict、x、yはオブジェクト、i、jはint):
L.append(x)
L1.extend(L2)
x = L[i]
x = L.pop()
L1[i:j] = L2
L.sort()
x = y
x.field = y
D[x] = y
D1.update(D2)
D.keys()
これらはそうではありません:
i = i+1
L.append(L[-1])
L[i] = L[j]
D[x] = D[x] + 1
他のオブジェクトを置き換える操作は、参照カウントがゼロに達したときにそれらの他のオブジェクトの__del__()
メソッドを呼び出す可能性があり、それが物事に影響を与える可能性があります。 これは、辞書とリストの一括更新に特に当てはまります。 疑わしい場合は、ミューテックスを使用してください。
グローバルインタプリタロックを取り除くことはできませんか?
グローバルインタープリターロック(GIL)は、ハイエンドマルチプロセッサーサーバーマシンでのPythonの展開の妨げと見なされることがよくあります。 )すべてのPythonコードは、GILが保持されている間のみ実行できます。
Python 1.5の時代に、Greg Steinは実際に包括的なパッチセット(「フリースレッド」パッチ)を実装し、GILを削除して、きめ細かいロックに置き換えました。 Adam Olsenは最近、彼の python-safethread プロジェクトで同様の実験を行いました。 残念ながら、両方の実験では、GILの削除を補うために必要なきめ細かいロックの量が原因で、シングルスレッドのパフォーマンスが急激に低下しました(少なくとも30 % s低い)。
これは、マルチCPUマシンでPythonをうまく利用できないという意味ではありません。 複数のスレッドではなく、複数のプロセスに作業を分割することで創造性を発揮する必要があります。 新しい concurrent.futures モジュールの ProcessPoolExecutor クラスは、これを行う簡単な方法を提供します。 マルチプロセッシングモジュールは、タスクのディスパッチをより細かく制御したい場合に備えて、低レベルのAPIを提供します。
C拡張機能の賢明な使用も役立ちます。 C拡張機能を使用して時間のかかるタスクを実行する場合、実行スレッドがCコード内にある間に拡張機能がGILを解放し、他のスレッドが作業を実行できるようにします。 zlib や hashlib などの一部の標準ライブラリモジュールはすでにこれを行っています。
GILは、真にグローバルではなく、インタプリタ状態ごとのロックである必要があることが示唆されています。 その場合、通訳者はオブジェクトを共有できなくなります。 残念ながら、これも起こりそうにありません。 現在、多くのオブジェクト実装にはグローバル状態があるため、これは膨大な量の作業になります。 たとえば、小さい整数と短い文字列がキャッシュされます。 これらのキャッシュは、インタープリター状態に移行する必要があります。 他のオブジェクトタイプには、独自のフリーリストがあります。 これらの無料リストは、インタプリタ状態に移行する必要があります。 等々。
また、サードパーティの拡張機能にも同じ問題が存在するため、有限の時間でさえ実行できるとは思えません。 サードパーティの拡張機能は、すべてのグローバル状態をインタプリタ状態に格納するように変換するよりも速い速度で書き込まれている可能性があります。
そして最後に、状態を共有していない複数のインタープリターができたら、各インタープリターを別々のプロセスで実行することで何が得られましたか?
入出力
ファイルを削除するにはどうすればよいですか? (およびその他のファイルに関する質問…)
os.remove(filename)
またはos.unlink(filename)
を使用します。 ドキュメントについては、 os モジュールを参照してください。 2つの機能は同じです。 unlink()は、この関数のUnixシステムコールの名前です。
ディレクトリを削除するには、 os.rmdir()を使用します。 os.mkdir()を使用して作成します。 os.makedirs(path)
は、path
に存在しない中間ディレクトリを作成します。 os.removedirs(path)
は、中間ディレクトリが空である限り、それらを削除します。 ディレクトリツリー全体とその内容を削除する場合は、 shutil.rmtree()を使用してください。
ファイルの名前を変更するには、os.rename(old_path, new_path)
を使用します。
ファイルを切り捨てるには、f = open(filename, "rb+")
を使用してファイルを開き、f.truncate(offset)
を使用します。 オフセットのデフォルトは現在のシーク位置です。 os.open()で開かれたファイル用のos.ftruncate(fd, offset)
もあります。ここで、 fd はファイル記述子(小さな整数)です。
shutil モジュールには、 copyfile()、 copytree()、 rmtree()などのファイルを操作するための関数も多数含まれています。 。
ファイルをコピーするにはどうすればよいですか?
shutil モジュールには、 copyfile()関数が含まれています。 MacOS 9では、リソースフォークとFinder情報はコピーされないことに注意してください。
バイナリデータを読み取る(または書き込む)にはどうすればよいですか?
複雑なバイナリデータ形式を読み書きするには、 struct モジュールを使用するのが最適です。 これにより、バイナリデータ(通常は数値)を含む文字列を取得して、Pythonオブジェクトに変換できます。 およびその逆。
たとえば、次のコードは、ファイルから2つの2バイト整数と1つの4バイト整数をビッグエンディアン形式で読み取ります。
import struct
with open(filename, "rb") as f:
s = f.read(8)
x, y, z = struct.unpack(">hhl", s)
フォーマット文字列の「>」は、ビッグエンディアンデータを強制します。 文字「h」は文字列から1つの「短整数」(2バイト)を読み取り、「l」は文字列から1つの「長整数」(4バイト)を読み取ります。
より規則的なデータの場合(例: intまたはfloatの同種リスト)、 array モジュールを使用することもできます。
os.popen()で作成されたパイプでos.read()を使用できないようです。 どうして?
os.read()は、開いているファイルを表す小さな整数であるファイル記述子を受け取る低レベルの関数です。 os.popen()は、組み込みの open()関数によって返されるのと同じタイプの高レベルのファイルオブジェクトを作成します。 したがって、 os.popen()で作成されたパイプ p から n バイトを読み取るには、p.read(n)
を使用する必要があります。
シリアル(RS232)ポートにアクセスするにはどうすればよいですか?
Win32、POSIX(Linux、BSDなど)の場合、Jython:
Unixについては、MitchChapmanによるUsenetの投稿を参照してください。
sys.stdout(stdin、stderr)を閉じないのはなぜですか?
Python ファイルオブジェクトは、低レベルのCファイル記述子の高レベルの抽象化レイヤーです。
組み込みの open()関数を使用してPythonで作成するほとんどのファイルオブジェクトの場合、f.close()
はPythonファイルオブジェクトをPythonの観点から閉じているものとしてマークし、基礎となるCファイル記述子。 これは、f
がガベージになると、f
のデストラクタでも自動的に発生します。
ただし、stdin、stdout、およびstderrは、Cによっても特別なステータスが与えられるため、Pythonによって特別に扱われます。 sys.stdout.close()
を実行すると、Pythonレベルのファイルオブジェクトが閉じているとマークされますが、関連するCファイル記述子はではなく閉じられます。
これら3つのうちの1つの基礎となるCファイル記述子を閉じるには、最初にそれが本当に実行したいことであることを確認する必要があります(たとえば、I / Oを実行しようとしている拡張モジュールを混乱させる可能性があります)。 そうである場合は、 os.close()を使用します。
os.close(stdin.fileno())
os.close(stdout.fileno())
os.close(stderr.fileno())
または、数値定数0、1、および2をそれぞれ使用できます。
ネットワーク/インターネットプログラミング
Python用のWWWツールは何ですか?
ライブラリリファレンスマニュアルのインターネットプロトコルとサポートおよびインターネットデータ処理というタイトルの章を参照してください。 Pythonには、サーバー側とクライアント側のWebシステムの構築に役立つ多くのモジュールがあります。
利用可能なフレームワークの概要は、Paul Boddieによって https://wiki.python.org/moin/WebProgrammingで管理されています。
Cameron Lairdは、PythonWebテクノロジーに関する便利なページセットを http://phaseit.net/claird/comp.lang.python/web_python で管理しています。
CGIフォーム送信(METHOD = POST)を模倣するにはどうすればよいですか?
フォームをPOSTした結果のWebページを取得したいと思います。 これを簡単に行える既存のコードはありますか?
はい。 urllib.request を使用する簡単な例を次に示します。
#!/usr/local/bin/python
import urllib.request
# build the query string
qs = "First=Josephine&MI=Q&Last=Public"
# connect and send the server a path
req = urllib.request.urlopen('http://www.some-server.out-there'
'/cgi-bin/some-cgi-script', data=qs)
with req:
msg, hdrs = req.read(), req.info()
一般に、パーセントエンコードされたPOST操作の場合、クエリ文字列は urllib.parse.urlencode()を使用して引用符で囲む必要があることに注意してください。 たとえば、name=Guy Steele, Jr.
を送信するには:
>>> import urllib.parse
>>> urllib.parse.urlencode({'name': 'Guy Steele, Jr.'})
'name=Guy+Steele%2C+Jr.'
Pythonスクリプトからメールを送信するにはどうすればよいですか?
標準ライブラリモジュール smtplib を使用します。
これは、それを使用する非常に単純なインタラクティブメール送信者です。 このメソッドは、SMTPリスナーをサポートするすべてのホストで機能します。
import sys, smtplib
fromaddr = input("From: ")
toaddrs = input("To: ").split(',')
print("Enter message, end with ^D:")
msg = ''
while True:
line = sys.stdin.readline()
if not line:
break
msg += line
# The actual mail send
server = smtplib.SMTP('localhost')
server.sendmail(fromaddr, toaddrs, msg)
server.quit()
Unixのみの代替手段はsendmailを使用します。 sendmailプログラムの場所は、システムによって異なります。 /usr/lib/sendmail
の場合もあれば、/usr/sbin/sendmail
の場合もあります。 sendmailのマニュアルページが役に立ちます。 サンプルコードは次のとおりです。
import os
SENDMAIL = "/usr/sbin/sendmail" # sendmail location
p = os.popen("%s -t -i" % SENDMAIL, "w")
p.write("To: [email protected]\n")
p.write("Subject: test\n")
p.write("\n") # blank line separating headers from body
p.write("Some text\n")
p.write("some more text\n")
sts = p.close()
if sts != 0:
print("Sendmail exit status", sts)
ソケットのconnect()メソッドでブロッキングを回避するにはどうすればよいですか?
select モジュールは、ソケットでの非同期I / Oを支援するために一般的に使用されます。
TCP接続がブロックされないようにするには、ソケットを非ブロックモードに設定します。 次に、socket.connect()
を実行すると、すぐに接続するか(可能性は低い)、エラー番号を.errno
として含む例外が発生します。 errno.EINPROGRESS
は、接続が進行中であるが、まだ終了していないことを示します。 OSが異なれば、返される値も異なるため、システムに何が返されるかを確認する必要があります。
socket.connect_ex()
メソッドを使用して、例外の作成を回避できます。 errno値を返すだけです。 ポーリングするには、後でsocket.connect_ex()
を再度呼び出すことができます– 0
またはerrno.EISCONN
は、接続していることを示します–または、このソケットを select.select()に渡すことができます書き込み可能かどうかを確認します。
データベース
Pythonのデータベースパッケージへのインターフェイスはありますか?
はい。
DBM や GDBM などのディスクベースのハッシュへのインターフェイスも標準のPythonに含まれています。 軽量のディスクベースのリレーショナルデータベースを提供する sqlite3 モジュールもあります。
ほとんどのリレーショナルデータベースのサポートが利用可能です。 詳細については、 DatabaseProgrammingwikiページを参照してください。
数学と数値
Pythonで乱数を生成するにはどうすればよいですか?
標準モジュール random は、乱数ジェネレーターを実装します。 使い方は簡単です:
import random
random.random()
これにより、[0、1)の範囲のランダムな浮動小数点数が返されます。
このモジュールには、次のような他の多くの特殊なジェネレーターもあります。
randrange(a, b)
は、[a、b)の範囲の整数を選択します。uniform(a, b)
は、[a、b)の範囲の浮動小数点数を選択します。normalvariate(mean, sdev)
は、正規(ガウス)分布をサンプリングします。
次のような一部の高レベル関数は、シーケンスを直接操作します。
choice(S)
は、指定されたシーケンスからランダムな要素を選択します。shuffle(L)
は、リストをインプレースでシャッフルします。 ランダムに並べ替えます。
Random
クラスもあり、インスタンス化して独立した複数の乱数ジェネレーターを作成できます。