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

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

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

Discordは、ゲーマー向けのボイスチャットアプリです。チャット・通話がブラウザ上で利用可能で、個人専用サーバーも開設できます。通話中でも音楽を流したり、PC画面を共有できるなど多機能な点が特徴です。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Windows

Windowsは、マイクロソフト社が開発したオペレーティングシステムです。当初は、MS-DOSに変わるOSとして開発されました。 GUIを採用し、主にインテル系のCPUを搭載したコンピューターで動作します。Windows系OSのシェアは、90%を超えるといわれています。 パソコン用以外に、POSシステムやスマートフォンなどの携帯端末用、サーバ用のOSもあります。

Q&A

解決済

2回答

2011閲覧

discord.pyでの指定時刻処理について

siroRabi

総合スコア5

Discord

Discordは、ゲーマー向けのボイスチャットアプリです。チャット・通話がブラウザ上で利用可能で、個人専用サーバーも開設できます。通話中でも音楽を流したり、PC画面を共有できるなど多機能な点が特徴です。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Windows

Windowsは、マイクロソフト社が開発したオペレーティングシステムです。当初は、MS-DOSに変わるOSとして開発されました。 GUIを採用し、主にインテル系のCPUを搭載したコンピューターで動作します。Windows系OSのシェアは、90%を超えるといわれています。 パソコン用以外に、POSシステムやスマートフォンなどの携帯端末用、サーバ用のOSもあります。

0グッド

0クリップ

投稿2020/05/29 13:36

前提・実現したいこと

私はいま、指定時刻(23時)に、辞書のすべての値を-1しようと思っています
しかし、whileなどで、書くとそのあとにある、コードが実行されなくて困っています(ずっとループしてしまうため)。これを両立させることはできないのでしょうか?調べても、期待していたものとは違うものばかりだったので、教えてください。(つい最近pythonを始めました。)

該当のソースコード

python

1dt_now = datetime.datetime.now() 2if dt_now.hour == 23: 3 point_check()

こんな感じに書いてみたのですがうまく行きません
point_checkは自作関数です。

試したこと

whileでループさせてみた。ifで現在時刻と比較させてみた。

補足情報(FW/ツールのバージョンなど)

python3.8.2 windows

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

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

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

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

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

guest

回答2

0

discord.py のwindowsでのエラー(SSL証明の更新)にはまって
なかなか動作確認が出来なかったけど、サンプルコードです。

あまりデバッグはしてないので、このまま実用できるコードかどうかは怪しいです。
必要な情報のみ参考にして下さい。(指定時間の計算等は実際には確認出来てません)
動作確認したPythonのバージョンは3.8.3 / win10 64bit

  • (1) discord.py: tasks.loop で一定時間毎に実行
  • (2) asyncio: 任意のループを組み込む方法 (asyncio での作法で書く必要があります)
  • (3) asyncio: call_later, call_at で指定日時に関数を実行
  • (4) 1 と 3 を組み合わせたお勧めの方法

1.2 は、自分のループを両立させる方法のデモで、毎分チャンネルに何か発言します5回
3.4 は、本題の指定時間に毎日実行です。4番がお勧めの方法。

何れの方法を取るとしても、ループで毎分時間をチェックするよりも、
指定時間に関数を実行のcall_laterを起点にするとよいです。


python

