私はかつてPythonで小さなことを書いたことがあります
しかし、最近、内部のインターフェースが突然失敗しました。
私がウェブサイトにアクセスしたとき、彼らはインターフェースを直接オフにし、機能はWeChat公式アカウントに移行されました。
その後、彼を率いた同級生は、彼を率いる本能に基づいて、wxpyというライブラリを直接見つけました。
pip install wxpy
wxpy→ドキュメントアドレス
元のコードでは、この関数は完全にカプセル化されているため、彼がしなければならないのは、カプセル化されたインターフェイスを置き換えるだけで、それを引き続き楽しく使用できます。
しかし、私が予期していなかったことは、WeChatを使用してそれを達成しようとすることは、以前の直接パケットgetとは大きく異なることです。
-
クローラーを使用して、他のインターフェースを直接調整します。入力→インターフェースの内部処理→出力リターン、どちらの端であっても、それはプロセス全体です。
-
WeChatを使用して、メッセージの入力と送信→インターフェイスの内部処理(応答を待機)→出力の戻りを実現します。これは非常に異なり、問題は応答を待機することにあります。
入力→処理→出力をカプセル化された関数とすると、クローラーのクロールは同期プロセスですが、WeChatでのメッセージの送受信は非同期プロセスであるため、相手からの応答を待つ必要があります。
一流の同級生はそれを解決できなかったので、彼は私に来ました。
書類を見つけて簡単に読んだのですが、クラスメートの話を聞いてすぐにどうしたらいいかわかりました。
msg_received = False # 是否收到消息的状态标志
msg = '' # 消息
@bot.register(chat_obj) # 这里相当于为一个聊天对象注册了一个回调函数,当收到来自它的消息时回调
def getMsg(in_msg):
msg_ = in_msg
msg_received = True # 改变状态标志
def query(question):
chat_obj.send_msg(question)
while msg_received != True:
pass # 等待,直到状态标志改变
msg_received = False
return msg
もちろん、このように記述してもかまいません。分離されたパーツをつなぎ合わせるのは自然なことですが、エレガントな大学生として、コードでこのような結合度の低下をどのように許容できますか。
インターフェイスはエレガントでなければなりません!
今、私たちはトピックを入力しようとしています
だから私は達成するためにクロージャを使用しようとしました:
def initial(chat_obj):
msg_received = False # 是否收到消息的状态标志
msg = '' # 消息
@bot.register(chat_obj) # 这里相当于为一个聊天对象注册了一个回调函数,当收到来自它的消息时回调
def getMsg(in_msg):
msg_ = in_msg
msg_received = True # 改变状态标志
def query(question):
chat_obj.send_msg(question)
while msg_received != True:
pass # 等待,直到状态标志改变
msg_received = False
return msg
return main_fun
このロジックがjsで実装されている場合、問題はありません。
ただし、これはPythonであり、例外が発生します。
NameError:名前 'msg_received'が定義されていません
主な理由は、Pythonの基盤が貧弱で、体系的に学習していないことです。毎日のチューニングなどです。
何か問題が発生した場合は、それをチェックして今すぐ学習してください。
それはどれほど悪いですか?少し前に、私はトライが何のためにあるのかを学びました。
この例外を振り返ると、彼はクエリ関数のmsg_receivedが定義されていないと述べました。
疑問符がいっぱいですが、外側のスコープで探してみませんか?
不完全な基本的なPython構文を単純にめくった後、グローバルについて考えたので、関数の先頭でmsgとmsg_receivedをglobalで宣言しました。
もちろん、結果はまだ間違っていますが、私がそれについて考えると、問題を解決するという私の考えは正しいですが、私の文法の知識は十分ではありません。
それで情報を探し始めて、探したらこのブログに目を向けました→ https://www.jianshu.com/p/17a9d8584530
とても良かったし、問題の解決方法もとても簡単でした。関数の先頭で宣言するには、nolocalを使用します。変数は「非ローカル変数」で問題ありません。
このとき、jsを書くことに慣れていたとき、Pythonの可変スコープメカニズムがjsのそれとは少し違うことに気づきました。
Pythonとjsのクロージャ
簡単に言えば、何もしなければ、Pythonは、jsの反対である外部スコープから検索するのではなく、ローカル変数の定義を優先します。
Pythonコードの一部を見てください:
def fun():
b = 1
def getb():
return b
return getb
getb = fun()
print(getb())
出力:
1
非常に正常ですよね?
次に、Pythonコードの一部を見てみましょう。
def fun():
b = 1
def getb():
b += 1
return b
return getb
getb = fun()
print(getb())
エラー
UnboundLocalError:割り当て前に参照されたローカル変数 'b'
彼が意味したのは、bを使用する前に値を割り当てなかったということです。
冒頭で述べたように、Pythonはローカル変数の定義を優先します。bが左辺値になると、Pythonインタープリターはそれをローカル変数として直接使用します。
したがって、bに値を割り当てるときに、式でbを参照することはできません。
Pythonコードの一部を見てみましょう:
def fun():
b = 1
def getb():
b = 2
return b
return getb
getb = fun()
print(getb())
出力:
2
この例の目的は、出力2が外部スコープのbではなく、getb関数のローカル変数bであることを示して思い出させることです。
したがって、正しい記述は次のようになります。
def fun():
b = 1
def getb():
nonlocal b
b += 1
return b
return getb
getb = fun()
print(getb())
Pythonとは異なり、jsでは、インタプリタは最初に外部スコープでそれを探します
Pythonでのこのアプローチは、非常に悪いプログラミング習慣を助長していると思います。いかなる状況でも、外部スコープと同じ名前の変数をクロージャ関数で宣言しないでください。
jsでは、クロージャ関数が外部スコープの変数と同じ意味を持つローカル変数を使用する必要がある場合、区別のためにlocal_プレフィックスをプレフィックスとして付けます。
だからそれでいい。