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

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

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

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

Raspberry Pi

Raspberry Piは、ラズベリーパイ財団が開発した、名刺サイズのLinuxコンピュータです。 学校で基本的なコンピュータ科学の教育を促進することを意図しています。

Python

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

Q&A

2回答

294閲覧

Pythonプログラムにて、他のpyプログラムが呼び込むには(環境:Raspberry Pi Pico)

nihonnnoheso

総合スコア6

import

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

Raspberry Pi

Raspberry Piは、ラズベリーパイ財団が開発した、名刺サイズのLinuxコンピュータです。 学校で基本的なコンピュータ科学の教育を促進することを意図しています。

Python

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

1グッド

0クリップ

投稿2024/03/11 14:04

現状

自分は、Raspberry Pi Picoを用いて、
「タクトスイッチが押されたら、LEDライトが一秒間点灯する」という、簡易的な回路を作りました
イメージ説明

プログラムは以下の通りとなります

from machine import Pin import time led1 = Pin(15, Pin.OUT) tact1 = Pin(16, Pin.IN, Pin.PULL_DOWN) led2 = Pin(14, Pin.OUT) tact2 = Pin(17, Pin.IN, Pin.PULL_DOWN) led3 = Pin(13, Pin.OUT) tact3 = Pin(26, Pin.IN, Pin.PULL_DOWN) while True: if tact1.value() == 1: led1.value(1) time.sleep(1) led1.value(0) time.sleep(1) if tact2.value() == 1: led2.value(1) time.sleep(1) led2.value(0) time.sleep(1) if tact3.value() == 1: led3.value(1) time.sleep(1) led3.value(0) time.sleep(1)

実現したいこと

このプログラムを短縮したいと思い、
「スイッチが押されたら、別のpyプログラムを呼び込む」という方法を取りたいと思いました

そこで、「別のpyファイルを読み込む方法」で検索をかけ、
「main.py」と同じディレクトリに保存し、「import」で呼び込むという方法を知りました

そこで、「main.py」と同じディレクトリに、「green.py」「yellow.py」「red.py」の三つのプログラムを作成、以下のように書き直しました

main.py==================== from machine import Pin import time led1 = Pin(15, Pin.OUT) tact1 = Pin(16, Pin.IN, Pin.PULL_DOWN) led2 = Pin(14, Pin.OUT) tact2 = Pin(17, Pin.IN, Pin.PULL_DOWN) led3 = Pin(13, Pin.OUT) tact3 = Pin(26, Pin.IN, Pin.PULL_DOWN) while True: if tact1.value() == 1: import green.py if tact2.value() == 1: import yellow.py if tact3.value() == 1: import red.py green.py================- from machine import Pin import time led1 = Pin(15, Pin.OUT) led1.value(1) time.sleep(1) led1.value(0) time.sleep(1) yellow.py================- from machine import Pin import time led2 = Pin(14, Pin.OUT) led2.value(1) time.sleep(1) led2.value(0) time.sleep(1) red.py================- from machine import Pin import time led3 = Pin(13, Pin.OUT) led3.value(1) time.sleep(1) led3.value(0) time.sleep(1)

発生している問題・エラーメッセージ

このプログラムを走らせると、
1回タクトスイッチを押した時は問題なくプログラムが動くのですが、
2回目にタクトスイッチを押すと、以下のようなエラーが発生します

Traceback (most recent call last): File "<stdin>", line 16, in <module> ImportError: no module named 'yellow.py' >>>

試したこと

プログラムの中で「import」したpyプログラムが、終了されずにずっと動き続けているから、
同じスイッチを二回押した時にエラーを起こしていると判断しました。

green.pyの最後に「machine.reset() 」をかけることで、運用できることは確認しました
これは前に質問した、プログラムの管理外に処理を放り投げるということでダメだということはわかっています

どうにかして、「プログラムを呼び出しては終了、呼び出しては終了」という形にすればよいと思うのですが、それはどうすればよいのでしょうか?

補足

そもそも、「import」以外に、同じディレクトリのpyファイルを読み込む方法はあるのでしょうか?

melian👍を押しています

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

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

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

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

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

melian

2024/03/11 14:23

> そもそも、「import」以外に、同じディレクトリのpyファイルを読み込む方法はあるのでしょうか? 読み込んで実行するのであれば、以下の様にするとよいかと思います。 import os exec(open(os.path.join(os.path.dirname(__file__), 'green.py')).read())
bsdfan

2024/03/11 22:39

上のmelian氏のコメントは、バッドノウハウなので、通常は使うべきではない方法です。
nihonnnoheso

2024/03/12 03:17

ラズベリーパイピコに処理を放り投げる方法、 出来なくもないけど、本来は使うべきではないものということですね ありがとうございました
melian

2024/03/12 04:01 編集

exec() の利用に不安がある場合は importlib の SourceFileLoader を使うとよいかと思います。 import os from importlib.machinery import SourceFileLoader green_py = os.path.join(os.path.dirname(__file__), 'green.py') SourceFileLoader('green', green_py).load_module()
nihonnnoheso

