質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
import

自身のプラットフォーム・プログラム・データセットに対して、外部ソースを取り込むプロセスをimportと呼びます。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

マイコン

マイクロコンピュータの略で、CPUにマイクロプロセッサを用いたコンピュータのこと。家電製品、電磁機器などの制御に用いられています。単体でコンピュータとしての機能を一通り備えています。 現代のパーソナルコンピュータに近く、同時期のメインフレームやミニコンピュータと比べ、小さいことが特徴です。

Q&A

解決済

4回答

2502閲覧

With 命令で__exit__がないと言われるのはなぜか

BuhKeil

総合スコア34

import

自身のプラットフォーム・プログラム・データセットに対して、外部ソースを取り込むプロセスをimportと呼びます。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

マイコン

マイクロコンピュータの略で、CPUにマイクロプロセッサを用いたコンピュータのこと。家電製品、電磁機器などの制御に用いられています。単体でコンピュータとしての機能を一通り備えています。 現代のパーソナルコンピュータに近く、同時期のメインフレームやミニコンピュータと比べ、小さいことが特徴です。

0グッド

0クリップ

投稿2020/08/17 21:43

編集2020/08/17 22:19

やりたいこと

ESP32と結線しているBMR280(温度湿度圧力センサ)のデータを
ローカルで待機させているサーバに転送できるようにしたい。

環境

Windows10 64bit版
micro python version 1.12
ターミナルソフトウェア: PuTTY(version 0.74)

micropython(データを転送する側 client.py) のコード

(空白でインデントができないので--->でインデントを表現しました)

micropython

1import machine 2import utime 3import bme280 4import usocket 5 6i2c = machine.I2C(scl=machine.Pin(22), sda=machine.Pin(21), freq=10000) 7 8line = 0 9 10while True: 11 bme = bme280.BME280(i2c=i2c) 12 13 temp_bme280 = bme.temperature 14 buf += str(temp_bme280) + "\n" 15 hum_bme280 = bme.humidity 16 pres_bme280 = bme.pressure 17 18 print("[BME280] Temperature: " + str(temp_bme280)) 19 print("[BME280] Humidity: " + str(hum_bme280)) 20 print("[BME280] Pressure: " + str(pres_bme280), end="\n") 21 22 with usocket.socket(usocket.AF_INET, usocket.SOCK_STREAM) as client: 23 client.connect(("192.168.0.4", 50755)) 24 client.sendall(buf.encode()) 25 data = client.recv(1024).decode() 26 print(repr(data)) 27 28 print(buf) 29 line += 1 30 utime.sleep(5) 31 32fp.close()

データを受け取る(サーバ側 server.py)のmicro pythonのコード

from datetime import datetime import socket print("The server started at ", datetime.now()) print("Waiting ...") with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.bind(("127.0.0.1", 50755)) s.listen(1) while True: conn, addr = s.accept() with conn: while True: data = conn.recv(1024) if not data: break print("data: ", data, "addr", addr) conn.sendall(b"Receive: " + data)

実行したこと

  1. コマンドプロンプトを起動し、サーバ側のmicro python(server.py)を実行する。
  2. 2つめのコマンドプロンプトから、クライアント側のmicro python(client.py)を実行する。

発生するエラー

Trackback (most recent call last)
File "client.py", in Line 70, in <module>(←client.pyのwith...の行)
AttributeError: "socket" object has no attribute "exit"

となります。再現性があります。
どのように対処すれば良いのでしょうか。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

BuhKeil

2020/08/17 22:19

ご指摘ありがとうございます。修正しました。
guest

回答4

0

ベストアンサー

他の方の回答をまとめておきます。
まず、ご使用のMicroPython1.12で、socketに対してwithが使えるのか?という点です。

(1)なぜWithでエラーになっているのか?

Trackback (most recent call last)
File "client.py", in Line 70, in <module>(←client.pyのwith...の行)
AttributeError: "socket" object has no attribute "exit"

とのことなので、socketオブジェクトにexitがないからということになります。どういうことかというと...

https://docs.python.org/ja/3/reference/compound_stmts.html#the-with-statement

↑に書かれているとおり、withというのは処理が終わった後に指定したオブジェクトの__exit__()を呼ぶからです。

(2)socketには__exit__()は用意されてないのか?

tajin_nabeさんの回答にあるとおり、CPython(普通のPython)ではsocketの__exit__()は3.2で導入されたそうです。つまりそれ以前だとありません。つまりwithが使えないということです。

(3)MicroPython1.12はCPythonのどのバージョンに対応しているのか?

http://docs.micropython.org/en/latest/genrst/index.html

The operations listed in this section produce conflicting results in MicroPython when compared to standard Python. MicroPython implements Python 3.4 and some select features of Python 3.5.

基本3.4で一部3.5のようです。
つまり(2)についてはバージョン的には問題ないようです。

