Soru Namedtuple örneği nasıl doğru şekilde seçilir?


Turşu kullanmayı öğreniyorum. Adlandırılmış bir nesne oluşturdum, bir listeye ekledim ve bu listeyi seçmeye çalıştım. Ancak, aşağıdaki hatayı alıyorum:

pickle.PicklingError: Can't pickle <class '__main__.P'>: it's not found as __main__.P

Kodu bir işlev içinde sarmadan çalıştırırsam, mükemmel çalışır. Bir işlevin içine sarıldığında bir nesneyi toplamak için gereken fazladan bir adım var mı?

İşte kodum:

from collections import namedtuple
import pickle

def pickle_test():
    P = namedtuple("P", "one two three four")
    my_list = []
    abe = P("abraham", "lincoln", "vampire", "hunter")
    my_list.append(abe)
    f = open('abe.pickle', 'w')
    pickle.dump(abe, f)
    f.close()

pickle_test()

39
2018-05-04 17:46


Menşei


Ne yazık ki, turşu adlandırılmış ile iyi çalışmıyor gibi görünüyor. - Antimony
@Antimon: pickle isim sınıfları sadece iyi sınıflar; Bir işlev yerel ad alanında tanımlanan sınıflar çok fazla değil. - Martijn Pieters♦
olası kopyası Python: X tipi seçilemiyor, özellik araması başarısız oldu - Air
@AirThomas Bu soru bir yıl önce soruldu / yanıtladı :) - Dirty Penguin
Hiçbiri alınmadı. Ben sadece komik olduğunu düşündüm. Soru bağlantısı gerçekten çok faydalı :) - Dirty Penguin


Cevaplar:


Adlandırılmış tuple oluştur dışında fonksiyonun

from collections import namedtuple
import pickle

P = namedtuple("P", "one two three four")

def pickle_test():
    my_list = []
    abe = P("abraham", "lincoln", "vampire", "hunter")
    my_list.append(abe)
    f = open('abe.pickle', 'w')
    pickle.dump(abe, f)
    f.close()

pickle_test()

şimdi pickle onu bulabilir; Şimdi küresel bir modüldür. Unpickling yaparken, tüm pickle modül yapmak zorunda __main__.P tekrar. Senin versiyonunda P bir yerel, pickle_test() işlev, ve bu iç içe geçmiş veya alınabilir değildir.

Bunu hatırlamak önemlidir namedtuple() bir sınıf fabrikasıdır; Parametreler verirsiniz ve sizden örnekler oluşturmak için bir sınıf nesnesi döndürür. pickle sadece depolar veri Örneklerde yer alan örneklerin yanı sıra örnekleri yeniden oluşturmak için orijinal sınıfa bir dize referansı.


56
2018-05-04 17:51



Mükemmel! Teşekkür ederim. - Dirty Penguin
Yani, eğer ben yaratıyorsam namedtuple Dinamik olarak çalışma zamanına kadar alanları bilmiyorum çünkü? Bu sorunu atlamak için hala bir yol var mı? Sınıf dışında başka bir yöntem oluşturmayı denedim ama işe yaramadı. - Chuim
@Chuim: Modül kürelerinize atayın (kullanın globals() bir haritalama almak için aynı isim, ve pickle Onu hala bulabilirsin. - Martijn Pieters♦


Soruyu ana yanıtın yorumu olarak ekledikten sonra, dinamik olarak yaratma problemini çözmenin bir yolunu buldum. namedtuple turşu-edebiliyoruz. Bu benim durumumda gereklidir çünkü çalışma zamanı sırasında alanları (bir DB sorgusundan sonra) keşfediyorum.

Tek yaptığım maymun yama  namedtuple etkin bir şekilde __main__ modülü:

def _CreateNamedOnMain(*args):
    import __main__
    namedtupleClass = collections.namedtuple(*args)
    setattr(__main__, namedtupleClass.__name__, namedtupleClass)
    namedtupleClass.__module__ = "__main__"
    return namedtupleClass

Dikkatle ki namedtuple adı (tarafından sağlanan args) başka bir üyenin üzerine yazabilir __main__ eğer dikkatli değilsen


7
2018-06-26 20:07



Basitçe ayarla globals()yerine: globals()[namedtupleClass.__name__] = namedtupleClass. Sonra var gerek yok ayarlamak __module__. - Martijn Pieters♦
Denediğimde globals()[namedtupleClass.__name__] = namedtupleClass gerçekten benim nesneyi seçmeme izin verdi, ama çıkarmaya çalıştığımda namedtupleClass gerekli. Benim tavsiyem sadece sözlük kullan Bunu yapmak için yeterince akıllı olana dek. - Teque5
Aferin @Chuim basit ve çalışır :) - Ron Kalian


Alternatif olarak, kullanabilirsiniz cloudpickle veya dill serileştirme için:

from collections import namedtuple

import cloudpickle
import dill



def dill_test(dynamic_names):
    P = namedtuple('P', dynamic_names)
    my_list = []
    abe = P("abraham", "lincoln", "vampire", "hunter")
    my_list.append(abe)
    with open('deleteme.cloudpickle', 'wb') as f:
        cloudpickle.dump(abe, f)
    with open('deleteme.dill', 'wb') as f:
        dill.dump(abe, f)


dill_test("one two three four")

2
2018-06-12 11:58





buldum bu cevap Başka bir iş parçacığında. Bu isimlendirilmiş tupenin isimlendirilmesi ile ilgilidir. Bu benim için çalıştı:

group_t =            namedtuple('group_t', 'field1, field2')  # this will work
mismatched_group_t = namedtuple('group_t', 'field1, field2')  # this will throw the error

2
2017-10-12 10:51



İlk satır benim için sorunu çözmüyor - Ron Kalian


Buradaki konu, çocuk süreçlerinin nesne sınıfını ithal edememesidir - bu durumda, P sınıfı, çok modelli bir projede Sınıf P'nin çocuk sürecinin her yerde ithal edilebilir olması gerekir.

hızlı bir çözüm, onu globals'a () etkileyerek onu ithal edilebilir kılmaktır.

globals()["P"] = P

0
2018-06-11 13:25