Saving function references to file

I’m currently working on saving and loading in my current project, and have hit a bit of a problem:

One of the mechanisms that I have in my game is a system that allows me to perform additional logic on an object via objects that each contain a function called on update, an initialisation function and a completion function, as well as argument lists for each, as desired. These functions are stored as function references, and are expected to have a given parameter list.

My problem, then, is how to save these functions. I can get and store the function name easily enough, and if any were instance methods I could get the name of the object to which they belonged and store that, I believe. If the method is a free function, not attached to any class, then storing its name alone should be enough, as long as the module to which it belongs is imported into the module in which I am implementing this.

However, I’m not sure of what to do about static methods belonging to classes. They appear to be functions, and so don’t provide access to their parent classes, but without that information I don’t see a means of calling them once I’ve acquired their name from the save file.

I’d prefer to not make them instance- or class- methods, as I’d prefer to not clutter my parameter list with data that isn’t used by the method.

I could move all such methods out to a new, commonly-imported module and have them all as free methods, but that seems to me less clean and makes “overriding” of them in sub-classes a seem to me little messier.

Does anyone have any suggestions? Are the above my only viable options? :confused:

My thanks for any help given. :slight_smile:

Hi, couldn’t you get methods’ references using their names into getattr calls? Something like getattr( objRef, ‘methodName’ )( ).

Well, you must somehow save the base class, then you can use:

method = <BaseClass>.__dict__[<methodname>].__get__(<object>)

this will return the “methodname” callback of the given object.

First of all, thank you both for your replies. :slight_smile:

If I understand your suggestion correctly, that should only work for instance methods, for which I believe that I already have a solution. My problem lies in saving static functions (that is, functions declared in a class but with the “@staticmethod” tag).

Unfortunately, at the moment I simply have a function reference, with no record of where it came from. Calling it works properly, I believe, since it is constructed properly when passed to the class that holds it, but from that class’s point of view it seems to just be a function, which doesn’t appear to provide class information. I could enforce that the constructor of the class that holds these function references take a reference to the appropriate class for each function (updating, initialisation and completion), but that seems a little messy and open to errors to me.

I think, on reflection, that I might end up either placing these methods in some mutually-imported file as free functions, although I’ll confess that this seems unpleasantly messy to me. :confused:

(I could also insist that all such methods be instance methods, but that would, I believe, call for changing my approach to another part of the game.)

You can find the name of a method by using the name attribute of the object that holds it.

class X:
	def __init__(self, i):
		self.i = i
	def double(self):
		print self.i*2

x = X(2)
mtd = x.double
print mtd.__name__



I have tried this and it seems to work (or I’m not understanding your problem):

class C():
  def m(): print 'called'
getattr( C, 'm' )()

It prints ‘called’, as expected.

Yep, I was assuming the use of getattr already.

Again, you will need to somehow know the Class (saving a Dict, for example).

class X:
	def __init__(self, i):
		self.i = i
	def double(self):
		print self.i*2
	def power(x):
		print x*3
mtd = X.power
s = mtd.__name__

getattr(X, s)(3)

In this example mtd would be your saved callback, you save the string using the name attribute, then use it as a parameter of the getattr.

Perhaps it would help if I mocked up a simple analogous system to explain:

from File2 import * #See "File2" below

#This is not the class that I'm having trouble saving.  See below.
class Class1:
    def __init__(self):
        #init code

    def aMethod():
        #some code

scriptObj = Class2(Class1.aMethod)
#scriptObj is used for something...

# This is the class that I want to save.
class Class2:
    def __init__(self, fnPtr):
        self.myFn = fnPtr

    def getSaveData(self):
        saveList = []
        # An identifier intended to help me to determine
        # whether I'm looking at a function or a method
        # when loading.
        # Notes that static methods seem to be "Functions",
        # not "Methods".
        if isinstance(fn, types.MethodType):
            # Gets the name of the instance to which
            # this method belongs; my "GameObjects"
            # should all have a "getName" method.
        elif isinstance(self.fnPtr, types.FunctionType):
            # Since this is a function, there seems to be
            # no information on what class, if any, it
            # belongs to.  I don't see a way to distinguish
            # a function unassociated with any class from
            # one declared in a class, or to get that class
            # in the latter case.  On restoring, how do I
            # distinguish and call static methods?
        return saveList

Simply put, since I’m no longer anywhere near the construction of the function reference, I don’t know what my equivalent to “C” is. All that I have is a function reference.

Indeed, but the name isn’t my problem - the class (in the case of static methods) or lack thereof (in the case of free functions) is my sticking point.

[edit] I just saw your new post above; as I mentioned in my last post, I could require that the object holding these function references take in class names (or “None” for free functions) on construction, but that seems a little error-prone to me, and a little messier than I’d like. Nevertheless, it’s worth considering, I suppose…