2024/03/16 12:48

ありがとうございます! 理屈はよくわかりませんが動きました!
guest

回答2

0

回答ではありません

回答としてはTakaiYさんのでいいと思います。

ただ質問者さんは、(マイコンだし)多分メモリを気にしてわざわざimportしているのかと思います。importが実際にはモジュールの読み込み処理であり、二度も読みませんよというのはその通りなのですが、無理矢理二度読み込んだらどうなるか?を実験してみました(PC上のUbuntu 22.04 python 3.10.12です)。

hoge.py

python

1print('hoge')

fuga.py

python

1import tracemalloc 2print('start trace') 3tracemalloc.start() 4 5print('import sys') 6import sys 7print('import gc') 8import gc 9print(tracemalloc.get_traced_memory()) 10 11print('import hoge') 12import hoge 13print('gc.collect()') 14gc.collect() 15print(tracemalloc.get_traced_memory()) 16 17print('import hoge') 18import hoge 19print('gc.collect()') 20gc.collect() 21print(tracemalloc.get_traced_memory()) 22 23print("sys.modules.pop('hoge')") 24sys.modules.pop('hoge') 25print('import hoge') 26import hoge 27print('gc.collect()') 28gc.collect() 29print(tracemalloc.get_traced_memory()) 30 31tracemalloc.stop()

実行結果

console

1$ python3 fuga.py 2start trace 3import sys 4import gc 5(5949, 6829) 6import hoge 7hoge 8gc.collect() 9(6926, 12662) 10import hoge 11gc.collect() 12(6926, 12662) 13sys.modules.pop('hoge') 14import hoge 15hoge 16gc.collect() 17(7158, 14620) 18$

出力を見ると分かりますが、import hogeが3回実行されていますが、その次の行にhogeと出力されているところはhoge.pyが読み込まれ、実行されています。1回目と3回目ですね。この際にメモリを見てみると、6926から7158に増えていることが分かります。

つまり、たとえ何度も読み込めたとしても、(少なくともこの環境&この方法では)メモリ使用量は増えてしまうということです。

なのでimportで策を弄するよりも、余計なことをしないようにコードを記述する方がRAMには優しい気がします。足りなければそもそもMicroPythonを使うべきではない、くらいの気持ちで作った方がいいかもしれません。とはいえ、この手のMicroPython固有の知見は全くないので、絶対そうなのかは分かりません

投稿2024/03/11 19:07

dameo

総合スコア943

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

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

nihonnnoheso

2024/03/11 22:36

回答ありがとうございます なるほど、倍々的にメモリが増えていきエラーが発生するわけですね… ラズベリーパイピコはとてもメモリが低いので、メモリがすぐ一杯になるのは当然かもしれません
guest

0

pythonでimportする.pyファイルは、import時に処理を実行するのではなく「特定の機能を持った関数を読込む」のが基本の使いかたです。また、importは「実行」ではなく「読込む」仕組みなので、同じファイルを複数回importしても、読み込み済みなので、2回目以降は実行されません。
なので、質問の使いかたのように「importしたときに動作する」のを目的とするのは正しい使いかたではないことになります。

importをつかった場合の簡単な例を書くと、
say.py

python

1def hello(): 2 print(hello) 3 4def bye(): 5 print(bye)

main.py

python

1import say 2 3print('こんにちは') 4say.hello() 5print('さようなら') 6say.bye()

このような感じになります。
この例では、say.pyで関数を2つ定義しています。 main.pyではそのsay.pyをimportしますが、importしたタイミングでは、関数が定義されるだけで何も実行されません。
その後、望みのタイミングで、say.pyで定義されている関数を呼び出して処理を実行しています。

質問者さんのコードもこのような構造にする必要があります。

  1. mainの中の別のファイルに移したい処理を、mainの中で関数化します。
    たとえば、 green() という関数を作ります。 このとき、対象のledは引数で渡すようにするといいでしょう。
  2. mainの処理をその関数を使った処理に書き換えます。
  3. 作った関数を別ファイルに移し、mainにimport文を入れ、関数の呼び出しを適切に書き換えます。

※ それぞれのステップで、mainプログラムがちゃんと動作することを確認してから次に進めます。 特に、Step2の後での確認は必須です。

こんな感じでやってみてはどうでしょう。

投稿2024/03/11 15:25

編集2024/03/12 01:43
TakaiY

総合スコア12769

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

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

nihonnnoheso

2024/03/11 22:34

回答ありがとうございました importは実行ではなく読み込みだったのですね 「他のファイルを実行」と検索をかけてもimportが出てきたので勘違いしていました
TakaiY

2024/03/12 01:38

実行されるように書けばimport時に実行されるので、仕組みを理解した上で使うのであれば問題ないのですが、一般的とは言えません。
nihonnnoheso

2024/03/16 12:50

ありがとうございます 自分は仕組みをまるで理解していないため、 おとなしく関数で制御する方法で開発を進めることにします
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問