0

This is a follow up of my previous question

I'm working on writing some constraints for a class method using PyContract (not PyContracts). As a postcondition, I'd like to ensure that the memory address of some object hasn't changed i.e. id(myObj) should be the same before and after calling the function. How can I do this with PyContract?

Here's what I'm doing right now:

def foo(param1, param2)
    """
        # some other constraints
        post[param1, param2]:
            __old__.param1 is param1
            __old__.param2 is param2
    """

However, that postcondition fails. I can only imagine that this is because __old__.param1 is not stored in the same memory location as is param1. This makes sense, as PyContract needs to make a copy of param1 before foo is executed in order to check its value against the value of param1 after foo is done executing.

Assuming that the above analysis is true, it only serves to explain why id(__old__.param1) is different from id(param1). However, it still doesn't answer how I can ensure that id(param1) doesn't change as a side-effect of foo. How could I go about checking this in PyContract?

Community
  • 1
  • 1
inspectorG4dget
  • 110,290
  • 27
  • 149
  • 241
  • 2
    This doesn't explain the PyContract behaviour, but what exactly do you hope to achieve with that postcondition? Python passes function arguments by reference, so the function won't be able to change what they refer to outside. And if the function changes what those names refer to inside the function, it won't change the binding outside either. – James Henstridge Oct 23 '12 at 07:43
  • @JamesHenstridge: touche! I hadn't considered python's behavior at all. I was more focussed on the actual contract. If you post your comment as an answer, I would accept it - it answers my question perfectly – inspectorG4dget Oct 23 '12 at 07:53

1 Answers1

1

I am not familiar with the PyContract library you are using, but the actual contract you are testing for does not make much sense in Python since function arguments are passed by reference. If you have code like the following:

x = a
y = b
foo(x, y)

Then the function will receive references to the objects named by x and y in the calling scope. Inside the function call, you have two separate variables initialised with references to those arguments.

So changes to those variables inside the function can not affect the binding of x and y in the calling scope.

James Henstridge
  • 42,244
  • 6
  • 132
  • 114
  • You describe Python's argument passing semantics correctly, but that isn't called pass by reference. Pass by reference does not mean that something called a reference is passed, it means a specific thing (and it, like several other things, is called reference) which allows mutating, among other things, the variables passed in. So `f(x)` **can** change what `x` refers to if you use pass by reference. See also: http://effbot.org/zone/call-by-object.htm –  Oct 23 '12 at 13:36
  • @delnan: Your argument holds, but only if `x` is a mutable type `f(x)` performs some in-place operation on `x`. If `f(x)` simply reassigns `x` to something else (before doing anything else, in-place or otherwise), then `x` stays the same before and after the function call, when observed from **outside** `f(x)` – inspectorG4dget Oct 23 '12 at 20:05
  • @inspectorG4dget (1) You got me wrong, I am arguing that Python does **not** use pass by reference, and `f` thus *cannot* change that `x` refers to. –  Oct 24 '12 at 11:44
  • @inspectorG4dget (2) Mutability has absolutely no effect on argument passing in any way. The rules are exactly the same: (a) No function `f` can change why `x` refers to, no matter if the object referred to is mutable or not. (b) All functions recieve a reference to the object `x` refers to (and thus share the object), whether it's mutable or not. It's just that immutable objects which are shared like that can't change their value - they never can, by definition. But one can still observe the sharing in other ways, e.g. with `id`. –  Oct 24 '12 at 11:47
  • I found [this post](http://stackoverflow.com/questions/986006/python-how-do-i-pass-a-variable-by-reference) interesting. – inspectorG4dget Oct 26 '12 at 01:45