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

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

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

DjangoはPythonで書かれた、オープンソースウェブアプリケーションのフレームワークです。複雑なデータベースを扱うウェブサイトを開発する際に必要な労力を減らす為にデザインされました。

Python 3.x

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

Q&A

5回答

2503閲覧

Pythonでreturnの後に処理を実行したい

sasaki0628

総合スコア106

Django

DjangoはPythonで書かれた、オープンソースウェブアプリケーションのフレームワークです。複雑なデータベースを扱うウェブサイトを開発する際に必要な労力を減らす為にデザインされました。

Python 3.x

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

0グッド

0クリップ

投稿2022/12/01 06:58

編集2023/01/13 03:23
from rest_framework.views import APIView from rest_framework.response import Response import gc class test(APIView): def post(self,request,*args,**kwargs): __test = self.request.data['test'] return Response(__test) del __test gc.collect()

DjangoでAPIを作成しています。returnの後に使用しない変数のオブジェクトを削除してガベージコレクションをしたいのですが、どのような方法があるでしょうか。

▽追記
みなさま回答ありがとうございました。WEBサイトの作成でメモリが足りなくなり、pythonのガベージコレクションを行うことで解決しようとしていました。そのあと調査を続けたところ、ApacheとMySQLのチューニングを行うことにより、メモリ不足を解決することができました。質問の件について、私の実力ではベストアンサーを選ぶことができないため、1ヵ月ほど様子を見て、グッドの数が多い方をベストアンサーにして質問を閉めさせていただきます。ありがとうございました。

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

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

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

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

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

guest

回答5

0

returnの後にその関数内でなにかすることはできません。

使用しない変数のオブジェクトを削除

もし、そのオブジェクトが関数外で使われないのであれば、pythonが自動で消してくれるので不要です。
また、質問の「__test」が束縛されているオブジェクトは、returnで返しているので、もし消してしまうと受け取った側で使えなくなります。

ガベージコレクションをしたい

もし、どうしてもやりたいなら、returnの前にやることになるでしょう。
消したオブジェクトをちゃんと消すのが目的なら、前に書いたとおりです。

また、書いたとおりインタプリタが適切に実施してくれるので、プログラムから意識的にGCを呼ぶ必要は無いと思います。

投稿2022/12/01 07:10

TakaiY

総合スコア12745

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

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

0

decoratorを使うのが一番簡単だと思いました(処理を追いにくく悪評も多い気がしますが)。

コード

python

1import os 2import gc 3import psutil 4 5def print_memories(): 6 print(psutil.Process(os.getpid()).memory_info()) 7 8def gc_when_returned(func): 9 def wrapper(*args, **kwargs): 10 func(*args, **kwargs) 11 gc.collect() 12 print("gc collected.") 13 return wrapper 14 15def hoge(): 16 print("hoge()") 17 o = [x for x in range(1024 * 1024)] 18 print_memories() 19 20@gc_when_returned 21def hoge_with_gc(): 22 print("hoge_with_gc()") 23 o = [x for x in range(1024 * 1024)] 24 print_memories() 25 26print_memories() 27hoge() 28print_memories() 29hoge_with_gc() 30print_memories()

※psutilはpipで入れる必要があります

結果

うちの環境(ubuntu 20.04 python3.8.10)だと実行結果は以下のようになります。

text

1pmem(rss=12230656, vms=22401024, shared=6459392, text=2863104, lib=0, data=5971968, dirty=0) 2hoge() 3pmem(rss=54915072, vms=65384448, shared=6602752, text=2863104, lib=0, data=48955392, dirty=0) 4pmem(rss=12750848, vms=22605824, shared=6602752, text=2863104, lib=0, data=6176768, dirty=0) 5hoge_with_gc() 6pmem(rss=54648832, vms=68108288, shared=6602752, text=2863104, lib=0, data=51679232, dirty=0) 7gc collected. 8pmem(rss=20930560, vms=34029568, shared=6602752, text=2863104, lib=0, data=17600512, dirty=0)

今回の例を今回の環境で見ると、普通に戻っただけでも開放されているので、あまり期待した効果はないようです。他の環境(処理系/バージョン/プラットフォーム)でどうなるかは未知数なので、能動的なgc自体に意味がないかどうかは分かりません。

注意

gcは基本的に自動で行われますが、任意のタイミングで実施できます。個人的に考えている、能動的なgcの主な使用用途としては、大きなメモリを使った後長く忙しい処理が入るとき、その直前に確実にメモリを空けておきたいとか、メモリの少ない環境でこまめに手動でgcしておきたいとか(パラメータでも調整できるかも)、でしょうか。いずれにしても比較的負荷の高い作業なことに注意です。

投稿2022/12/06 05:12

dameo

総合スコア943

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

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

0

「returnの後に使用しない変数のオブジェクト」をローカルな名前空間から削除したとしても、それはDjangoがクライアントにレスポンスとして返し終わるまでは必要なオブジェクトであり続けます。
関数の終了後にガベージコレクションをしたとしても、レスポンスに必要なオブジェクトである限りガベージコレクションで回収の対象になるはずがありません


また、これはX-Y問題であるように感じます。

質問のような考えを仮定するとしても、カベージコレクションに回収されなかった時に何か困ることが起きているのでしょうか?
その何か困ることの方を質問するべきです
何も困っていないのなら何もする必要はないし、何か困っているならその困っていることを解決する手段が知りたいはずだからです。(そして回答者は何もする必要はないことに回答はしたくないし、困っていることが解決する手段を回答したいのです)


Responseを返却し終わった後に処理をさせる方法を探してみましたが、request_finishedシグナルに応じて毎回ガベージコレクションを走らせるくらいしかなさそうでした。これですとすべてのリクエストの後にガベージコレクションが走ってまうので現実的ではなさそうという感想です。

あとはResponseを継承して終了後に何かを実行するという案もあります。
破棄したいものが特別扱いされるように__init__を共に実装すれば何かが解決するかもしれません。

どちらも何に困っているかが質問にない以上、直接の回答はできずアイディア止まりです。あしからず。

投稿2022/12/02 05:35

編集2022/12/02 05:41
quickquip

総合スコア11038

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

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

0

contextlib.ExitStack を利用して、Golang の defer と同様な事ができます。
※ 今回の場合、test.defer() メソッド内での処理は不要なものかと思います。

python

1from contextlib import ExitStack 2import gc 3 4class Response(): 5 def __init__(self, arg): 6 self.arg = arg 7 8class test(): 9 def defer(self, local_vars, name): 10 del local_vars[f'_{__class__.__name__}{name}'] 11 gc.collect() 12 print('defer done') 13 14 def post(self,*args,**kwargs): 15 with ExitStack() as stack: 16 __test = [1, 'Response value'] 17 stack.callback(self.defer, locals(), '__test') 18 19 print('return from post') 20 return Response(__test) 21 22if __name__ == '__main__': 23 t = test() 24 ret = t.post() 25 print(ret.arg) 26 27# return from post 28# defer done 29# [1, 'Response value']

投稿2022/12/01 08:49

編集2022/12/01 09:27
melian

総合スコア19712

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

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

0

python

1from rest_framework.views import APIView 2from rest_framework.response import Response 3import gc 4 5class test(APIView): 6 def post(self,request,*args,**kwargs): 7 8 __test = self.request.data['test'] 9 10 ret = Response(__test) 11 12 del __test 13 gc.collect() 14 return ret

ただし、ガベージコレクトは必要なときに走ってくれるので自分で走らせる意味は無いと思います。

投稿2022/12/01 07:12

編集2022/12/01 07:16
ozwk

総合スコア13521

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

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

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

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問