次のメソッドがあるとします。
_def read(file: str) -> List[str]:
temp = []
with open(file) as f_obj:
for line in f_obj:
temp.append(line)
return temp
def append_items_to_list(folders : List[str], file: str):
with open(file) as f_obj:
for line in f_obj:
folders.append(line)
def main():
source: str = "source.txt"
directories : List[str] = read(file=source)
print(len(directories))
folderList : List[str] = []
append_items_to_list(folders=folderList, file=source)
print(len(folderList))
if __name__ == '__main__':
main()
_
どちらのメソッドもファイルから読み取り、List
にアイテムを追加します。最初のメソッドは一時的なList
を作成して返しますが、2番目のメソッドはList
をパラメーターとして受け入れ、それに追加します。
どちらが望ましいかを示すガイドラインはありますか?どちらかについて心配する必要があるとは思わない根本的な問題はありますか?
新しいList
を作成する必要がある理由を確認する必要があると思います。この場合、新しいList
を作成する必要はありません。2番目の方法を使用できます。
説明:
一般的な答えは新しいList
を返すことですが、問題をもう少し絞り込みました。
_def do_work(source: Path, destination: Path):
# do some work with the folders.
def create_list_of_empty_folders(folders : List[str], folder: Path):
# Check if folder is empty, if so, append it to the List.
def cleanup(folders_to_remove: List[Path]):
# Remove all folders in the List from the HD.
def main():
portableHD = Path("Path\\to\\HD")
USB = Path("Path\\to\\USB")
empty_folders : List[Path] = []
for folder in portableHD.iterdir():
do_work(source=folder, destination=USB)
create_list_of_empty_folders(folders=empty_folders, folder=folder)
# Outside of the for loop we can safely remove the empty folders.
cleanup(folders_to_remove=empty_folders)
if __name__ == '__main__':
main()
_
このコンテキストでは、List
とfolder
を関数に渡す以外に選択肢はありません。明らかに、関数を使用せずにforループでコードを書き出すことができますが、クリーンで保守可能なコードを書きたいとしましょう。
最初の例では、実際に関数を使用する必要はありません。データを読み取り、List
に直接main
メソッドで追加できます。
_def main():
file: str = "source.txt"
folders : List[str] = []
with open(file) as f_obj:
for line in f_obj:
folders.append(line)
if __name__ == '__main__':
main()
_
しかし、これらの各フォルダーでさらに多くの作業を行う必要があると想定して、コードをリファクタリングしてより小さなメソッドを作成します。なぜ関数から一時的なList
を返すのが望ましいのでしょうか。
関数は本当に、呼び出し元の目的が追加であることを知っている必要がありますか?
呼び出し元がList
に追加したいことを関数が認識できないのはなぜですか?結局のところ、コードをより小さな関数に分解し、そのうちの1つをList
に追加しました。メソッドの名前をappend(folders : List[str], file: str)
に変更したとしても、関数のパラメーターは追加したいものを示します。
そのような普遍的なガイドラインはありません。
言語イディオム、言語機能、パフォーマンス、プログラミングパラダイム(関数指向など)などの言語固有の側面を無視すると、いくつかの経験則があります。
操作のsemanticに応じて、実装する関数の最も広い再利用の可能性を検討します。
あなたの例では、それはフォルダ内のファイルの新しいリストを作成することです。関数は本当に、呼び出し元の目的が追加であることを知っている必要がありますか?それとも、リストの所有権を考慮せずに、通常はうまく機能するでしょうか?新しいリストを返して、発信者に何をするかを決定させます。
説明
これらは経験則ですが、作成するすべてのプログラムについて、設計上の決定はあなた次第です。
特定のユースケースでは、大きな関数を小さな関数に分割することにしました。これは設計上の決定です。つまり、原則として最初のケースです。リストは、全体的な処理を担当する呼び出し元によって所有され、関数はその一部のみを実行します。
何も問題はなく、ここで止めることができます。次に、再利用の可能性についてのポイントが来ます。個人的には、他の場合にもフォルダのリストの多くの用途を見ることができます。これが、デザインの決定を修正し、関数をリファクタリングして新しいリストを作成し、呼び出し側に追加を行わせる理由です。再利用の機会が見当たらない場合は、ぜひお試しください。
リストについてさらに多くのことがある場合でも、私はそれを一般的に保ち、呼び出し元がリストの要素に関数を適用できるようにします(関数は、名前の変更、日付のタッチ、移動、印刷、 ...)。しかし、繰り返しますが、おそらく私が見る可能性はあなたの場合には関係ありません。最終的に選択はあなた次第です。他に理由がある場合は、いかなる規則もあなたに選択を指示することはありません。
私がお勧めするガイドラインは次のとおりです。
ユーザーに不要な制限をかけないでください。
リストをパラメーターとして受け取る場合、ユーザーが提供するアイテムよりも多くのアイテムを必要としていない場合でも、ユーザーはリストを作成して渡す必要があります。それにより、コードは他の場合よりも使用するのが面倒になります。