It would be very difficult to do for the general case, but for some practical cases you could do something like this:
def call_function_checking_for_modification(f, *args, **kwargs): myargs = [deepcopy(x) for x in args] mykwargs = dict((x, deepcopy(kwargs[x])) for x in kwargs) retval = f(*args, **kwargs) for arg, myarg in izip(args, myargs): if arg != myarg: raise ValueError, 'Argument was modified during function call!' for kwkey in kwargs: if kwargs[kwkey] != mykwargs[kwkey]: raise ValueError, 'Argument was modified during function call!' return retval
But obviously there are a few problems with this. For trivial things (i.e., all input data are simple types), then this is not very useful in any case - they are likely to be immutable, and in any case they are easier (well, relatively) to detect than complex types.
However, for complex types, deepcopy will be expensive, and there is no guarantee that the == operator will work correctly. (and a simple copy is not good enough ... imagine a list in which one item changes value ... a simple copy will just save the link, and therefore the original value with the change too).
In general, however, this is not so useful, because if you are already worried about side effects when calling these functions, you can simply protect them more intelligently (by storing your own copy if necessary, checking the destination function, etc.) and if this is your function, you are worried about the occurrence of side effects, you check it to make sure.
Something like the above can be wrapped in a decorator; with expensive parts created by a global variable ( if _debug == True: something like that), maybe this can be useful in projects where many people are editing the same code, though, I think ...
Edit: this only works in environments where a more "severe" form of "side effects" is expected. In many programming languages, you can make the side effects available much more explicit - for example, in C ++, all at a cost if you don't explicitly have a pointer or link, and even then you can declare incoming links as const so that it can’t be changed There "side effects" can cause errors during compilation. (Of course, there is a way to get something anyway).
The above means that any changed values are in the return value / tuple. If you are in python 3 (I don't know yet), I think you can specify the decoration in the function declaration itself to indicate the attributes of the function arguments, including whether they are allowed to change, and include a function in this function to allow some arguments are explicitly mutable.
Notice that I think you could probably do something like this:
class ImmutableObject(object): def __init__(self, inobj): self._inited = False self._inobj = inobj self._inited = True def __repr__(self): return self._inobj.__repr__() def __str__(self): return self._inobj.__str__() def __getitem__(self, key): return ImmutableObject(self._inobj.__getitem__(key)) def __iter__(self): return self.__iter__() def __setitem__(self, key, value): raise AttributeError, 'Object is read-only' def __getattr__(self, key): x = getattr(self._inobj, key) if callable(x): return x else: return ImmutableObject(x) def __setattr__(self, attr, value): if attr not in ['_inobj', '_inited'] and self._inited == True: raise AttributeError, 'Object is read-only' object.__setattr__(self, attr, value)
(Probably not a full implementation, not a lot of testing, but the beginning). It works as follows:
a = [1,2,3] b = [a,3,4,5] print c [[1, 2, 3], 3, 4, 5] c[0][1:] = [7,8] AttributeError: Object is read-only
This will allow you to protect a specific object from modification if you do not trust the downstream function, while still being relatively light. However, it requires an explicit shell object. Perhaps you could build a decorator to do this semi-automatically, albeit for all arguments. Be sure to skip those that are called.