34900


Djangoでアプリを作っている時のエラーです。  
まず、Djagoとは別のレポジトリであるクラスを作成し、そのインスタンスをpickle形式で保存しました。  
そして、Djangoのapp/views.pyでそのクラスをインポートし、さらにpickleデータをloadしようとしました。すると、以下のエラーが出てしまいます。

[code]

    % python manage.py runserver                                                               
    Performing system checks...
    
    Unhandled exception in thread started by <function check_errors.        
    <locals>.wrapper at 0x1058489d8>
    Traceback (most recent call last):
      File "/Users/you_mac/.pyenv/versions/django_env/lib/python3.5/site-
    packages/django/utils/autoreload.py", line 226, in wrapper
        fn(*args, **kwargs)
    
    ・・・
    
      File "/Users/you_mac/workspace/python/django-app/django-
    app/classifier/urls.py", line 2, in <module>
        from . import views
      File "/Users/you_mac/workspace/python/django-app/django-
    app/classifier/views.py", line 13, in <module>
        obj = pickle.load(f)
    AttributeError: Can't get attribute 'NaiveBayes' on <module '__main__' from 'manage.py'>
    
[/code]

ディレクトリの構造はこのようになっています(抽象化しています)。

[code]

    - django/
        - django-app/
            - mysite/
            - manage.py
            - app/
                - templates/
                - urls.py
                - views.py
        - src/
            - src1.py
            - model.pkl
    
[/code]

django/src/src1.pyのコードです（わかりやすいようにかなり省略してます）。

[code]

    import pickle
    
    class NaiveBayes:
        def __init__(self, data):
            self.data = data
            self.dic = {}
        def train(self):
            for d in self.data:
                self.dic[d] += 1
        def classify(self, text):
            """辞書を使ってスコアを計算し、クラス分類"""
    
    if __name__ == '__main__':
        data = ["a", "b", ...]
        cls = NaiveBayes(data)
    
        with open('model.pkl', 'wb') as f:
            pickle.dump(cls, f)
    
[/code]

django/django-app/app/views.pyです（かなり省略）。

[code]

    import pickle, sys, os
    
    sys.path.append(os.path.abspath(".") + '/../src')
    from src1 import NaiveBayes
    
    path = os.path.abspath("../src")
    with open(path+'/model.pkl', 'rb') as f:
        obj = pickle.load(f)
    obj.train()
    
    def form(request):
        category = obj.classify(request.POST['text'])
    
        ・・・
    
[/code]

ざっくりした説明ですが、解決方法がありましたらご教授ください。


CC BY-SA 3.0
2017-05-20T08:07:56.077
34866
2017-05-21T13:15:10.317
22480
question
python django
Djangoでpickleを読み込む時のエラー


まずこれで動くであろう修正点を記載します。

django/src/src1.py の NaiveBayes を 別モジュール(例えばbayes.pyとか作って) に移動してimportする

[code]

    import pickle
    
    from bayes import NaiveBayes # <- 移動した モジュールからimport
    
    
    if __name__ == '__main__':
        data = ["a", "b", ...]
        cls = NaiveBayes(data)
    
        with open('model.pkl', 'wb') as f:
            pickle.dump(cls, f)
    
[/code]

django/django-app/app/views.py では NavieBayes importしなくて良い

[code]

    import pickle, sys, os
    
    sys.path.append(os.path.abspath(".") + '/../src')
    
    # delete this line.
    # from src1 import NaiveBayes # <- importしなくても良い、上でパスを通すだけで良い。
    
    path = os.path.abspath("../src")
    with open(path+'/model.pkl', 'rb') as f:
        obj = pickle.load(f)
    obj.train()
    
    def form(request):
        category = obj.classify(request.POST['text'])
    
[/code]

ここまでの修正で、上記エラーは解消されるはずです。次になぜこうなるのか説明します。

[code]

    AttributeError: Can't get attribute 'NaiveBayes' on <module '__main__' from 'manage.py'>
    
[/code]

`__main__` モジュール に `NaiveBayes` がないというエラーになっています。

これは `python src1.py` と実行した時にに `__main__.NaiveBayes`
というクラスをPickle化して保存してしまったからです。

[https://docs.python.jp/3/library/
**main**.html](https://docs.python.jp/3/library/__main__.html)

ドキュメントにもある通り、 python コマンドで渡した scriptファイルはどんなファイル名であっても `__main__`
モジュールとして扱われます。それは `python manage.py` でも一緒です。

なので

[code]

    1. python src1.py で `__main__.NavieBayes` を Pickle化保存
    2. python mange.py runserver で 1のpikcle から `__main__.NavieBayes` 
       を loadしようとしたけど、実際に存在してるのは `src1.NaiveBayes`なのでエラーとなる。
    
[/code]

そこで敢えて別モジュール `bayes` を作りその中に NaiveBayes を 移動することで、両方とも `bayes.NaiveBayes`
を参照するようにすれば今回のエラーが回避できます。

[code]

    1. python src1.py で `bayes.NavieBayes` を Pickle化保存
    2. python mange.py runserver で 1のpikcle から `bayes.NavieBayes` を loadする
    
[/code]


CC BY-SA 3.0
2017-05-21T13:15:10.317
34900
2017-05-21T13:15:10.317
2168
34866
answer