なぜこのPythonコードはインポート/コンパイルでハングしますが、シェルで動作しますか?
-
06-07-2019 - |
質問
Pythonを使用してファイルをsftpしようとしていますが、コードはインタラクティブシェルでうまく機能します。一度にすべてを貼り付けることもできます。
ファイルを(コンパイルするために)インポートしようとすると、例外または明らかなエラーなしでコードがハングします。
どのようにコードをコンパイルしますか、または誰かが他の方法でsftpを実行する作業コードを持っていますか?
このコードは、ssh.connect()ステートメントでハングします。
""" ProblemDemo.py Chopped down from the paramiko demo file. This code works in the shell but hangs when I try to import it! """ from time import sleep import os import paramiko sOutputFilename = "redacted.htm" #-- The payload file hostname = "redacted.com" ####-- WARNING! Embedded passwords! Remove ASAP. sUsername = "redacted" sPassword = "redacted" sTargetDir = "redacted" #-- Get host key, if we know one. hostkeytype = None hostkey = None host_keys = {} try: host_keys = paramiko.util.load_host_keys(os.path.expanduser('~/.ssh/known_hosts')) except IOError: try: # try ~/ssh/ too, because windows can't have a folder named ~/.ssh/ host_keys = paramiko.util.load_host_keys(os.path.expanduser('~/ssh/known_hosts')) except IOError: print '*** Unable to open host keys file' host_keys = {} if host_keys.has_key(hostname): hostkeytype = host_keys[hostname].keys()[0] hostkey = host_keys[hostname][hostkeytype] print 'Using host key of type %s' % hostkeytype ssh = paramiko.Transport((hostname, 22)) ssh.connect(username=sUsername, password=sPassword, hostkey=hostkey) sftp = paramiko.SFTPClient.from_transport(ssh) sftp.chdir (sTargetDir) sftp.put (sOutputFilename, sOutputFilename) ssh.close()
解決 3
奇妙さはさておき、インポートを使用してコードをコンパイルしていました。スクリプトを関数に変換することは、この種のアプリケーションにとっては不要な複雑さのようです。
別のコンパイル手段を検索して見つけました:
import py_compile py_compile.compile("ProblemDemo.py")
これにより、意図したとおりに動作するpycファイルが生成されました。 したがって、学んだ教訓は、インポートはPythonスクリプトをコンパイルするための堅牢な方法ではないということです。
他のヒント
これはインポート時にこの種のコードを実行するのは本当に悪い考えですが、なぜそれがハングするのかはわかりません-インポートメカニズムがparamikoとひどく相互作用する奇妙な何かをするかもしれません(スレッド関連の問題かもしれません?)とにかく、通常の解決策は、機能を関数に実装することです:
def my_expensive_function(args):
pass
if __name__ == '__main__':
import sys
my_expensive_functions(sys.args)
この方法では、モジュールをインポートするだけでは何も行われませんが、スクリプトを実行すると、コマンドラインで指定された引数で関数が実行されます。
これは直接的な理由ではないかもしれませんが、「まれにあなたはこれまでにない」「機能」を持ちたいと思っています。インポート時に実行されます。通常、クラスまたは関数を定義して、次のように呼び出します。
import mymodule
mymodule.run()
" global"インポートで実行するコードは通常、インポート、変数定義、関数およびクラス定義などに限定する必要があります...