Skip to content

Instantly share code, notes, and snippets.

@cosmologicon
Created September 27, 2020 17:13
Show Gist options
  • Save cosmologicon/bae7a8d20d2d3311796e1a850356e329 to your computer and use it in GitHub Desktop.
Save cosmologicon/bae7a8d20d2d3311796e1a850356e329 to your computer and use it in GitHub Desktop.
PyWeek 30 pickle edge case: minimal example
# Minimal example of pickling error encountered in my PyWeek 30 entry.
# Unpickling a function fails when it can't be referred to by the name in its __name__ attribute,
# such as when the function is locally defined within a callback.
# This is unlikely to come up in general unless you explicitly set the __name__ attribute, because
# you can't pickle local objects. However, it occurs when you pickle the method of an instance and
# the method of that instance's class is a local object.
import pickle
def g():
def h(self):
return 123
return h
# Uncommenting this line fails with AttributeError: Can't pickle local object 'g.<locals>.h'
# pickle.dumps(g())
# Define a class with a method whose __name__ attribute does not match the name of the method as it
# appears in the class.
# i.e. hasattr(A, A.f.__name__) is False
class A:
f = g()
# Uncommenting this line fixes the error.
#f.__name__ = "f"
print("method __name__ attribute:", A.f.__name__)
print("hasattr:", hasattr(A, A.f.__name__))
# prints 123
a = A()
print(a.f())
# The class can be pickled and unpickled fine. Prints 123.
B = pickle.loads(pickle.dumps(A))
print(B().f())
# The class method cannot be pickled.
# Uncommenting this line fails with AttributeError: Can't pickle local object 'g.<locals>.h'
# pickle.dumps(A.f)
# The instance can be pickled and unpickled fine too. Prints 123
a = pickle.loads(pickle.dumps(a))
print(a.f())
# The instance method can be pickled.
s = pickle.dumps(a.f)
# But unpickling the instance method fails with AttributeError
f = pickle.loads(s)
print(f())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment