Official definition of call-by-value (Re: Finding the instance reference...)

Steven D'Aprano steven at REMOVE.THIS.cybersource.com.au
Tue Nov 18 04:23:30 EST 2008


On Sun, 16 Nov 2008 15:46:54 -0800, rurpy wrote:

> Since many responses to my definition of value raised similar points, I
> will try and respond generally here.
> 
> In hindsight, I should not have used the word "value"; it is far too
> overloaded with preexisting semantics for me to have attempted to
> redefine it, even if it is the word used (but not defined) in the Python
> Reference Manual.

It shouldn't need definition, since it already has a perfectly fine 
definition in the dictionary. It would only need an alternative 
definition if the dictionary one isn't suitable.


> Let me try again, in a slightly different way and using slightly
> different terminology in the hope we can avoid the fascinating but
> basically irrelevant philosophical digressions into form and ideal, the
> nature of nothingness, etc. :-)
> 
> Suppose I have two objects and want to know if they are the same or not.

Define "the same".

Pick up two bricks from the one batch. They have identical size and shape 
and colour, but any two bricks will have slight differences. Are they the 
same?



>  They are distinct objects so I know that their id()'s are different but
> that's not what I'm interested in.  Example
> 
>   class A(object): pass
>     def __init__ (self): self.foo = 1
>   class B(object): pass
>     def __init__ (self): self.foo = 2
>   a = A()
>   b = B()
> 
> How I can answer the question, "are the objects a and b the same or
> different"? I can look at every aspect of each object, looking for
> something that is different.

Well, sure, if you care *that much* about potentially trivial aspects. I 
have a ten dollar note with a spec of dirt on one corner, and a ten 
dollar note with a slightly larger spec of dirt on a different corner. 
I'd agree with you that they are not "the same" in every aspect, but 
they're the same in every way I care about.


> What are the aspects of the object that I can look at?
> 
> id(obj) will give me the identity but I know that will be different and
> so its irrelevant.

Philosophically, no, not irrelevant. You haven't explicitly defined "the 
same" in enough detail to make that call. Perhaps because the objects are 
in different locations (different IDs) is enough to make them different, 
even if everything else about them is identical.

For example, consider the two electrons around a helium nucleus. They 
have the same mass, the same speed, the same spin, the same electric 
charge, the same magnetic moment, they even have the same location in 
space (technically, the same wave function). They are identical in every 
possible way. Are they the same electron, or two different electrons? 
What does the question even mean?

My point is that as a philosophical position, identity may or may not 
count as "sameness". It depends on the circumstances.



> What else can we look at?  We can go through each
> attribute of the objects looking for an attribute that one has and the
> other doesn't, or for attributes of the same name that are different.
> 
> We look at .__class__, .__delattr__, .... and so on and they are all the
> same until we come to .foo and note that a.foo and b.foo are different.
> One is an int(1) object, the other is an int(2) object.  So we can say
> that a and b are different.

Philosophically, sure, but practically, perhaps not. The foo attribute 
may be entirely irrelevant to your purposes, the equivalent of a random 
speck of dirt or a slight tear on a ten dollar note.

Luckily, Python doesn't try to guess whether differences are significant 
or not. You can override the __eq__ method on classes and choose for 
yourself what properties of a class are differences that make a 
difference and which are mere markers of no particular concern.

 
> Lets do the same with these two objects:
> 
>   a = int(2)
>   b = int(3)
> 
> When we do that, we find no difference!  Every attribute is the same in
> both a and b!  WTF!? 

That's because you haven't asked the objects themselves if they are the 
same. Not every aspect of objects are implemented as attributes.



> But we know when we call a's .__add__ method [*1]
> with the argument 1, we get a different result than when we call b's
> __add__ method with the argument 1.
> 
> Somehow, built into the internal representation of the int(2) object, is
> some representation of the number 2 and the int(2) object's __add__()
> method accesses this representation in order to decide that it has to
> create an int(3) object to return, rather than creating an int(47)
> object to return.
> But why don't we see this "2" when we examine the object?

Of course you do. Just look at the object and you will see it is a 2.



> Why isn't
> there a .value attribute or something holding 2?

Why should there be a value attribute? Python attributes are just a 
particular interface for accessing data. It's not the only possible 
interface.


> We look at everything we can 

You forgot to look at the object as a whole. Consider a pair of trousers. 
You're rifling through the pockets of one looking for a coin or a wallet 
or some other object to distinguish it from another pair of trousers, 
without noticing that one is made of blue cotton and the other is green 
spandex.



> but we can see no difference between the two objects, nothing
> that tells us that one is a 2, and the other a 3.

