この一連の記事は、「Pythonプログラムを改善するための高品質なコード91の提案を書く」の本質の要約です。
需要を選択しますsort()
か、sorted()
Pythonの関数は、一般的に、ソートに使用されているsort()
とsorted()
2つの機能の形式は次のとおりです。
sorted(iterable[, cmp[, key[, reverse]]])
s.sort([cmp[, key[, reverse]]])
sort()
そして、sorted()
3つの共通のパラメータがあります。
cmp
:ユーザー定義の比較関数、関数のパラメーターは2つの比較可能な要素(反復可能またはリストから)、関数は-1、0または+1を返します(最初のパラメーターは、最初のパラメーターと2番目のパラメーターの関係に従って)パラメータが2番目のパラメータより小さい場合、負の数が返されます)。このパラメータのデフォルト値None
。key
各要素の比較値を抽出するために使用されるパラメーター付きの関数です。デフォルトはNone
(つまり、各要素を直接比較します)reverse
並べ替え結果を逆にするかどうかを示します
2つの比較:
-
sorted()
作用する任意のオブジェクトは、反復することができ、そしてsort()
一般に作用するリスト。 -
sorted()
関数のリストは、元のリストは同じまま後に注文を返す ;とsort()
機能がします直接元のリストを変更し、機能のリターンをNone
。実際のアプリケーション・プロセスが使用し、元のリストを維持するために必要なsorted()
機能がより適切である、またはあなたが選択することができますsort()
ので、機能をsort()
関数は元のリスト、少ないメモリ消費、高効率をコピーする必要はありません。 -
か
sort()
またはsorted()
パラメータ渡し、関数key
着信よりもパラメータをcmp
高効率。cmp
そして、発注プロセスを通じて受信機能は、複数回、大きなオーバーヘッド機能と呼ぶkey
使用するよりそうキーを使用して、各要素についての取引を行うだけcmp
高い効率。 -
sorted()
この関数は非常に強力で、さまざまなデータ構造をソートしてさまざまなニーズを満たすことができます。
例:
辞書を並べ替える:
>>> phone_book = {"Linda": "7750", "Bob": "9345", "Carol": "5834"}
>>> from operator import itemgetter
>>> sorted_pb = sorted(phone_book.items(), key=itemgetter(1))
>>> print(sorted_pb)
[('Carol', '5834'), ('Linda', '7750'), ('Bob', '9345')]
多次元リストの並べ替え:実際のケースは、フィールドの数でソートされるように、状況のニーズに実行されます、それはDBの内部でSQL文を実行することは非常に簡単ですが、関節の多次元リスト使用するsorted()
機能も簡単にアクセスすることができます
>>> import operator
>>> game_result = [["Bob",95,"A"],["Alan",86,"C"],["Mandy",82.5,"A"],["Rob",86,"E"]]
>>> sorted(game_result, key=operator.itemgetter(2, 1))
[['Mandy', 82.5, 'A'], ['Bob', 95, 'A'], ['Alan', 86, 'C'], ['Rob', 86, 'E']]
辞書内の混合リストの並べ替え:辞書内のキーまたは値はリストであり、リスト内の特定の位置にある要素が並べ替えられます
>>> my_dict = {"Li":["M",7],"Zhang":["E",2],"Wang":["P",3],"Du":["C",2],"Ma":["C",9],"Zhe":["H",7]}
>>> import operator
>>> sorted(my_dict.items(), key=lambda item:operator.itemgetter(1)(item[1]))
[('Du', ['C', 2]), ('Zhang', ['E', 2]), ('Wang', ['P', 3]), ('Zhe', ['H', 7]), ('Li', ['M', 7]), ('Ma', ['C', 9])]
リストでの混合辞書ソート:リストの各要素は辞書の形式で、辞書の複数のキー値をソートします。
>>> import operator
>>> game_result = [{"name":"Bob","wins":10,"losses":3,"rating":75},{"name":"David","wins":3,"losses":5,"rating":57},{"name":"Carol","wins":4,"losses":5,"rating":57},{"name":"Patty","wins":9,"losses":3,"rating":71.48}]
>>> sorted(game_result, key=operator.itemgetter("rating","name"))
[{'losses': 5, 'name': 'Carol', 'rating': 57, 'wins': 4}, {'losses': 5, 'name': 'David', 'rating': 57, 'wins': 3}, {'losses': 3, 'name': 'Patty', 'rating': 71.48, 'wins': 9}, {'losses': 3, 'name': 'Bob', 'rating': 75, 'wins': 10}]
コピーモジュールを使用してオブジェクトを深くコピーする
- 浅いコピー:新しい複合オブジェクトを作成し、元のオブジェクトで見つかった参照をオブジェクトに挿入します。そのような植物の機能、スライス、コピーモジュールとして実装の種々の浅いコピー、
copy
操作。 - ディープコピー:新しい複合オブジェクトも作成されますが、参照に遭遇すると、ポイントされている特定のコンテンツを再帰的にコピーし続けます。つまり、参照によってポイントされているオブジェクトをコピーし続けるので、結果のオブジェクトは他の参照オブジェクト操作の影響を受けます。これは、コピーモジュールのディープコピー達成するために依存している
deepcopy()
操作を。
浅いコピーでは完全なコピーは作成されません。リストや辞書などの不変オブジェクトがある場合、参照アドレスのみがコピーされます。上記の問題を解決するには、ディープコピーが必要です。ディープコピーは、参照だけでなく、参照が指すオブジェクトもコピーするため、ディープコピーによって取得されたオブジェクトと元のオブジェクトは互いに独立しています。
統計をカウントするためにカウンターを使用する
統計のカウントは、アイテムの発生数をカウントすることです。さまざまなデータ構造を使用して実装できます。
- 例については、使用
defaultdict
を実現
from collections import defaultdict
some_data = ["a", "2", 2, 4, 5, "2", "b", 4, 7, "a", 5, "d", "a", "z"]
count_frq = defaultdict(int)
for item in some_data:
count_frq[item] += 1
print(count_frq)
# defaultdict(<class 'int'>, {'a': 3, '2': 2, 2: 1, 4: 2, 5: 2, 'b': 1, 7: 1, 'd': 1, 'z': 1})
しかし、よりエレガントな、よりPython的解決策を使用することですcollections.Counter
:
from collections import Counter
some_data = ["a", "2", 2, 4, 5, "2", "b", 4, 7, "a", 5, "d", "z", "a"]
print(Counter(some_data))
# Counter({'a': 3, '2': 2, 4: 2, 5: 2, 2: 1, 'b': 1, 7: 1, 'd': 1, 'z': 1})
ConfigParserの深い理解
一般的な構成ファイル形式はXML、iniなどです。これらの中で、MS Windowsシステムでは、iniファイル形式が特に使用され、オペレーティングシステムのAPIでも、それをサポートするための関連するインターフェイス関数が提供されます。Linuxなどのオペレーティングシステムでも、iniと同様のファイル形式がよく使用されており、たとえば、pylintの構成ファイルはこの形式です。Pythonにはそれをサポートする標準ライブラリ、つまりConfigParserがあります。
ConfigParserの基本的な使い方は、マニュアルで習得できますが、注目に値するいくつかの知識ポイントがあります。最初は、getboolean()
この機能。getboolean()
特定のルールに従って、構成アイテムの値は、次の構成などのブール値に変換されます。
[section1]
option1=0
あなたが呼び出すとgetboolean("section1", "option1")
、それはFalseを返します。
getboolean()
真の値のルールは:0に加えて、いや、偽、とオフがFalseのようにエスケープされ、対応する1、はい、本当、それは真のエスケープされている上、他の値はになりますValueError
例外。
構成アイテムの検索ルールにも注意してください。まず、のConfigParserがあり、コンフィギュレーション・ファイル・フォーマットをサポートする[DEFAULT]
設定項目を読んでは、セクションで指定されていないとき、それはのConfigParserのになり、祭りを[DEFAULT]
見つけるために、セクション。
また、より複雑な設定項目を探すためのプロジェクト原因いくつかのメカニズムがあり、これは、クラスのConfigParserのコンストラクタのパラメータのデフォルト値だけでなく、そのあるget(section, option[, raw[, vars]])
フルネームパラメータvars
。これらのメカニズムがすべて使用されている場合、構成アイテム値の検索ルール:
- セクション名が見つからない場合、NoSectionErrorがスローされます
- 与えられた設定項目が表示された場合には
get()
、メソッドvar
の引数は、返すvar
パラメータの値を - 指定された構成アイテムが指定されたセクションに含まれている場合、その値が返されます
- [DEFAULT]に指定された構成アイテムがある場合、その値を返します
- コンストラクタのdefaultsパラメータで指定された構成アイテムがある場合、その値が返されます
- NoOptionErrorがスローされます
argparseを使用してコマンドライン引数を処理する
アプリケーションは通常、構成ファイルを介してコードを変更せずに動作を変更できますが、次のような柔軟で使いやすいコマンドラインパラメーターを提供することは非常に意味があります。ユーザーの学習コストを削減するには、通常、コマンドラインパラメーターの使用だけで十分です。プログラム名は--helpパラメータを追加することで取得できます。通常、設定ファイルの設定方法は、マニュアルでマスターする必要があります。
コマンドライン処理に関して、この段階でのパラメータ処理の標準ライブラリはargparseです。
add_argument()
このメソッドは、パラメーター宣言を追加するために使用されます。
import argparse
parser = argparse.ArgumentParser(description='Process some integers.')
parser.add_argument('integers', metavar='N', type=int, nargs='+',
help='an integer for the accumulator')
parser.add_argument('--sum', dest='accumulate', action='store_const',
const=sum, default=max,
help='sum the integers (default: find the max)')
args = parser.parse_args()
print(args.accumulate(args.integers))
- 従来型サポートINTの基本値に加えて/ argparseも、同様にフロートサポートされているファイルの種類長い有効なパラメータとして、プログラムは、対応するファイル記述子を使用することができるように、。
parser = argparse.ArgumentParser()
parser.add_argument("bar", type=argparse.FileType("w"))
parser.parse_args(["out.txt"])
- また、型を拡張する方が簡単です。関数などの呼び出し可能なオブジェクトは、typeの引数として使用できます。選択肢パラメータ加えても、のようなより多くの種類を、サポートしています
parser.add_argument("door", type=int, choices=range(1, 4))
。 - さらに、必須パラメーターがTrueに設定されて渡されている限り、add_argument()は必須パラメーターのサポートを提供します。このパラメーターがない場合、argparseは自動的にプログラムを終了し、ユーザーにプロンプトを表示します。
- パラメータのグループ化もサポートされています。add_argument_group()は、ヘルプ情報を出力するときに、より明確にすることができます。これは、複雑な使用法のCLIアプリケーションで非常に役立ちます。
parser = argparse.ArgumentParser(prog="PROG", add_help=False)
group1 = parser.add_argument_group("group1", "group1 description")
group1.add_argument("foo", help="foo help")
group2 = parser.add_argument_group("group2", "group2 description")
group2.add_argument("--bar", help="bar help")
parser.print_help()
- あり
add_mutually_exclusive_group(required=False)
非常に実用的:それは一群のことを保証パラメータ、少なくとも一つだけ1(=真必須)。 - argparseもサポートサブコマンドなど、
pip
そこinstall/uninstall/freeze/list/show
およびその他のサブコマンドは、これらのサブコマンドを、異なるパラメータを受け入れる、ArgumentParser.add_subparsers()を使用し、同様の機能を実現することができます。
import argparse
parser = argparse.ArgumentParser(prog="PROG")
subparsers = parser.add_subparsers(help="sub-command help")
parser_a = subparsers.add_parser("a", help="a help")
parser_a.add_argument("--bar", type=int, help="bar help")
parser.parse_args(["a", "--bar", "1"])
- パラメータ処理に加え、不正なパラメータが出現した場合、ユーザは何らかの処理を行う必要があり、処理が完了すると、通常、プロンプトメッセージが出力され、アプリケーションが終了します。ArgumentParser機能はそれぞれ、2つのメソッドを提供
exit(status=0, message=None)
し、error(message)
保存することができますimport sys
リコールsys.exit()
手続きを。
ピクルスモジュールの長所と短所を理解する
シリアライゼーションは、メモリ内のデータ構造を、オブジェクトのIDとタイプ情報を失うことなく、オブジェクトのテキストまたはバイナリ表現に変換するプロセスです。オブジェクトのシリアル化された形式は、逆シリアル化プロセス後に元のオブジェクトを復元できる必要があります。
Pythonには、pickle、json、marshal、shelveなど、シリアル化をサポートする多くのモジュールがあります。
Pickleは最も一般的なシリアル化モジュールです。また、cPickleのC言語実装を備えています。pickleよりもパフォーマンスが優れています。速度はpickleの約1000倍です。したがって、ほとんどのアプリケーションでcPickleを使用する必要があります。 (注:cPickleを継承できないことを除いて、それらの使用法は基本的に同じです)。二つの最も重要な機能酸洗dump()
とload()
、それぞれ、シリアル化およびデシリアライズオブジェクトに使用します。
ピクルスの優れた特徴は、次の点に要約されています。
-
インターフェースはシンプルで使いやすいです。使用
dump()
してload()
簡単にシリアライズとデシリアライズを達成することができます。 -
pickleのストレージ形式は普遍的で、さまざまなプラットフォームのPythonパーサーで共有できます。たとえば、Linuxでのシリアル化されたフォーマットファイルは、WindowsプラットフォームのPythonパーサーで逆シリアル化でき、互換性が向上します。
-
幅広いデータ型をサポートします。デジタル、ブール、文字列、シリアル化されたオブジェクト等、唯一のタプル、辞書、リストが含まれ、非入れ子関数、クラス、クラスによって
__dict__
、または__getstate__()
インスタンスシリアル化されたオブジェクトなどを返すことができます。 -
pickleモジュールは拡張可能です。インスタンス・オブジェクトの場合、オブジェクトは、一般的に呼び出していないときにピクルスを低減
__init__()
機能する場合に呼び出される__init__()
初期化クラスの古典のためのクラス定義で提供されてもよい、__getinitargs__()
化したりunpickle化したりが、Pythonの自動的に行う場合、機能、およびタプルを返します通話__init__()
、および__getinitargs__()
返されたタプルがに引数として渡さ__init__()
れ、新しいクラスのために提供することができる__getnewargs__()
オブジェクト生成時間を提供するためのパラメータを、するとき化したりunpickle化したりClass.__new__(Class, *arg)
、オブジェクトを作成します。等ソケット、ファイルハンドル、データベース接続、非直列化オブジェクトについては、また、主に特別な方法を介して、滞在ピクルスプロトコルを実装することによって解決することができる__getstate__()
と__setstate__()
インスタンスピクルスのリターン・ステータスに。例:
import cPickle as pickle class TextReader: def __init__(self, filename): self.filename = filename # 文件名称 self.file = open(filename) # 打开文件的句柄 self.postion = self.file.tell() # 文件的位置 def readline(self): line = self.file.readline() self.postion = self.file.tell() if not line: return None if line.endswith("\n"): line = line[:-1] return "{}: {}".format(self.postion, line) def __getstate__(self): # 记录文件被 pickle 时候的状态 state = self.__dict__.copy() # 获取被 pickle 时的字典信息 del state["file"] return state def __setstate__(self, state): # 设置反序列化后的状态 self.__dict__.update(state) file = open(self.filename) self.file = file reader = TextReader("zen.text") print(reader.readline()) print(reader.readline()) s = pickle.dumps(reader) # 在 dumps 的时候会默认调用 __getstate__ new_reader = pickle.loads(s) # 在 loads 的时候会默认调用 __setstate__ print(new_reader.readline())
-
オブジェクト間の参照を自動的に維持できます。オブジェクトに複数の参照がある場合、pickleはオブジェクト間の参照を変更せず、循環参照と再帰参照を自動的に処理できます。
>>> a = ["a", "b"] >>> b = a # b 引用对象 a >>> b.append("c") >>> p = pickle.dumps((a, b)) >>> a1, b1 = pickle.loads(p) >>> a1 ["a", "b", "c"] >>> b1 ["a", "b", "c"] >>> a1.append("d") # 反序列化对 a1 对象的修改仍然会影响到 b1 >>> b1 ["a", "b", "c", "d"]
ただし、pickleの使用には次の制限もあります。
- Pickleは操作の原子性を保証できません。ピクルはアトミック操作ではないため、ピクル呼び出し中に例外が発生した場合、データの一部が保存されている可能性があります。さらに、オブジェクトが深い再帰状態にある場合、Pythonの最大再帰深度を超える可能性があります。再帰の深さをできる
sys.setrecursionlimit()
拡張します。 - Pickleにはセキュリティの問題があります。Pythonのドキュメントには、セキュリティが保証されていないことが明記されているため、信頼できないデータソースから受信したデータを簡単にデシリアライズしないでください。load()は文字列をパラメータとして受け取ることができるため、適切に設計された文字列は侵入の可能性を提供します。Pythonインタプリタのコードを入力し
pickle.loads("cos\nsystem\n(S'dir\ntR.")
、現在のディレクトリ内のすべてのファイルを閲覧することができます。dirを他のより破壊的なコマンドに置き換えることができます。セキュリティをさらに強化するために、ユーザーはを通じて継承されたクラスpickle.Unpicklerを上書きすることができますfind_class()
達成するための方法。 - pickleプロトコルはPythonに固有であり、異なる言語間の互換性を保証することは困難です。Pythonで作成されたピクルファイルは、他の言語では使用できない場合があります。
シリアル化JSONのもう1つの優れたオプション
Pythonの標準ライブラリJSONが提供する最も一般的なメソッドはpickleに似ており、ダンプ/ダンプはシリアル化に使用され、ロード/ロードは逆シリアル化に使用されます。jsonはデフォルトでは非ASCIIベースのエンコーディングをサポートしていないことに注意してください。中国語の文字を処理するときにloadメソッドが正しく表示されない場合は、encodingパラメータで対応する文字エンコーディングを指定する必要があります。シリアライゼーションに関して、JSONにはピクルに比べて次の利点があります。
- 使い方は簡単で、複数のデータ型をサポートしています。JSONドキュメントの構成は非常に単純です。主なデータ構造は2つだけです。
- 名前と値のペアのコレクション。さまざまな言語で、オブジェクト、レコード、構造、辞書、ハッシュテーブル、キーリスト、または連想配列として実装されます。
- 値の順序付きリスト。ほとんどの言語では、配列、ベクトル、リスト、またはシーケンスとして実装されます。Pythonでサポートされている対応するデータ型には、辞書、リスト、文字列、整数、浮動小数点数、True、False、Noneなどがあります。JSONのデータ構造とPythonの変換は厳密には1対1の対応ではなく、特定の違いがあります。
- 保存形式は、より読みやすく、簡単に変更できます。pickleと比較すると、json形式はプログラマーの考えに近く、読みやすく、変更も簡単です。dumps()関数は、生成されたjsonファイルを読みやすくするためのパラメーターインデントを提供します。0は「各値が別の行にある」ことを意味します。0より大きい数値は「各値が別の行にあり、この番号のスペースを使用してネストされたデータ構造をインデントします。ただし、このパラメーターはファイルサイズが大きくなるという犠牲を払うことに注意してください。
- jsonは、クロスプラットフォームおよびクロス言語の操作をサポートしています。たとえば、Pythonで生成されたjsonファイルはJavaScriptを使用して簡単に解析でき、相互運用性はより強力ですが、ピクル形式ファイルはPython言語でのみサポートされます。さらに、jsonのネイティブJavaScriptサポートであるクライアントブラウザーは、このために追加のインタープリターを使用する必要がなく、特にWebアプリケーションが高速でコンパクトで便利なシリアル化操作を提供するのに適しています。さらに、pickleと比較して、jsonのストレージ形式はよりコンパクトであり、占有するスペースも少なくなります。
- 強力なスケーラビリティがあります。jsonモジュールはエンコード(JSONEncoder)とデコードクラス(JSONDecoder)も提供するため、ユーザーはデフォルトでサポートしていないシリアル化タイプを拡張できます。
Pythonの標準モジュールjsonのパフォーマンスは、pickleやcPickleよりもわずかに劣ります。シリアル化のパフォーマンスに対する要件が非常に高い場合は、cPickleモジュールを使用できます。
スレッドモジュールを使用してマルチスレッドプログラムを作成する
GILは、マルチスレッド複数のプロセッサを利用することが一時的にできないのPythonプログラミング、および稼働率を向上させることができないが、いくつかのケースでは、などの存在なる復帰に外部リソースを待っている、またはユーザ・エクスペリエンスを向上させ、柔軟なユーザインタフェース反応を作成するためには、または、マルチユーザーアプリケーションでは、マルチスレッドがより優れたソリューションです。
Pythonは、マルチスレッドプログラミング用に、スレッドとスレッドという2つの非常にシンプルで明確なモジュールを提供します。
スレッドモジュールはマルチスレッドの低レベルサポートモジュールを提供し、低レベルでプリミティブな方法でスレッドを処理および制御します。これは使用がより複雑です。スレッドモジュールはスレッドに基づいてパッケージ化され、スレッドの操作はオブジェクト化されているため、言語レベルで豊富な機能を提供します。実際のアプリケーションでは、スレッドモジュールではなくスレッドモジュールを最初に使用することをお勧めします。
-
スレッドの同期と相互排除に関しては、Lock命令ロック、RLock再入可能命令ロックだけでなく、条件変数Condition、セマフォSemaphore、BoundedSemaphore、およびEventイベントもスレッドモジュールでサポートされています。
-
スレッド化モジュールのメインスレッドとサブスレッドは対話型であり、
join()
メソッドは、このメソッドを呼び出すスレッドが終了するか、指定されたタイムアウト(オプションのパラメーター)に達するまで、現在のコンテキストのスレッドをブロックできます。このメソッドを使用すると、メインスレッドとサブスレッドの実行、およびサブスレッド間の実行を簡単に制御できます。
実際、多くの場合、終了する前にすべてのサブスレッドが完了するのをメインスレッドに待機させたい場合があります。このとき、スレッド化モジュールを使用してスレッドを保護します。スレッドのデーモン属性は、setDaemon()関数で設定できます。デーモン属性がTrueに設定されている場合、メインスレッドは子スレッドの完了を待たずに終了できます。デフォルトでは、デーモンフラグはFalseであり、メインスレッドはデーモン以外のすべてのスレッドが終了した後に終了します。
import threading
import time
def myfunc(a, delay):
print("I will calculate square of {} after delay for {}".format(a, delay))
time.sleep(delay)
print("calculate begins...")
result = a * a
print(result)
return result
t1 = threading.Thread(target=myfunc, args=(2, 5))
t2 = threading.Thread(target=myfunc, args=(6, 8))
print(t1.isDaemon())
print(t2.isDaemon())
t2.setDaemon(True)
t1.start()
t2.start()
Queueを使用してマルチスレッドプログラミングをより安全にする
マルチスレッドプログラミングは簡単な作業ではありません。スレッド間の同期とスレッド間の相互排除、スレッド間のデータの共有などはすべて、スレッドの安全性に関して考慮すべき問題です。
PythonのQueueモジュールは、3種類のキューを提供します。
-
Queue.Queue(maxsize)
:FIFOキューは無限ループで、非正であるMAXSIZEキューサイズ、 -
Queue.LifoQueue(maxsize)
:後入れ先出し、スタックと同等 -
Queue.PriorityQueue(maxsize)
:優先キュー
これら3つのキューは、次のメソッドをサポートしています。
Queue.qsize()
:キューのサイズを返します。Queue.empty()
:キューが空の場合はtrue、それ以外の場合はfalseQueue.full()
:キューサイズが設定されている場合、キューがいっぱいの場合はTrueを返し、それ以外の場合はFalseを返します。Queue.put(item[, block[, timeout]])
:要素項目をキューに追加するときに、blockがFalseに設定されている場合、キューがいっぱいになるとFull例外がスローされます。ブロックがTrueに設定されている場合、タイムアウトがNoneの場合、空の位置になるまで待機します。それ以外の場合は、タイムアウト設定に従ってタイムアウト後にフル例外をスローします。Queue.put_nowait(item)
:等しいput(item, False).block
Falseに例外が空に投げられた場合にキューが空です。ブロックがTrueに設定され、タイムアウトがNoneの場合、使用可能な要素が存在するようになるまで待機します。それ以外の場合は、タイムアウト設定に従ってタイムアウト後に空の例外をスローします。Queue.get([block[, timeout]])
:キューから要素を削除し、要素の値を返しますQueue.get_nowait()
:に相当get(False)
Queue.task_done()
:エンキュータスクが完了したことを示す信号を送信します。コンシューマスレッドでよく使用されますQueue.join()
:キュー内のすべての要素が処理されるまでブロックします
Queueモジュールはスレッドセーフです。Queueモジュールのキューは、collections.dequeで表されるキューと同じではないことに注意してください。前者は主に異なるスレッド間の通信に使用され、内部でスレッドロックメカニズムを実装しますが、後者は主にデータ構造にあります。コンセプト。
マルチスレッドダウンロードの例:
import os
import Queue
import threading
import urllib2
class DownloadThread(threading.Thread):
def __init__(self, queue):
threading.Thread.__init__(self)
self.queue = queue
def run(self):
while True:
url = self.queue.get() # 从队列中取出一个 url 元素
print(self.name + "begin download" + url + "...")
self.download_file(url) # 进行文件下载
self.queue.task_done() # 下载完毕发送信号
print(self.name + " download completed!!!")
def download_file(self, url): # 下载文件
urlhandler = urllib2.urlopen(url)
fname = os.path.basename(url) + ".html" # 文件名称
with open(fname, "wb") as f: # 打开文件
while True:
chunk = urlhandler.read(1024)
if not chunk:
break
f.write(chunk)
if __name__ == "__main__":
urls = ["https://www.createspace.com/3611970","http://wiki.python.org/moni.WebProgramming"]
queue = Queue.Queue()
# create a thread pool and give them a queue
for i in range(5):
t = DownloadThread(queue) # 启动 5 个线程同时进行下载
t.setDaemon(True)
t.start()
# give the queue some data
for url in urls:
queue.put(url)
# wait for the queue to finish
queue.join()