homepage

This issue tracker has been migrated to GitHub , and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: Patch to make pickle aware of __qualname__
Type: enhancement Stage: resolved
Components: Extension Modules Versions: Python 3.4
process
Status: closed Resolution: duplicate
Dependencies: Superseder: Implement PEP 3154 (pickle protocol 4)
View: 17810
Assigned To: alexandre.vassalotti Nosy List: alexandre.vassalotti, lukasz.langa, pitrou, sbt, vstinner
Priority: normal Keywords: patch

Created on 2011年12月02日 16:29 by sbt, last changed 2022年04月11日 14:57 by admin. This issue is now closed.

Files
File name Uploaded Description Edit
pickle_qualname.patch sbt, 2011年12月02日 16:29
Messages (5)
msg148759 - (view) Author: Richard Oudkerk (sbt) * (Python committer) Date: 2011年12月02日 16:29
The attached patch makes pickle use an object's __qualname__ attribute if __name__ does not work.
This makes nested classes, unbound instance methods and static methods picklable (assuming that __module__ and __qualname__ give the correct "address").
BTW, It would not be hard to make instance methods picklable (and, as a by-product, class methods) by giving instance methods a __reduce__ method equivalent to
 def __reduce__(self):
 return (getattr, (self.__self__, self.__name__))
Is there any reason not to make such a change?
msg148770 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2011年12月02日 19:10
> The attached patch makes pickle use an object's __qualname__ attribute
> if __name__ does not work.
> 
> This makes nested classes, unbound instance methods and static methods
> picklable (assuming that __module__ and __qualname__ give the correct
> "address").
Thanks. I'm not sure that's a good approach for protocol 3: some pickles
created by Python 3.3 would not be readable by Python 3.2. That's why I
initially added that idea to PEP 3154, for a hypothetical protocol 4.
However, perhaps it is possible to use the same reduce/getattr trick you
are proposing for instance methods?
> BTW, It would not be hard to make instance methods picklable (and, as
> a by-product, class methods) by giving instance methods a __reduce__
> method equivalent to
> 
> def __reduce__(self):
> return (getattr, (self.__self__, self.__name__))
> 
> Is there any reason not to make such a change?
I don't see any personally. Actually, multiprocessing has a Pickler
subclass called ForkingPickler which does something similar (in
Lib/multiprocessing/forking.py).
msg148903 - (view) Author: Alexandre Vassalotti (alexandre.vassalotti) * (Python committer) Date: 2011年12月06日 02:36
This might not be the case anymore, but __module__ can sometime be None. There is some discussion about this in Issue 3657. We should define the expected behavior when this happens.
Also, I don't think backward-compatibility of the protocol is a big issue if we use the getattr approach. I feel bumping the protocol version is only necessary if we introduce new opcodes or change their interpretation.
msg148920 - (view) Author: Richard Oudkerk (sbt) * (Python committer) Date: 2011年12月06日 14:52
It looks like Issue 3657 is really about builtin methods (i.e. builtin_function_or_method objects where __self__ is not a module). It causes no problem for normal python instance methods.
If we tried the getattr approach for builtin methods too then it should only be used as a fallback when saving as a global will not work.
msg168820 - (view) Author: Richard Oudkerk (sbt) * (Python committer) Date: 2012年08月21日 23:16
There is a cute way to use operator.attrgetter to produce backwards compatible pickles using the qualname:
import pickle, copyreg, operator, sys, pickletools, types
class AttrGetter(object):
 def __init__(self, name):
 self.name = name
 def __call__(self): # pretend to be callable
 raise RuntimeError
 def __reduce__(self):
 return operator.attrgetter, (self.name,)
def reduce_by_qualname(obj):
 mod = sys.modules[obj.__module__]
 first, rest = obj.__qualname__.split('.', 1)
 firstobj = getattr(mod, first)
 assert operator.attrgetter(rest)(firstobj) is obj
 return AttrGetter(rest), (firstobj,)
# FunctionType defaults to save_global but uses fallback if it fails
copyreg.pickle(types.FunctionType, reduce_by_qualname)
class A(object):
 class B(object):
 class C(object):
 @staticmethod
 def foo():
 print("foo foo foo")
def bar():
 print("bar bar bar")
for obj in [A.B.C.foo, bar]:
 data = pickle.dumps(obj, 2)
 pickletools.dis(data)
 func = pickle.loads(data)
 assert func is obj
 func()
This produces
 0: \x80 PROTO 2
 2: c GLOBAL 'operator attrgetter'
 23: q BINPUT 0
 25: X BINUNICODE 'B.C.foo'
 37: q BINPUT 1
 39: \x85 TUPLE1
 40: q BINPUT 2
 42: R REDUCE
 43: q BINPUT 3
 45: c GLOBAL '__main__ A'
 57: q BINPUT 4
 59: \x85 TUPLE1
 60: q BINPUT 5
 62: R REDUCE
 63: q BINPUT 6
 65: . STOP
highest protocol among opcodes = 2
foo foo foo
 0: \x80 PROTO 2
 2: c GLOBAL '__main__ bar'
 16: q BINPUT 0
 18: . STOP
highest protocol among opcodes = 2
bar bar bar
History
Date User Action Args
2022年04月11日 14:57:24adminsetgithub: 57729
2013年11月30日 04:52:45alexandre.vassalottisetstatus: open -> closed
versions: + Python 3.4, - Python 3.3
resolution: duplicate
assignee: alexandre.vassalotti
superseder: Implement PEP 3154 (pickle protocol 4)
stage: patch review -> resolved
2012年08月21日 23:16:03sbtsetmessages: + msg168820
2012年06月24日 07:31:31hyneksetnosy: - hynek
2012年02月26日 18:43:44lukasz.langasetnosy: + lukasz.langa
2012年01月22日 19:48:15hyneksetnosy: + hynek
2011年12月06日 14:52:15sbtsetmessages: + msg148920
2011年12月06日 02:36:52alexandre.vassalottisetmessages: + msg148903
2011年12月02日 19:13:05pitrousetnosy: + alexandre.vassalotti
2011年12月02日 19:10:40pitrousetmessages: + msg148770
2011年12月02日 16:36:13vstinnersetnosy: + vstinner
2011年12月02日 16:33:31ezio.melottisettype: enhancement
components: + Extension Modules
stage: patch review
2011年12月02日 16:29:12sbtcreate

AltStyle によって変換されたページ (->オリジナル) /