1import asyncio 2import datetime 3import discord 4from discord.ext import tasks 5 6 7# ※ 必須設定 8BOT_TOKEN = "XXXXXXXX" 9CHANNEL_ID = 99999999 10 11 12 13def get_next_time(now, hour=23): 14 # 既に23時過ぎの場合、翌日の23時迄の秒数を返す 15 next_time = datetime.datetime(now.year, now.month, now.day, hour, 0, 0) 16 delta = next_time.timestamp() - now.timestamp() # 23時から現在時刻を引く 17 return delta if delta > 0 else (delta + 1*24*60*60) # マイナスであれば一日加算 18 19 20def main(): 21 client = discord.Client() 22 23 @client.event 24 async def on_ready(): 25 loop = asyncio.get_running_loop() 26 channel = client.get_channel(CHANNEL_ID) 27 28 # テスト用フラグ 29 USE_TEST1 = True 30 USE_TEST2 = False 31 USE_TEST3 = False 32 USE_TEST4 = True 33 34 # (1) discordの提供する、一定時間に起動する関数 (60秒毎に5回) 35 # 前後の処理(before_loop,after_loop)が不要であれば、一番手軽な方法です。 36 # https://discordpy.readthedocs.io/ja/latest/ext/tasks/ 37 if USE_TEST1: 38 @tasks.loop(seconds=60.0, count=5) 39 async def task_loop_func(): 40 await channel.send("TEST1") 41 pass 42 43 @task_loop_func.before_loop 44 async def on_task_loop_before(): 45 print("START TEST1") 46 47 @task_loop_func.after_loop # <-- このタスクはキャンセルされたときも呼び出される 48 async def on_task_loop_after(): 49 print("DONE TEST1") 50 51 # タスクを起動 52 task_loop_func.start() 53 54 # (2) 非同期のループを起動する方法 (asyncio) 55 if USE_TEST2: 56 # asyncio でのループの記述の仕方 57 # time.sleepやループは、イベントループ(discord通信等)を止めてしまうので 58 # 必ず asynci.sleep を使います。 59 async def my_loop_func(channel, seconds=60.0, count=5): 60 print("START TEST2") 61 for _ in range(count): 62 await channel.send("TEST2") 63 await asyncio.sleep(seconds) 64 print("DONE TEST2") # <-- キャンセルされた場合中断されます 65 66 asyncio.ensure_future(my_loop_func(channel)) 67 68 # (3) call_at, call_later で指定時間に処理 69 # 注意点: 70 # call_at は loop.time() を基準とした秒数, 71 # call_later は loop.time() を抜いた秒数なので、 (例: call_later(5, func) 5秒後に実行) 72 # この場合、call_later の方が使いやすいのですが、サンプルの為 解り辛い call_at の使い方を解説。 73 if USE_TEST3: 74 async def test3_func(channel): 75 await channel.send("TEST3") 76 loop.call_later(1*24*60*60, lambda:asyncio.ensure_future(test3_func(channel))) 77 78 next_time = get_next_time(datetime.datetime.now()) 79 when = loop.time() + next_time 80 handle = loop.call_at(when, lambda:asyncio.ensure_future(test3_func(channel))) 81 82 83 # (4) 上記を組み合わせた方法 84 # 85 # 1. tasks.loop で24時間毎に実行するタスクを作る 86 # 2. call_later で指定時にタスクを開始 87 if USE_TEST4: 88 @tasks.loop(hours=24) 89 async def test4_func(): 90 await channel.send("TEST4") 91 92 next_time = get_next_time(datetime.datetime.now()) 93 loop.call_later(next_time, test4_func.start) 94 95 client.run(BOT_TOKEN) 96 97 98if __name__ == '__main__': 99 try: 100 main() 101 except KeyboardInterrupt: 102 pass 103

投稿2020/05/31 07:42

編集2020/05/31 08:57
teamikl

総合スコア8760

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

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

0

ベストアンサー

念の為確認しますが、discord.py のバージョンは何でしょう?

古いものでなければ、discord.py は asyncio というライブラリ上で動いているので、
このライブラリの作法で書く必要があります。(async/await等の理解が必須です)


両立させることはできないのでしょうか?

可能ですが、一度の実行で良いならcall_later, call_at で指定日時に関数を実行できます。

参考: discord.py 時間を比較し数日後にBANを解除する

投稿2020/05/29 15:02

teamikl

総合スコア8760

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

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

siroRabi

2020/05/29 15:31

version 1.4.0aでした失礼しました。 1度ではなく毎日23時に実行したい時はどうすれば良いでしょうか?
teamikl

2020/05/30 12:55 編集

一度実行した時に、24時間後に同じ関数を実行するようにします。 call_later(1*24*60*60, func, args) 追記: 一度で~というのは、「辞書のすべての値を-1」についてでした。 ループで書くと 23 時にずっと -1 し続けてまうので、合わせて他の対策が必要です。
teamikl

2020/05/31 08:54

他の方法思いついたのでメモ IFTTT 等で指定時間にメッセージを発言するように設定できれば、(出来るのか確認はしてません) bot 側では通常のメッセージを拾って指定時間に実行と出来ますね。 環境整備が少し大掛かりになりますが。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問