The objects themselves tell us that they are 2 or 3. They don't need an 
extra attribute, and in fact the implementation of int objects don't 
allow for extra attributes because they have no __dict__ to store them in.


> So clearly the 2-ness of int(2) is built into the object and is not
> visible *except* in it behavior.  The int(2)'s __add__ method knows how
> to access it, so do __repr() and __str__() and other methods.  But short
> of using those methods, there is no way for me (the programmer using
> Python) to access it.  The 2-ness is some sort of intrinsic property of
> the int(2) object. I will call it "intrinsic value".

I don't think this is a valuable distinction to make. What's the 
intrinsic value of a dict?


 
> The Python Reference Manual states that an object consists of identity,
> type, and value.  "Identity" seems to be non-controversial.
> 
> Let's take "type" as meaning the attributes an object inherits from it's
> class.

Let's not.

The type of an object is a label that tells Python where to look in order 
to interpret the object. It is certainly *not* the attributes on the 
object:

>>> type(5)
<type 'int'>



> "value" is then what is left: the object's local attributes and
> the intrinsic-value described above.

What do you mean by "local attributes"?

Do you mean instance attributes? That's well defined: an attribute is an 
instance attribute if it is in obj.__dict__. It is a class attribute if 
it is in obj.__class__.__dict__.

(Slots make this a little more complicated in practice, but we can ignore 
them for now.)


> This seems to be the most common view of "value", and similar to the one
> Fredrik Lundh takes in
>   http://effbot.org/zone/python-objects.htm
> which was pointed to in an earlier response (he calls it "content")
> 
> One could also take all attributes accessible through obj (its class'
> attributes as well as its local attributes) as "type" leaving only
> intrinsic-value as "value".
> This was the view I proposed.
>
> Or one could adopt what Terry Reedy called a 4-aspect view: an object is
> identity, class, value (or local-state or something) and
> intrinsic-value.

I don't think we gain anything from distinguishing value and intrinsic 
value, except confusion.


How do you deal with compound objects. What's the value of [1, 2, 3] if 
it isn't "the list consisting of ints 1, 2 and 3"?

And recursive objects?

class Parrot:
    def __init__(self):
        self.me = self

p = Parrot()

a = []
a.append(a)




> I don't understand Python well enough to defend any of these
> descriptions (I now realize, despite my previous postings to the
> contrary. :-)
> 
> But what I do defend is the concept of intrinsic value which I have not
> ever seen explicitly stated anywhere and which clarifies a lot of things
> for me.

Think about lists. The "intrinsic" value of a list is the items in the 
list itself, if it is anything, but you have an interface for looking at 
them individually:

alist[i]

Here's another problem with your idea of "intrinsic value". Consider a 
list. The list object in CPython is an array of cells, containing data. 
Some of those cells are in use, some of them are free, but regardless of 
whether they are free or in use they still have data in them. (The data 
may be obsolete in the case of the free cells. The list object also 
includes a cell which records the number of cells in the array, and 
another cell recording private information of use to the Python garbage 
collector. These cells are not necessarily the same size.

Are they part of the "intrinsic value"? You can't access them via 
attributes.

What if we use another implementation of list, say, a linked list? What 
if we use PyPy, an implementation of Python in Python, and (for the sake 
of the argument) lists are implemented as follows:

class list(object):  # untested
    def __init__(self, values):
        for i, x in enumerate(values):
            setattr(self, i, x)

(This would make a lousy implementation. Don't try it!) Does that mean 
that the value of [1, 2, 3] depends on the implementation of Python you 
create it under?


 
> For example, you can define the value of None however you want, but it
> seems clear that it has (and needs) no intrinsic-value.

To me, that seems just as silly as arguing that zero is not a number, or 
that white pixels are "nothing" and black pixels are "something".  Or 
maybe they should be the other way around?

None is None. It is what it is, and that is it's value. What *meaning* 
you put to that is up to your program. It is a convention, a useful 
convention but still merely a convention, that None is used to represent 
values which otherwise would be missing, if there could be actual holes 
in Python code.


> Same with
> object(). I now understand why the only way to describe the object
> int(2) is requires using str/repr 

Not true.

>>> x == int(3)
>>> if x == 2:
...     print "x has the value two"
... elif x == 3:
...     print "x has the value three"
...
x has the value three


At no stage did I call str() or repr() on x.


> whereas with objects without an
> intrinsic value, I can describe without needing str/repr.
>
> I can think of expressions as always returning objects, never "values".

Expressions always evaluate to objects (unless they don't return at all). 
The value of an expression is the object it evaluates to. What is wrong 
with that claim? Why do you believe that we need a more complicated, 
convoluted understanding of value? What problem are you trying to solve?



-- 
Steven



More information about the Python-list mailing list