在Python中,类名的自动完全限定如何工作? [与物品酸洗相关] [英] How does the automatic full qualification of class names work, in Python? [relevant to object pickling]

查看:117
本文介绍了在Python中,类名的自动完全限定如何工作? [与物品酸洗相关]的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

(可以直接跳到问题,进一步向下,跳过介绍。)



有一个常见的困难,从用户定义的类:

 #这是程序dumper.py 
import pickle

C(object):
pass

with open('obj.pickle','wb')as f:
pickle.dump(C(),f)

事实上,试图从另一个程序中取回对象 loader.py

 #这是程序loader.py 
with open('obj.pickle' 'rb')as f:
obj = pickle.load(f)

  AttributeError:'module'object没有属性'C'

事实上,这个类是通过名字(C)来处理的,而 loader.py 不知道任何关于 C 。一个常见的解决方案是从转储导入C#导入

 可以导入类C的对象

with open('obj.pickle','rb')as f:
obj = pickle.load(f)

然而,这个解决方案有一些缺点,包括所有被pickled对象引用的类都必须被导入(可能有很多)。此外,本地命名空间受到来自 dumper.py 程序的名称的污染。



现在,包括完全限定对象在pickling之前:

 #新的dumper.py程序:
import pickle
import dumper#这是这个程序!

class C(object):
pass

with open('obj.pickle','wb')as f:
pickle.dump (dumper.C(),f)#完全限定类

c> loader.py 程序现在可以直接工作(不需要从转储导入C 中执行)。



问题:现在,来自 dumper.py 的其他类似乎在pickling后自动完全合格,我希望知道这是如何工作,以及这是一个可靠的,记录的行为:

  import pickle 
import dumper#这是这个非常方案!

class D(object):#New class!
pass

class C(object):
def __init __(self):
self.d = D()#* NOT * fully qualified

with open('obj.pickle','wb')as f:
pickle.dump(dumper.C(),f)#完全合格的pickle类

现在,使用原始 loader.py 程序取消绑定也可以 from dumper import C ); print obj.d 提供了一个完全限定的类,我觉得很奇怪:

 < dumper.D object at 0x122e130> 

这种行为非常方便,因为只有顶部的pickled对象必须完全限定name( dumper.C())。但这种行为是否可靠和记录?如何通过名称(D)来处理类,但是unpickling决定了 self.d 属性是类 dumper.D (而不是某些本地 D 类)?



问题,细化:我只是注意到一些有趣的细节,可能指向这个问题的答案:



在酸洗程序 dumper.py print self.d 列印< __ main __。D object at 0x2af450> ,使用第一个 dumper.py 程序(不包含 import dumper 的程序)。另一方面,在中使用 import dumper 并创建 dumper.C() > dumper.py 打印 打印 打印< dumper.D对象在0x2af450> self.d 属性由Python自动限定!所以,看起来 pickle 模块在上面描述的nice unpickling行为中没有任何作用。



问题是因此,为什么Python在第二种情况下将 D()转换为完全限定的 dumper.D

解决方案

这是发生什么:当导入 dumper dumper.py 中,(> <$ c $> (可以通过在模块中插入打印来查看)。这个行为是期望的,因为 dumper 不是已经加载的模块( __ main __ 被认为加载)它不是在 sys.modules



如Mark的回答所示,导入模块自然限定所有名称在模块中定义,使得 self.d = D()被解释为 dumper.D 重新评估文件 dumper.py (这相当于在Mark的回答中解析 common.py )。 p>

因此, import dumper (或 from dumper import C )trick解释,pickling完全限定不仅类 C 而且类 D



这也表明 import dumper dumper.py 强制Python解释器解析程序两次,这既不高效也不优雅。因此,在程序中选择类,并在另一个中取出它们可能最好通过Mark的答案中概述的方法来完成:pickled类应该在一个单独的模块中。


(It is possible to directly jump to the question, further down, and to skip the introduction.)

There is a common difficulty with pickling Python objects from user-defined classes:

# This is program dumper.py
import pickle

class C(object):
    pass

with open('obj.pickle', 'wb') as f:
    pickle.dump(C(), f)

In fact, trying to get the object back from another program loader.py with

# This is program loader.py
with open('obj.pickle', 'rb') as f:
    obj = pickle.load(f)

results in

AttributeError: 'module' object has no attribute 'C'

In fact, the class is pickled by name ("C"), and the loader.py program does not know anything about C. A common solution consists in importing with

from dumper import C  # Objects of class C can be imported

with open('obj.pickle', 'rb') as f:
    obj = pickle.load(f)

However, this solution has a few drawbacks, including the fact that all the classes referenced by the pickled objects have to be imported (there can be many); furthermore, the local namespace becomes polluted by names from the dumper.py program.

Now, a solution to this consists of fully qualifying objects prior to pickling:

# New dumper.py program:
import pickle
import dumper  # This is this very program!

class C(object):
    pass

with open('obj.pickle', 'wb') as f:
    pickle.dump(dumper.C(), f)  # Fully qualified class

Unpickling with the original loader.py program above now works directly (no need to do from dumper import C).

Question: Now, other classes from dumper.py seem to be automatically fully qualified upon pickling, and I would love to know how this works, and whether this is a reliable, documented behavior:

import pickle
import dumper  # This is this very program!

class D(object):  # New class!
    pass

class C(object):
    def __init__(self):
        self.d = D()  # *NOT* fully qualified

with open('obj.pickle', 'wb') as f:
    pickle.dump(dumper.C(), f)  # Fully qualified pickle class

Now, unpickling with the original loader.py program also works (no need to do from dumper import C); print obj.d gives a fully qualified class, which I find surprising:

<dumper.D object at 0x122e130>

This behavior is very convenient, since only the top, pickled object has to be fully qualified with the module name (dumper.C()). But is this behavior reliable and documented? how come that classes are pickled by name ("D") but that the unpickling decides that the pickled self.d attribute is of class dumper.D (and not some local D class)?

PS: The question, refined: I just noticed a few interesting details that might point to an answer to this question:

In the pickling program dumper.py, print self.d prints <__main__.D object at 0x2af450>, with the first dumper.py program (the one without import dumper). On the other hand, doing import dumper and creating the object with dumper.C() in dumper.py makes print self.d print <dumper.D object at 0x2af450>: the self.d attribute is automatically qualified by Python! So, it appears that the pickle module has no role in the nice unpickling behavior described above.

The question is thus really: why does Python convert D() into the fully qualified dumper.D, in the second case? is this documented somewhere?

解决方案

Here is what happens: when importing dumper (or doing from dumper import C) from within dumper.py, the whole program is parsed again (this can be seen by inserting a print in the module). This behavior is expected, because dumper is not a module that was already loaded (__main__ is considered loaded, however)–it is not in sys.modules.

As illustrated in Mark's answer, importing a module naturally qualifies all the names defined in the module, so that self.d = D() is interpreted as being of class dumper.D when re-evaluating file dumper.py (this is equivalent to parsing common.py, in Mark's answer).

Thus, the import dumper (or from dumper import C) trick is explained, and pickling fully qualifies not only class C but also class D. This makes unpickling by an external program easier!

This also shows that import dumper done in dumper.py forces the Python interpreter to parse the program twice, which is neither efficient nor elegant. Pickling classes in a program and unpickling them in another one is therefore probably best done through the approach outlined in Mark's answer: pickled classes should be in a separate module.

这篇关于在Python中,类名的自动完全限定如何工作? [与物品酸洗相关]的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