(4)MicroPython 1.12のsocketには__exit__()はあるのか?

http://docs.micropython.org/en/latest/library/usocket.html

そもそもsocketではなく、usocketです。似てるけど違いそうですね。
もちろん仕様上exitも__exit__もありません。

CPythonのsocketではどうなっているかというと...

https://docs.python.org/ja/3/library/socket.html#module-socket

仕方がないのでコードから追うと...
まずはCPython3.8から、

https://github.com/python/cpython/blob/3.8/Lib/socket.py

Python

1 def __exit__(self, *args): 2 if not self._closed: 3 self.close()

ありますね。

MicroPythonはCPythonと仕組みが全く違っていて、基本Cで書かれており、明確にどこで文を処理しているか確信が持てなかったので(多分modusocket.c)、thkanaさんの実行環境からの結果に頼ります。

['class', 'close', 'read', 'readinto', 'readline', 'send', 'write', 'del', 'accept', 'bind', 'connect', 'fileno', 'listen', 'makefile', 'recv', 'recvfrom', 'sendall', 'sendto', 'setblocking', 'setsockopt', 'settimeout']

ない!と。

従って、MicroPythonではsocketモジュールがCPythonと違っており、withに対応していない、ということです。

対策

対策は、tajin_nabeさんのおっしゃるとおり、try~exception~finally構文がいいでしょう。まずは上の最初の方のリンク上げたとおり、withと等価なtry~exception~finally構文

Python

1with EXPRESSION as TARGET: 2 SUITE

Python

1manager = (EXPRESSION) 2enter = type(manager).__enter__ 3exit = type(manager).__exit__ 4value = enter(manager) 5hit_except = False 6 7try: 8 TARGET = value 9 SUITE 10except: 11 hit_except = True 12 if not exit(manager, *sys.exc_info()): 13 raise 14finally: 15 if not hit_except: 16 exit(manager, None, None, None)

を見て、書き換えると...(端末は除外)

python

1hit_except = False 2s = None 3 4try: 5 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 6 元の処理 7except: 8 hit_except = True 9 raise 10finally: 11 if not hit_except and s is not None: 12 s.close()

※未確認

投稿2020/08/19 19:42

編集2020/08/19 19:53
dameo

総合スコア943

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

BuhKeil

2020/08/23 06:41

try:except:finally:の構文で書き直したら無事に通信することができました。 ありがとうございました。
guest

0

with というのは、そもそも、そのオブジェクトを開いて(生成)、処理終了時に確実に閉じる(破棄)、というのが前提の命令です
閉じる(破棄する)必要のないオブジェクトはwithの対象になりません。

ということで、withに使用することを前提をするのであれば、閉じる(破棄する)メソッドを実装しておく必要があります
#それが空のメソッドでも可

投稿2020/08/17 23:42

y_waiwai

総合スコア87774

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

BuhKeil

2020/08/18 23:17

コメントありがとうございます。 仕事でなかなk時間が取れず確認作業が手についていません。 もう少し時間をください。
BuhKeil

2020/08/23 06:42

try:except:finally:の構文で書き直したら無事に通信することができました。 ありがとうございました。
guest

0

cl=usocket.socket(usocket.AF_INET, usocket.SOCK_STREAM)
dir(cl)
として実装されているメソッドを覗いてみると、
['__class__', 'close', 'read', 'readinto', 'readline', 'send', 'write', '__del__', 'accept', 'bind', 'connect', 'fileno', 'listen', 'makefile', 'recv', 'recvfrom', 'sendall', 'sendto', 'setblocking', 'setsockopt', 'settimeout']
とのことなので、たしかに__enter__とか__exit__が無いですね。microPythonで実装されているのがsocketのサブセットとのことなのでそういうことなのでしょう。
withには載らないので、使い終わったら自分でclose()することになりそうです。

投稿2020/08/17 23:24

thkana

総合スコア7639

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

BuhKeil

2020/08/18 23:17

コメントありがとうございます。 仕事でなかなk時間が取れず確認作業が手についていません。 もう少し時間をください。
BuhKeil

2020/08/23 06:42

try:except:finally:の構文で書き直したら無事に通信することができました。 ありがとうございました。
guest

0

以下のサイトが参考になりませんかね。

https://stackoverflow.com/questions/49472282/python-socket-attributeerror-exit

> support for using a context manager (i.e. with socket.socket()) was added in Python 3.2.
with socket.socket()はPython 3.2で追加されました、とあるので、
micropython では使えないのかもですね。

try, except, finallyを使って書いてはどうでしょうか。

投稿2020/08/17 23:01

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

BuhKeil

2020/08/18 23:17

コメントありがとうございます。 仕事でなかなk時間が取れず確認作業が手についていません。 もう少し時間をください。
BuhKeil

2020/08/23 06:42

try:except:finally:の構文で書き直したら無事に通信することができました。 ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問