Finding the instance reference of an object

A

Aaron Brady

Those people clearly know a great deal about Python,
and I respect them for that. However, that doesn't
necessarily make them authorities on programming
language terminology.

If you're going to indulge in argument by authority,
you need to pick authorities that can be considered,
er, authoritative in the field concerned...

The authors of C# and Java can be considered authorities in the field
concerned. So authoritative, that if they want to redefine existing
terms, the masses must follow.
 
G

greg

Fredrik said:
Python's definition of the word "value" can be found in the language
reference:

http://docs.python.org/reference/datamodel.html#objects-values-and-types

That whole passage is talking almost
exclusively about the value of an *object*:

Every object has an identity, a type and a value...
...possible values for objects of that type...
The value of some objects can change...

etc. etc. But we don't want to know about the value of
an object, we want to know about the value of an
*expression*. That section doesn't tell us. Nor does
it tell us that expressions don't *have* values. It
says nothing about expressions at all.
> Using that definition, a Python expression yields an object, not an
> object value.

And as I've said before, that's a perfectly fine viewpoint.
Because,

An assignment statement evaluates the expression list (remember that this can
be a single expression or a comma-separated list, the latter yielding a tuple)
and assigns the single resulting object to each of the target lists, from left
to right.

[http://docs.python.org/reference/simple_stmts.html#grammar-token-assignment_stmt]

and what it says about binding makes it clear that assignment
is a form of binding operation.

So it doesn't matter *what* you call the result of an expression
-- a value, an object, an object reference, or whatever -- the
differences all cancel out when you define assignment in a
corresponding way.
 
F

Fredrik Lundh

greg said:
If you're going to indulge in argument by authority,
you need to pick authorities that can be considered,
er, authoritative in the field concerned...

Like Barbara Liskov, who's won tons of awards for her work on computer
science and programming languages, and who was among the first to
design, implement, and formally describe a language with *exactly* the
same evaluation semantics as Python? What did she and her co-authors
have to say about the calling semantics in their new language? Let's see:

"In particular it is not call by value because mutations
of arguments performed by the called routine will be
visible to the caller. And it is not call by reference
because access is not given to the variables of the
caller, but merely to certain objects."

Let's take that again, with emphasis:

"IN PARTICULAR IT IS NOT CALL BY VALUE because mutations
of arguments performed by the called routine will be visible to
the caller. And IT IS NOT CALL BY REFERENCE because access
is not given to the variables of the caller, but merely to
certain objects."

"It is not". "And it is not".

But maybe they were just ignorant, and didn't really "get" how earlier
languages worked? Let's see what Liskov has to say about that:

"The group as a whole was quite knowledgeable about languages that
existed at the time. I had used Lisp extensively and had also
programmed in Fortran and Algol 60, Steve Zilles and Craig
Schaffert had worked on PL/I compilers, and Alan Snyder had done
extensive programming in C. In addition, we were familiar with
Algol 68, EL/1, Simula 67, Pascal, SETL, and various machine
languages. Early in the design process we did a study of other
languages to see whether we should use one of them as a basis for
our work [Aiello, 1974]. We ultimately decided that none would be
suitable as a basis. None of them supported data abstraction, and
we wanted to see where that idea would lead us without having to
worry about how it might interact with pre-existing
features. However, we did borrow from existing languages. Our
semantic model is largely borrowed from Lisp; our syntax is
Algol-like."

Still think they didn't understand Algol's semantic model?

:::

But nevermind - the real WTF with threads like this one is the whole
idea that there are two and only two evaluation strategies to choose
from. That's a remarkable narrow-mindedness.

</F>
 
T

Terry Reedy

Fredrik said:
Like Barbara Liskov, who's won tons of awards for her work on computer
science and programming languages, and who was among the first to
design, implement, and formally describe a language with *exactly* the
same evaluation semantics as Python? What did she and her co-authors
have to say about the calling semantics in their new language? Let's see:

"In particular it is not call by value because mutations
of arguments performed by the called routine will be
visible to the caller. And it is not call by reference
because access is not given to the variables of the
caller, but merely to certain objects."

CLU reference manual. 1979 Google's searchable HTML version (apparently
from OCR of scan package as .pdf) with a few mis-conversions.
http://64.233.169.104/search?q=cache:iNQhnst06X8J:www.oberon2005.ru/doc/doc-mit1979-000225e.pdf

We call the argument passing technique call by sharing, because the
argument objects are shared between the caller and the called routine.

She later. in 1992, called it "pass by object" (below).
But maybe they were just ignorant, and didn't really "get" how earlier
languages worked? Let's see what Liskov has to say about that:

"The group as a whole was quite knowledgeable about languages that
existed at the time. I had used Lisp extensively and had also
programmed in Fortran and Algol 60, Steve Zilles and Craig
Schaffert had worked on PL/I compilers, and Alan Snyder had done
extensive programming in C. In addition, we were familiar with
Algol 68, EL/1, Simula 67, Pascal, SETL, and various machine
languages. Early in the design process we did a study of other
languages to see whether we should use one of them as a basis for
our work [Aiello, 1974]. We ultimately decided that none would be
suitable as a basis. None of them supported data abstraction, and
we wanted to see where that idea would lead us without having to
worry about how it might interact with pre-existing
features. However, we did borrow from existing languages. Our
semantic model is largely borrowed from Lisp; our syntax is
Algol-like."

Still think they didn't understand Algol's semantic model?

The second quote come from
A History of CLU, by Barbara Liskov 1992
http://publications.csail.mit.edu/lcs/pubs/pdf/MIT-LCS-TR-561.pdf

Python owes more to CLU than I realized.

"Assignment has a type-independent meaning with the heap approach;
x := e
causes x to refer to the object obtained by evaluating expression e."

"arguments are passed "by object"; the (pointer to the) object resulting
from evaluating the actual argument expression is assigned to the
formal. (Thus passing a parameter is just doing an assignment to the
formal.)"

Exactly described Python also.

"we wanted to treat built-in and user-defined types alike"

Achieved fully in 3.0. She notes a difference though: some built-in
types have literals. No user types do.

"We allow common operator symbols but these are only short forms for
what is really happening, namely a call on an operation using its full
t$o name. When the compiler encounters such a symbol, it "desugars" it
by following a simple rule: it produces t$o where t is the type of the
first argument, and o is the operation name associated with the symbol.
Thus "x + y" is desugared to "t$add(x, y)" where t is the type of x."

In CLU and Python, methods belong to the class/type rather than to the
instances (as in C++ she claims).

"""Not only is this approach simple and easy to understand, it applies
to both built-in and user-defined types uniformly. To allow sugars to be
used with a new type, the type definer need only choose the right
names for the operations. For example, to allow the use of +, he or she
names the addition operation "add." """

Also, CLU has exceptions that terminate and iterators used in for
statements.

Terry Jan Reedy
 
R

rurpy

Quoting the relevant part:

"The value of some objects can change. Objects whose value can change
are said to be mutable; objects whose value is unchangeable once they
are created are called immutable."

Strictly speaking that's not a definition; it doesn't say what a value
is, only how it relates to objects. But regardless, according to this,
a Python value is what the rest of the world usually calls "state",
....snip...

That just pushes the question to, "what's state?" doesn't it?
Is a method part of an object's state (and hence "value"?)
Are an object's data attribute values part of it's state?

Are the values of a, b, and c different below?

a = int(1)
class myint(int): pass
b = myint(1)
c = myint(1)
c.foo = 2

I have yet to see any reasonable definition of a Python
value in the Python docs or elsewhere, despite the fact
that a value is one of the three defining characteristics
of an object, a central concept in Python.
 
T

Terry Reedy

I have yet to see any reasonable definition of a Python
value in the Python docs or elsewhere, despite the fact
that a value is one of the three defining characteristics
of an object, a central concept in Python.

I noticed too. My try:

The value of an object is the information that the object represents (or
that is stored with the object) that the interpreter uses to compute the
value of a new object when you use the object in an expression. For
number objects, the number value. For collection objects, the objects
collected. For functions, the signature and function performed when called.

How is that?

Terry Jan Reedy
 
R

rurpy

I noticed too. My try:

The value of an object is the information that the object represents (or
that is stored with the object) that the interpreter uses to compute the
value of a new object when you use the object in an expression. For
number objects, the number value. For collection objects, the objects
collected. For functions, the signature and function performed when called.

How is that?

I am starting with the idea that "value" is what we call
whatever it is that is the difference between, for example,
the objects int(3) and int(4). While your definition
seems to be saying something similar it does not seem
very precise.

How would I use your definition to answer the following
questions?

* How does an object get a value?

* Can I create an object that has a value that
is the same as int(3) without somehow using an
int(3) object in its construction?

* Do all objects have values? (Ignore the Python
docs if necessary.)

* What is the value of object()?

* Does an object's behavior (methods) affect
its value?

* If two objects have different unrelated types
(i.e. not subclassed), are their values necessarily
different (regardless of how they print, or act
when used in an expression)?

* What if they aren't unrelated but one is a sub-
class of the other?

* Can one completely hide an object's value by
overriding methods?

* Can two objects have the same value, even if the
methods of one have been overridden to hide it's
value as completely as possible?

I wonder if all values come, directly or indirectly,
from "valued objects" created in the C-API?
Or perhaps value is some sort of useful but fundamentally
undefinable concept that disappears when looked at too
closely, leaving behind only state and behavior?
 
T

Terry Reedy

I am starting with the idea that "value" is what we call
whatever it is that is the difference between, for example,
the objects int(3) and int(4). While your definition
seems to be saying something similar it does not seem
very precise.

I think necessarily so, or rather, it can only be specific for each
class. In the formulation: an object has identify, class, and value,
class and value are separated. Others have said that type/class is a
universe of possible values and operations on those values. Each
instance has a particular value. 'Universe of possible values' is vague
until one gets specific. For some classes, the possible values are
rather complex.
How would I use your definition to answer the following
questions?

* How does an object get a value?

A Python interpreter, human or electronic, creates objects with values
as directed by Python code. How it does so is its private secret ;-).
The directive code includes literals, expressions, and some statements.
* Can I create an object that has a value that
is the same as int(3) without somehow using an
int(3) object in its construction?

Yes: 1 + 2
Yes: mpz(3) where mpz is multi-precision int class with same set of
possible values as Python ints.

??? 3.0
??? Fraction(3,1)

While Python sees these as *equal*, one could say they are not the same
because they indicate members of different (non-isomorphic) universes.
* Do all objects have values? (Ignore the Python
docs if necessary.)

If one allows null values, I am current thinking yes.
Still, numbers, characters, and collections thereof of what code is
usually about.
* What is the value of object()?

Essentially none, other than bool(object()) == True.
Ditto for None, other than bool(None) == False.
Otherwise, None and object convey no information.
* Does an object's behavior (methods) affect
its value?

My first answer is No. Instance methods are attributes of a class and,
in most cases, the value of a class. In those cases in which the class
of an object can be and is changed to another class, the interpretation
of the value/info of the instance could change and one might claim that
the effective value and hence the value of the object has changed and
hence the answer could be Yes. But this is extremely rarely done and I
could claim that this is a shortcut for creating a new object and
deleting the old.
* If two objects have different unrelated types
(i.e. not subclassed), are their values necessarily
different (regardless of how they print, or act
when used in an expression)?

No. See above Q. about int(3).
* What if they aren't unrelated but one is a sub-
class of the other?

Easier no than above.
* Can one completely hide an object's value by
overriding methods?

You tell me ;-)
Do you have an example that you were thinking of?
* Can two objects have the same value, even if the
methods of one have been overridden to hide it's
value as completely as possible?

I wonder if all values come, directly or indirectly,
from "valued objects" created in the C-API?

CPython creates objects with values in C functions. I presume most are
exposed in the API. But my definition is intentionally not specific to
any implementation.
Or perhaps value is some sort of useful but fundamentally
undefinable concept

Either yes or defined in terms of information or universes.
that disappears when looked at too closely
No.

Leaving behind only state and behavior?

State is a choice amoung possible states, which is to say, information.
Behavior is determined by class,

Terry Jan Reedy
 
S

Steven D'Aprano

I think necessarily so, or rather, it can only be specific for each
class. In the formulation: an object has identify, class, and value,
class and value are separated. Others have said that type/class is a
universe of possible values and operations on those values. Each
instance has a particular value. 'Universe of possible values' is vague
until one gets specific. For some classes, the possible values are
rather complex.

I prefer another definition of object: an object *is* a value, rather
than *has* a value. That value consists of identity, type (or class), and
everything else of interest which is sometimes also called "value". Since
identity is usually unimportant, and type is assumed from context, we can
often get away with stating that the "everything else of interest" is
*the* value.

I usually talk about one of the three levels of value:

(1) The value of the NAME (or variable) x is the object int(3); that is,
the thing denoted by the symbol x is the object int(3).


(2) The value of the OBJECT int(3) is the specific concrete instantiation
that makes it the thing that it is rather than another thing (a
complicated way of saying that the value of an object is itself); that
is, the thing denoted by the symbol int(3) is some specific byte pattern
in memory which causes that object to be int(3) rather than some other
object.

To put it another way, the value of that object is whatever properties of
the object distinguish it from any other the whole number 1. Since
identity is (usually) unimportant for distinguishing one object from
another (we usually care whether x==y, not whether x is y) the identity
is not part of the value. We're generally indifferent to the serial
number on our ten dollar bills: any note is (usually) as good as any
other note. But sometimes identity is important, and in some specific
contexts I'd be happy to say that the value of a symbol must include the
identity of the object.


(3) But at another level, the value of the object int(3) is the abstract
integer three. This is the only level at which I'm happy to talk about
objects (as opposed to names) "having" a value: "object int(3) has the
value three".


A Python interpreter, human or electronic, creates objects with values
as directed by Python code. How it does so is its private secret ;-).
The directive code includes literals, expressions, and some statements.

I would answer that the object *is* the value, but with the proviso that
we usually don't care about identity:
False

I'm happy to say that the value of x and the value of y are the same,
even though they have different identities. But context is important:
there are times were I would want to wrap identity under the umbrella of
value. See below.

Yes: 1 + 2
Yes: mpz(3) where mpz is multi-precision int class with same set of
possible values as Python ints.

??? 3.0
??? Fraction(3,1)

While Python sees these as *equal*, one could say they are not the same
because they indicate members of different (non-isomorphic) universes.

Whether we wish to say that mpz(3) has the same value as int(3) depends
on what we care about, and we only care about that because our data types
are leaky abstractions. In principle, we should be indifferent to whether
x is int(3), float(3.0), mpz(3), or any other instantiation of the
abstract numeral three. In practice, we're not indifferent: we prefer
ints for mpz objects for some purposes, but not for others. If we care
about the specifics, then we might say they have different values
(because they have different types, and therefore different
characteristics). If we care only about the thing they represent, the
abstract number three, then we'd say that they have the same value.


If one allows null values, I am current thinking yes. Still, numbers,
characters, and collections thereof of what code is usually about.

I would say that all objects *are* values, rather than *have* values. The
value of None is the object None, which is a concrete instantiation of a
selected subset of behaviour of the null object pattern.


Essentially none, other than bool(object()) == True. Ditto for None,
other than bool(None) == False. Otherwise, None and object convey no
information.

I would say that the "everything of interest" I referred to above is the
empty set: object() has little or no state. But of course having no state
is itself a state, in the same way that 0 is a perfectly good integer.

In practice, I'd say that object() is one of those cases where we should
include identity in the value. Although we're indifferent as to *which*
object() instance we get, once we've got one, we care whether other
instances are the same instance or different ones. Imagine that object()
keeps a cache of instances, and returns one instead of creating a brand
new object. We don't care which instance we get, or even whether it comes
from the cache or is created fresh. But once we have one, we care about
the identities of others:

special = object() # we don't care which object instance we get
if special is some_other_instance():
print "Match!"


My first answer is No. Instance methods are attributes of a class and,
in most cases, the value of a class. In those cases in which the class
of an object can be and is changed to another class, the interpretation
of the value/info of the instance could change and one might claim that
the effective value and hence the value of the object has changed and
hence the answer could be Yes. But this is extremely rarely done and I
could claim that this is a shortcut for creating a new object and
deleting the old.

I would say that the answer to this is, "Would you like to include
behaviour in value?". Let me give you an example:

class String(string):
def upper(self):
return "spam"

s1 = "Norwegian Blue"
s2 = String("Norwegian Blue")


Do s1 and s2 have the same value?

Using definition (1) above, we can see that the names s1 and s2 refer to
different objects, so the names have different values.

Using definition (2), the objects s1 and s2 have different concrete
expressions, and so they are different values. (Remember: the object is
the value.) But from definition (3) they both represent that same
abstract string, so if I care only about that level of description, I'd
say yes they *have* the same value but *are* different values.

Assuming I cared about the behaviour of upper(), then s2 is probably not
suitable for my purposes and so I would like to distinguish s1 from s2.
I'd insist that they have different values which merely looked the same
under equality. To use the bank note analogy, then s1 is legal tender but
s2 is just a very good forgery.

But note that to a collector of forgeries, s2 might be more valuable than
s1, and presumably the writer of class String had a reason for the
behaviour given. The answer to the question "do s1 and s2 have different
values" will depend on why you are asking.



[snip]
Either yes or defined in terms of information or universes.


No.

I would say that although value is dependent on context, that's no excuse
for concluding that it has no meaning. If you look too closely at
*anything*, it becomes fuzzy. (Well, with the possible exception of pure
mathematics.)
 
A

Aaron Brady

On Fri, 14 Nov 2008 22:56:52 -0500, Terry Reedy wrote: snip
I would say that the answer to this is, "Would you like to include
behaviour in value?". Let me give you an example:

class String(string):
    def upper(self):
        return "spam"

s1 = "Norwegian Blue"
s2 = String("Norwegian Blue")

Do s1 and s2 have the same value?

Using definition (1) above, we can see that the names s1 and s2 refer to
different objects, so the names have different values.

Using definition (2), the objects s1 and s2 have different concrete
expressions, and so they are different values. (Remember: the object is
the value.) But from definition (3) they both represent that same
abstract string, so if I care only about that level of description, I'd
say yes they *have* the same value but *are* different values.

Assuming I cared about the behaviour of upper(), then s2 is probably not
suitable for my purposes and so I would like to distinguish s1 from s2.
I'd insist that they have different values which merely looked the same
under equality. To use the bank note analogy, then s1 is legal tender but
s2 is just a very good forgery.

But note that to a collector of forgeries, s2 might be more valuable than
s1, and presumably the writer of class String had a reason for the
behaviour given. The answer to the question "do s1 and s2 have different
values" will depend on why you are asking.
snip
I would say that although value is dependent on context, that's no excuse
for concluding that it has no meaning. If you look too closely at
*anything*, it becomes fuzzy. (Well, with the possible exception of pure
mathematics.)

I'm reading that the result of the __eq__ comparison isn't the only
meaning of value, and that there is more than one.
.... def upper(self):
.... return "spam"
....False

Murmur, good. I could see rejecting that two objects of different
types can have the same value. I could also see rejecting that 'the
value than an object is' is nonsense, permitting only 'the value that
an object has'. However, as a counterexample, 'x has the value [1, 2,
3]' and 'x is [1, 2, 3]' are both colloquially sensical statements,
though the latter is imprecise, because 'x is [1, 2, 3], y is [1, 2,
3], x is not y'; certainly '[1, 2, 3]' is neither 'x' nor 'y', and
identity is a commutative relation.

If you'll permit a tangent into another (computer) language, I don't
have a problem saying either that the value of x in 'int* x' in C is a
memory address, or that its value is an integer, which stance is
definitely prone to miscommunication. I still maintain that passing
an object by value calls its copy constructor.
 
A

Arnaud Delobelle

I have yet to see any reasonable definition of a Python
value in the Python docs or elsewhere, despite the fact
that a value is one of the three defining characteristics
of an object, a central concept in Python.

I don't remember how the expression 'object value' is used in the Python
docs (and python.org is unreachable from where I am at the moment) but I
know that I don't need such a concept to understand, or code in, Python.

Objects have a type, may have attributes, and that's it!
 
R

rurpy

First of all, thanks. Thanks to your answers I have
finally been able to formulate a concept of Python
values. Now we'll see if it is valid/usable... :)
I think necessarily so, or rather, it can only be specific for each
class. In the formulation: an object has identify, class, and value,
class and value are separated. Others have said that type/class is a
universe of possible values and operations on those values. Each
instance has a particular value. 'Universe of possible values' is vague
until one gets specific. For some classes, the possible values are
rather complex.


A Python interpreter, human or electronic, creates objects with values
as directed by Python code. How it does so is its private secret ;-).
The directive code includes literals, expressions, and some statements.
OK.


Yes: 1 + 2

OK, but my question was too strict.
"1 + 2" is shorthand for: int(1).__add__(int(2))
Rephrasing: is possible to create an object that has
a value that is the same as int(3) without somehow
using a method of the int class (or sub/super-class)
in its construction?
I think it is not possible in the Python language.
That is one could in theory have a float method,
to_int(), but it could not be implemented in the
Python language (as opposed to implemented in the
Python implementation) without using int(), or some
other callable that uses int().
Yes: mpz(3) where mpz is multi-precision int class with same set of
possible values as Python ints.

The argument to mpz() is int(3).
??? 3.0
??? Fraction(3,1)

While Python sees these as *equal*, one could say they are not the same
because they indicate members of different (non-isomorphic) universes.

At this point, I would so say.
If one allows null values, I am current thinking yes.

I don't see a difference between a "null value"
and not having a value.
Still, numbers, characters, and collections thereof of what code is
usually about.

Yes, which is why we have int, str, and list classes
which, unlike some others, can have values.
Essentially none, other than bool(object()) == True.
Ditto for None, other than bool(None) == False.
Otherwise, None and object convey no information.

A method/function can use whatever characteristic of
its arguments that it wants. For example, id() pays no
attention to the value of its argument, only its identity.
So we can say that the bool class constructor returns
True for all object except None. Since None is a
singleton, bool() can identify it by identity, without
consideration of it's (non-existent I propose) value.
My first answer is No. Instance methods are attributes of a class and,
in most cases, the value of a class.

The value of a class is it's attributes?
Are you saying that attributes of an object are
part of its value? That would mean that 'a'
and b' below have different values?

class My_int(int):
def __init__(self): self.foo = None
a = int(3)
b = My_int(3)

I propose that attributes are not part of a class'
(or any other object's) value and that a class object
has no value.
of an object can be and is changed to another class, the interpretation
of the value/info of the instance could change and one might claim that
the effective value and hence the value of the object has changed and
hence the answer could be Yes. But this is extremely rarely done and I
could claim that this is a shortcut for creating a new object and
deleting the old.


No. See above Q. about int(3).

I now think this answer is yes. See above Q. about int(3). :)
Easier no than above.

Yes, I agree no. :)
You tell me ;-)

My guess is no. For example, if I try to make int that
appears to be 1 + its "real" value:

class myInt (int):
def __repr__ (self): return int.__repr__(self + 0)
def __str__ (self): return int.__str__(self + 0)
def __add__ (self, x): return int.__add__(self, x + 1)
def __radd__ (self, x): return int.__add__(self, x + 1)
def __sub__ (self, x): return int.__sub__(self, x - 1)
def __rsub__ (self, x): return int.__sub__(self, x - 1)
...etc...

At first it seems to work:
-2

But 8.0

:-(

Do you have an example that you were thinking of?

Nothing specific. I was trying to see if one can
separate the behavior of objects from whatever it
is that constitutes value. The example above conveys
to me at least that value and behavior *can* be
separated -- even if one could completely hide the
"real" value of an object, one can still view it
as having a real value, and it's apparent value as
something produced by it's behavior.
CPython creates objects with values in C functions. I presume most are
exposed in the API. But my definition is intentionally not specific to
any implementation.

OK, s/C-API/implementation/
Either yes or defined in terms of information or universes.


No.

Good, I am not chasing a chimera.
State is a choice amoung possible states, which is to say, information.
Behavior is determined by class,

Here is my (tentative) concept of value. I will
give a wordy version and leave a clear, concise
definition to later, or someone else, whichever
occurs first. :)

Some builtin[1] objects have a value.
A value is a "hidden" piece of data in an object
that is not directly accessible from the Python
language; access to an object's value is provided
only through methods of the object's class. The
object's methods can (and usually will) make use
of the object's value when producing an object
to return or changing the object's state or value.

It is not possible to define a class in Python
that provides its objects with a value unless
that class is derived from a builtin class that
provides a value.[3]

If this in not an inaccurate description of "value"
it clears up several points of confusion for me:
* No need to worry about what the value of object() is.
(it has no value.)
* No need to worry about whether expressions return
values. (They don't, they always return (references
to) objects.)
* Where do values come from? (They are created/modified
by methods of builtin classes and are otherwise not
directly accessible.)
* How can I find an object's value (if I don't believe
.str(), .repr(), etc)? Use gdb. :)

Notes:

[1] "builtin" is not the right word, but I'm not sure
what is. I mean, in C-Python, an object created
using the C-API, rather than purely in Python. This
includes true builtin objects, as well as objects
created in C extensions in stdlib and 3rd-party
extensions. How to express the distinction
between classes that are or can be defined purely
in Python and those that aren't (can't), in an
implementation independent way, I don't know.
(I presume that in PyPy, everything is defined
in Python.)

[2] I wrote things like "... is not directly accessible"
and "is not possible to...". That is true for C-Python
but other implementations could violate those statements.
So they probably should be rewritten to "... need not
be directly accessible", "need not be possible to...",
etc.

[3] For rhetorical purposes I am writing factually. In
reality I am not certain of most of what I've written.
I'm sure mistakes will not go uncorrected and view
this thread as a learning exercise.
 
T

Terry Reedy

First of all, thanks. Thanks to your answers I have
finally been able to formulate a concept of Python
values. Now we'll see if it is valid/usable... :)

Good questions help refine a concept.
OK, but my question was too strict.
"1 + 2" is shorthand for: int(1).__add__(int(2))

Both are shorthand for int.__add__(int(1),int(2)). Liskov intentionally
designed CLU with methods belonging to classes, not instances, because
the binary op case does not fit the idea of some that a method is a
message to an actor, that 1+2 means 'hey 1, add 2 to yourself'.

....
The value of a class is it's attributes?
Are you saying that attributes of an object are
part of its value?

Either: objects have 4 aspects -- id, class, attributes, and value
Or: attributes are included with value, so that obs have 3 aspects --
id, class, and value.
[Or: (Aprano) id, class, and attributes are included with value.]

I an not sure yet which viewpoint/formulation is the more useful. I
answered from the 3-aspect viewpoint. It is more traditional, but
probably predates 'objects with attributes' as opposed to 'strucures
with fields'. But I suspect that the values of the fields would be
considered the value of the structure. In any case, I have also
considered the 4-aspect view also.
That would mean that 'a'
and b' below have different values?

class My_int(int):
def __init__(self): self.foo = None
a = int(3)
b = My_int(3)

Yes, and indeed, a.foo raises an exception and b.foo does not.

If attributes are included with value, then value must be subdivided
into attributes and private value. For numbers, the private value is
the numerical value; it cannot be accessed separate from the number
object itself. Strings have a private value which can be exposed a
character or slice at a time. Numbers and strings are the two classes
with literals.
I propose that attributes are not part of a class'
(or any other object's) value and that a class object
has no value.

That is the first choice of the either/or choice above. It is okay as
long as it is understood that 'value' is being used in a restrictive sense.

Here is one reason I have not adopted it yet (and I need to make a
choice for the algorithm book I am writing). Consider a(b). This means
'call a with argument b'. I would rather say 'the value of a is what it
does with b (for all possible b), which is to say, the mapping it
implements', than to explain calling in terms of an
implementation-dependent, essentially private, attribute structure.

So I am thinking I may go with
class: determines universe of possible values of instances and (with
superclasses) functions such instances can work with. 'Functions'
includes all types of syntactic expressions.
value: determine specific result when used as argument in functions

Terry Jan Reedy
 
R

rurpy

So if method .foo() is an instance attribute it
is part of the object's value, but if it is part
of the object's class, it is part of the object's
behavior? Even though calling obj.foo() causes
exactly same results? I can see that a case can
be made for defining things that way, but it doesn't
seem desirable.
The value of a class is it's attributes?
Are you saying that attributes of an object are
part of its value?

Either: objects have 4 aspects -- id, class, attributes, and value
Or: attributes are included with value, so that obs have 3 aspects --
id, class, and value.
[Or: (Aprano) id, class, and attributes are included with value.]

Or: object attributes are considered together with class
attributes to define an object's behavior leading to:
obs have 3 aspects -- id, behavior, and value.
(The definition of "type" might be stretched a little to
make it synonymous with behavior.)
I an not sure yet which viewpoint/formulation is the more useful. I
answered from the 3-aspect viewpoint. It is more traditional, but
probably predates 'objects with attributes' as opposed to 'strucures
with fields'. But I suspect that the values of the fields would be
considered the value of the structure. In any case, I have also
considered the 4-aspect view also.


Yes, and indeed, a.foo raises an exception and b.foo does not.

But raising an exception is a aspect of behavior,
not of value.
If attributes are included with value, then value must be subdivided
into attributes and private value. For numbers, the private value is
the numerical value; it cannot be accessed separate from the number
object itself. Strings have a private value which can be exposed a
character or slice at a time. Numbers and strings are the two classes
with literals.

It seems to me that what I think of as "value" is
indeed a sort of private attribute (that's how I
am trying out thinking of it.) But it is its
privateness, its totally different way of getting
created, used, and changed, that is the very thing
that makes it unique and worthy of getting it's
own name.
That is the first choice of the either/or choice above. It is okay as
long as it is understood that 'value' is being used in a restrictive sense.

Which seems to me to most closely match the intuitive
sense of value. To me it is intuitive that int(3)
and subclass_of_int(3) have the same value, 3. To
learn that their values are different because one
has an attribute the other didn't, or because the
values in a common (in name) attribute were different,
would be very surprising to me.
Here is one reason I have not adopted it yet (and I need to make a
choice for the algorithm book I am writing). Consider a(b). This means
'call a with argument b'. I would rather say 'the value of a is what it
does with b (for all possible b), which is to say, the mapping it
implements', than to explain calling in terms of an
implementation-dependent, essentially private, attribute structure.

I can see viewing functions in general as a mapping
of arguments values to results in the context of describing
algorithms. I am not sure it is the best way to view
them in the context of how objects are manipulated in
the Python runtime environment.
So I am thinking I may go with
class: determines universe of possible values of instances and (with
superclasses) functions such instances can work with.

If attributes are part of an object's value, that
universe is effectively infinite, isn't it? For
the vast majority of objects (those created in
Python from a class not designed to impose bondage
and discipline by using slots for example) I can
add any attributes I wish with any values I wish
to an object. So class doesn't really determine
much under that definition, does it?
'Functions'
includes all types of syntactic expressions.

Doesn't that use of the word "function" conflict
with the already established use of "function"
in Python. I.e., I think of functions as just
another object, albeit one with a code attribute
that the Python VM knows how to call.

I think of evaluation of expressions as a series
of method (or other callable) executions, each
returning an object that is used in the next step
of the series.
value: determine specific result when used as argument in functions

You are prepared to redefine everything about
objects. I was trying to restrict my redefinition
to only value. But I see your point that the
existing definition of object does not handle
instance attributes very well either.

In comparing your definitions with mine, I think
I see a difference in view point. It seems to me
you give greater attention to class, whereas my
mental model of Python focuses more on individual
objects. I think I was led to that view by Python's
very dynamic behavior. One can dynamically coerse
an A instance into behaving nearly indistinguishably
from a B instance. So what A was before seems some-
what academic.

I tend to think of an object's class as a template
for creating new instances and a convenient place
to stash common attributes to avoid duplicating them
in each instance. (Is this too simplistic?) So I
think of behavior (as defined by attributes) to be
more closely related to the instance than the class.
In my model, there is not a big problem not making
a strong distinction between class attributes and
an instance's attributes -- I think of the union of
the object's attributes, its class' attributes (and
superclass attributes recursively) as all being virtually
part of the instance.

Python itself encourages this view I think. A while
ago I tried to write an object examiner and found it
hard to figure out, in the results for inspect.getmembers(obj),
which belonged to obj, which obj's class, obj's class'
superclass, etc. Same with dir()'s results.
 
R

rurpy

[Tried multiple times to post this but Google errors
out so will try posting in two parts... this is part 1]


I will presume you read my response to Terry Reedy so
I won't repeat everything I said there here.
I prefer another definition of object: an object *is* a value, rather
than *has* a value. That value consists of identity, type (or class), and
everything else of interest which is sometimes also called "value". Since
identity is usually unimportant, and type is assumed from context, we can
often get away with stating that the "everything else of interest" is
*the* value.

The Python Lang. Ref. says:
object = identity + type + value
You are defining objects as:
object = identity + type + (object - (identity + type))
value = object - identity = type + (object - (identity + type))

Seems to me it is easier just to give the "object - (identity + type)"
part a name, say, "value". :)

I also question, "type is assumed from context". To
me, type is very objective: it is the set of methods
and other attributes that define the behavior of the
object.
I usually talk about one of the three levels of value:

(1) The value of the NAME (or variable) x is the object int(3); that is,
the thing denoted by the symbol x is the object int(3).

OK, but a name is a rather abstract concept, is it
not? Because of Python's interpreted nature, names
can't be compiled away as in C, they need a concrete
runtime existence, but does the language definition
need to assume that?

And per innumerable previous discussions, is it not
preferable to "bind the name to an object" sidestepping
any need for "value" in this context?
(2) The value of the OBJECT int(3) is the specific concrete instantiation
that makes it the thing that it is rather than another thing (a
complicated way of saying that the value of an object is itself); that
is, the thing denoted by the symbol int(3) is some specific byte pattern
in memory which causes that object to be int(3) rather than some other
object.

I don't see how saying "the value of an object is
itself" is particularly useful. We already have a
word for what an object is, it is "object". :)
The point of the word "value" is to describe, in
a general way, without defining implementation
details, what you describe as "some specific byte
pattern in memory which causes that object to be
int(3) rather than some other object" and does not
mix in other bit-pattern differences, such as
differences in type which are not relevant to what
we intuitively think of as "value".
To put it another way, the value of that object is whatever properties of
the object distinguish it from any other the whole number 1.

This is saying something different, that the value
of an object depends on how it's type relates to
some non-programming-language concept ("whole numbers"
in this case) that the object attempts to model.
Since
identity is (usually) unimportant for distinguishing one object from
another (we usually care whether x==y, not whether x is y) the identity
is not part of the value.

The result of x==y depends solely on the behavior (methods)
of x. (To be anal, the behavior of x might be to delegate
calculating the result to y). That behavior (if reasonable)
will take into consideration the "value"s of x and y. This
seems to imply that "value" is something more specific
than the totality of the x and y objects.
We're generally indifferent to the serial
number on our ten dollar bills: any note is (usually) as good as any
other note. But sometimes identity is important, and in some specific
contexts I'd be happy to say that the value of a symbol must include the
identity of the object.

What you or I think is important in a calculation
need not have a bearing on an object's value. id()
does not need to consider that identity is part of
an object's value -- its programmer needed merely
use identity if that's what was needed, while it's
argument goes on having whatever value it has.
(3) But at another level, the value of the object int(3) is the abstract
integer three. This is the only level at which I'm happy to talk about
objects (as opposed to names) "having" a value: "object int(3) has the
value three".

As above, where you referred to "the whole number 1",
this seems problematic. What one is doing is mapping
int's to the mathematical concept of integers and using
the equivalence of integers to decide the equivalence
of ints. This is fine if you are relating the behavior
of your program to real-world mathematics. But in
some cases the mapping may not be so clear, nor may
there be universal agreement about what is equivalence
in the real-world concept, so it seems shaky to pin
a fundamental defining concept of Python objects to
this.

Is the value of float(1.0/3.0) the same as
float(.3333333333333333)? Mathematics says no, but
Python (at least on my machine) says yes. (At least
if you accept that the "==" operation is written to
compare values.)
I would answer that the object *is* the value, but with the proviso that
we usually don't care about identity:

False

I'm happy to say that the value of x and the value of y are the same,
even though they have different identities. But context is important:
there are times were I would want to wrap identity under the umbrella of
value. See below.

So you would say that a and b have different values below?

class My_int(int):
def __init__(self): self.foo = None
a = int(3)
b = My_int(3)

How can one have an objective definition
of "value" if it depends on context?

[continued...]
 
R

rurpy

[Tried multiple times to post this but Google errors
out so will try posting in two parts... this is part 2]
Whether we wish to say that mpz(3) has the same value as int(3) depends
on what we care about, and we only care about that because our data types
are leaky abstractions. In principle, we should be indifferent to whether
x is int(3), float(3.0), mpz(3), or any other instantiation of the
abstract numeral three. In practice, we're not indifferent: we prefer
ints for mpz objects for some purposes, but not for others. If we care
about the specifics, then we might say they have different values
(because they have different types, and therefore different
characteristics). If we care only about the thing they represent, the
abstract number three, then we'd say that they have the same value.

You are saying there is no objective definition
of "value". I disagree. I think one can define
value in a useful way that is precise, objective,
and useful.
I would say that all objects *are* values, rather than *have* values. The
value of None is the object None, which is a concrete instantiation of a
selected subset of behaviour of the null object pattern.


I would say that the "everything of interest" I referred to above is the
empty set: object() has little or no state. But of course having no state
is itself a state, in the same way that 0 is a perfectly good integer.

"interest" is pretty subjective, isn't it? In the
My_int example above, is the .foo attribute of interest
or not? How would I decide? How would you decide?
I was also going to ask about changing methods, but I
see you consider that below.
In practice, I'd say that object() is one of those cases where we should
include identity in the value. Although we're indifferent as to *which*
object() instance we get, once we've got one, we care whether other
instances are the same instance or different ones. Imagine that object()
keeps a cache of instances, and returns one instead of creating a brand
new object. We don't care which instance we get, or even whether it comes
from the cache or is created fresh. But once we have one, we care about
the identities of others:

special = object() # we don't care which object instance we get
if special is some_other_instance():
print "Match!"


I would say that the answer to this is, "Would you like to include
behaviour in value?". Let me give you an example:

class String(string):
def upper(self):
return "spam"

s1 = "Norwegian Blue"
s2 = String("Norwegian Blue")

Do s1 and s2 have the same value?

Using my definition of value, the answer is
an unambiguous yes.
Using definition (1) above, we can see that the names s1 and s2 refer to
different objects, so the names have different values.

No, they refer to different objects. The object
str("Norwegian Blue") has a value, tucked away
inside it somewhere, of some implementation defined
bits that encode "Norwegian Blue".

String("Norwegian Blue") is a subclass of str
and has the same value. (Actually, we don't really
care about bit patterns, it is enough to declare
that the values stored in the objects are the same
because that's how the language is defined.)
If they appear different when .upper() is called,
it is because the two types (i.e. behaviors) are
different.
Using definition (2), the objects s1 and s2 have different concrete
expressions, and so they are different values. (Remember: the object is
the value.)

Sorry, I disagree.
But from definition (3) they both represent that same
abstract string, so if I care only about that level of description, I'd
say yes they *have* the same value but *are* different values.

They "have" the same value, it is the difference
in their behavior (type) that produces different
results from .upper().

class xint (int):
def bigger(self):
"return a number bigger than me."
return self + 2
class yint (xint):
def bigger(self):
"return a number very much bigger than me."
return self + 1000
a = xint(5)
b = yint(5)

Do you claim that a and b really have different values?
Assuming I cared about the behaviour of upper(), then s2 is probably not
suitable for my purposes and so I would like to distinguish s1 from s2.
I'd insist that they have different values which merely looked the same
under equality. To use the bank note analogy, then s1 is legal tender but
s2 is just a very good forgery.

But note that to a collector of forgeries, s2 might be more valuable than
s1, and presumably the writer of class String had a reason for the
behaviour given. The answer to the question "do s1 and s2 have different
values" will depend on why you are asking.

That is ok if one is happy with such a squishy,
subjective definition of value. But I propose
that one can define value in a precise way that
captures what most people think of as value, and
avoids confusing objects (or references to them)
and the value of objects.

Given that "value" is one of the three defining
characteristics of objects, a (the?) central concept
of Python, I don't see how such a subjective definition
as yours is workable.
[snip]
Either yes or defined in terms of information or universes.


No.

I would say that although value is dependent on context, that's no excuse
for concluding that it has no meaning. If you look too closely at
*anything*, it becomes fuzzy. (Well, with the possible exception of pure
mathematics.)

But it is desirable to define with as little
fuzz as possible :)
 
S

Steven D'Aprano

* Can I create an object that has a value that
is the same as int(3) without somehow using an int(3) object in its
construction?
[...]
Yes: mpz(3) where mpz is multi-precision int class with same set of
possible values as Python ints.

The argument to mpz() is int(3).

Does mpz take string arguments? If it doesn't, it is easy to imagine a
version that does.

mpz("3")


I don't see a difference between a "null value" and not having a value.

Ah, the Medieval concept of numbers. Of course it's very much older than
Medieval. Roman and Greek mathematics was bedeviled by their philosophy
that one is the smallest number. (In fact, some early mathematicians
argued that *two* was the smallest number, for the reason that if you
have only one sheep (say) it would be unnatural to say that "I have a
number of sheep") It wasn't until the fifth century C.E. that Indian
mathematicians invented the concept of zero, and it took many centuries
for the idea to get to Europe via the Arabs.

If you wish to say that null values aren't values at all, you will find
that you have many conceptual difficulties. Given:

x = 5
y = 5
z = x - y

you will be forced to say that x and y have values but z does not. But
that doesn't mean that z is undefined -- it means that z is defined and
has no value, which makes communication very much more complicated. You
are forced to say things like:

"The value of the object is the number of sheep in the paddock, unless
the number of sheep is zero, in which case the object has no value..."

which is needlessly complicated.

I say that 0 is a perfectly fine value. So is None, [], {}, and any other
null-value. I recommend you don't complicate and confuse matters by
trying to treat them differently.


Yes, which is why we have int, str, and list classes which, unlike some
others, can have values.

What classes do you think have no values?



[snip]
The value of a class is it's attributes? Are you saying that attributes
of an object are part of its value? That would mean that 'a' and b'
below have different values?

class My_int(int):
def __init__(self): self.foo = None

That won't work you know.
a = int(3)
b = My_int(3)


That depends on whether the existence of foo makes a difference to you or
not. Consider pickle. Since pickle can't predict what aspects of the
object are important, it must treat *everything* as significant, and
pickle will absolutely treat a and b as having different values.

(Actually, that's not quite true: by necessity pickle *cannot* treat
identity as important. If your application requires object identity to be
persistent over execution session, you can't do so in Python. Hence
pickle and related serialisers can afford to ignore identity.)

Given input of b, the round-trip of pickle/unpickle must return an object
with a foo attribute. If the round-trip merely returns a My_int instance
without the foo attribute, we would rightly consider it a bug, that the
output doesn't have the same value as the input. Likewise if it returned
int(3) instead of My_int(3).

But other functions may have weaker constraints. Consider sum([a, b]).
The function sum makes no promises that it will return the same type as
it's arguments. Since, *for the purposes of addition*, the foo attribute
has no significance, sum() makes no promise whether the sum of a and b
will include the foo attribute. In fact it does not. As far as addition
is concerned, a and b have the same value, and the foo attribute is lost.

In general, Python makes the fewest possible promises of that nature. If
you want to treat foo as having a significant part of the value of b,
then you need to deal with it yourself, perhaps by writing __add__ and
__radd__ methods to My_int.

But from a philosophical position, as opposed to a practical one, of
course a and b have different values. The value of a is (the integer 3),
and the value of b is (the integer 3 together with an attribute foo),
even if foo is a mere decoration, a stripe of red paint on an otherwise
identical object. Since they are different, the objects a and b have
different values. This is a valid philosophical position, although in
practice we often lower our expectations, especially when duck-typing. We
don't care about the red stripe or not, and so we are indifferent to
whether we get int(3) or My_int(3).


I propose that attributes are not part of a class' (or any other
object's) value and that a class object has no value.

Consider:

import urllib2
x = urllib2.urlopen('http://www.yahoo.com')
y = urllib2.urlopen('ftp://ftp.dina.kvl.dk/pub/Math-reports/README')

Do you really want to say that the objects x and y have the same value
(or worse, "no value") just because all the significant "stuff" that
distinguishes x from y are stored as attributes? I suggest that you are
looking at many conceptual difficulties if you make that distinction.

I would say that the value of the object x is the open HTTP connection to
www.yahoo.com while the value of the object y is the open FTP connection
to ftp.dina.kvl.dk/pub/Math-reports/README. The nature of how those
values are stored is irrelevant. Whether they are class attributes in the
Python implementation, or data structures in C, or byte patterns in a
database, is irrelevant (except perhaps for performance issues).


I now think this answer is yes. See above Q. about int(3). :)


Yes, I agree no. :)

Classes and subclasses is a mere implementation detail, a specific method
of implementing a range of useful programming techniques. Consider
delegation as an alternative to inheritance.

class MyInt:
def __init__(self, value):
self.__dict__['_delegate'] = value
def __getattr__(self, name):
return getattr(self._delegate, name)
def __setattr__(self, name, value):
setattr(self._delegate, name, value)
def __delattr__(self, name):
delattr(self._delegate, name, value)

n = MyInt(3)

The object n behaves just like int(3), except the class is different. For
the purposes of arithmetic, why would you insist that their values are
*necessarily* different?


Consider this subclass of int:

class WeirdInt(int):
def __new__(cls, value):
return int.__new__(cls, -value)
def __init__(self, value):
self._magic = value
def __str__(self):
return str(self._magic)
__repr__ = __str__

n = WeirdInt(3)

Why would you say that the value of n is *necessarily* the same as the
value of int(3) just because it is subclassed from int? Let's see how
they behave:
3


I would say that n has a unique value: it is an object that looks like 3
but behaves like -3. It is different from both int(3) and int(-3).
Subclassing is irrelevant.


My guess is no. For example, if I try to make int that appears to be 1
+ its "real" value:

[snip failed example]

You neglected to override __float__.

But using the example of WeirdInt above:
-2.0




Nothing specific. I was trying to see if one can separate the behavior
of objects from whatever it is that constitutes value. The example
above conveys to me at least that value and behavior *can* be separated
-- even if one could completely hide the "real" value of an object, one
can still view it as having a real value, and it's apparent value as
something produced by it's behavior.

Ah, you're coming from the Platonic view of "Ideal Forms".
http://en.wikipedia.org/wiki/The_Forms

Aristotle was a critic of that, and I don't think modern philosophers
think too highly of it either. In any case, it's rather impractical to
use as a basis for understanding a programming language.


Here is my (tentative) concept of value. I will give a wordy version
and leave a clear, concise definition to later, or someone else,
whichever occurs first. :)

Some builtin[1] objects have a value. A value is a "hidden" piece of
data in an object that is not directly accessible from the Python
language; access to an object's value is provided only through methods
of the object's class. The object's methods can (and usually will) make
use of the object's value when producing an object to return or changing
the object's state or value.

I see you are still insisting that value is something that objects "have"
rather than "are". I don't see that this is a useful stance to take,
except in the sense of a comparison to some sort of Platonic Ideal or
abstract concept, e.g. the object int(3) has the value of the abstract
whole number three. That's generally not very helpful: in practice, we
can assume that objects are just like the abstract values, except when
they're not.

(E.g. 1+1 in Python is just like 1+1 in pure mathematics; however
10**10**100 in Python is significantly different from 10**10**100 in pure
maths. For starters, the calculation in Python will probably take longer
than the expected lifespan of the Universe; the calculation in pure maths
takes as long as it takes the mathematician to write down "one
googolplex".)

Working around those leaky abstractions is an important part of
programming, but it doesn't help much trying to understand the principles
of a language.

It is not possible to define a class in Python that provides its objects
with a value unless that class is derived from a builtin class that
provides a value.[3]

Again, I do not believe that this is a helpful approach to take. Why
should the value (or lack thereof) of an object depend on the
implementation details of how it is created?


If this in not an inaccurate description of "value" it clears up several
points of confusion for me:
* No need to worry about what the value of object() is.
(it has no value.)

I don't believe that this is a question that needs any worry. The value
of object() is simply the instance itself.


* No need to worry about whether expressions return
values. (They don't, they always return (references to) objects.)

An expression is a symbol. It's a compound symbol, and potentially large
and complicated, but still a symbol. The term "value" has a perfectly
good definition:

That which a symbol denotes or represents.

Given the expression:

Whatever(57) if y or SomeObject(4, 5, "foo") else SomethingDifferent("x")

we can take the entire expression as a symbolic representation of a
thing. It doesn't matter whether we can determine what that thing is at
compile-time or run-time. We know that at run-time there will be such a
thing, and that thing is the value of the expression. (The sole exception
is if the expression fails to evaluate at all.)

So, if the expression does evaluate, then it has evaluates to a thing. It
represents that thing: when talking or reasoning about the thing, we can
substitute the expression for that thing. Doing so might be counter-
productive, because the expression is so long and complicated. But we can
create a *short* symbol representing the expression, say x, and now talk
about x as a short-hand for the long complicated expression. Going back
to the dictionary meaning of "value", we can say that the value of x is
whatever thing is represented by it, which is the same thing as
represented by the expression, which is whatever object the expression
evaluates to.

In other words: the value of an expression is the object that the
expression evaluates to.


* Where do values come from? (They are created/modified
by methods of builtin classes and are otherwise not directly
accessible.)

There are many things of interest which are not created/modified by
methods of built-in classes, and it would be terribly limiting to say
that they don't have values.

I might choose to implement integers as follows:

class UnaryInt:
def __init__(self, n):
if n == 0:
self.ptr = None
else:
self.ptr = UnaryInt(n-1)
def __add__(self, other):
result = UnaryInt(other)
# Find the end of the linked list.
obj = result
while obj.ptr is not None:
obj = obj.ptr
# And extend it.
obj.ptr = self.ptr
return result
__radd__ = __add__
def __str__(self):
count = 0
obj = self
while obj.ptr is not None:
count += 1
obj = obj.ptr
return "%s" % count
__repr__ = __str__


This is an incomplete class -- I haven't spent the time to implement all
the methods necessary to make it work correctly, so it is *very* easy to
break. For example, don't pass a negative integer to it. I could get that
to work too, but it would require significant effort. But for the simple
case of this demonstration, it is good enough.

According to your definition, UnaryInt(3) has no value. But I argue that
it is merely a different implementation of int(3):
7


Why should I not say that the value of UnaryInt(3) is three, just like
the value of int(3) is three? The differences are mere implementation
details.


* How can I find an object's value (if I don't believe
.str(), .repr(), etc)? Use gdb. :)

I would say the object's value is the value, so if you have the object,
you have its value.

What your question really is, how can I be sure that the string
representation of an object tells me everything I want/need to know about
the object? And the answer is, naturally, you can't.

Python has very powerful introspection tools:

type()
str(), repr()
help()
dir()
the inspect module

and probably others. If you want to know what makes a thing (a Python
object) itself instead of another, different, thing, then use them.
 
D

Derek Martin

I have yet to see any reasonable definition of a Python value in the
Python docs or elsewhere, despite the fact that a value is one of
the three defining characteristics of an object, a central concept
in Python.

Why does it need to be defined in the Python docs? Is this really
even an important question to answer? Are you unable to write correct
functional programs in Python without having it answered? I suspect
it's not an issue...

Let's assume for the moment that it is, though. The term "value"
already has a meaning... the one ascribed to it by its use in natural
language. One on-line dictionary includes this among its definitions:

magnitude; quantity; number represented by a figure, symbol, or the
like: the value of an angle; the value of x; the value of a sum.

It seems clear that this, or something extremely close to this, is
what is meant in the Python docs by the unqualified use of the term.

So, then, what is the value of a Python object? As has been alluded by
others, it is not possible to formally define or enumerate what such a
value is, in general terms, because the term "object" refers to
to a thing with neither a deterministic nor static identity; in the
abstract an object has no inherent or intrinsic value.

The best you can hope to do is define it in context. To illustrate:
In natural language and the physical world, an object has any number
of values; for example a book has a title, a topic, a weight, a
height, a length, a width, a page count, a word count, a purchase
price, a printing cost, a number of copies sold, a profit per unit
sold, etc. to the limits of your imagination regarding ways to
describe books. Which of these is its "value" depends upon the
context in which you are discussing the book. To the reader, the
value is the price he pays for the book, or perhaps some measure of
the enjoyment he derives from reading it (possibly the amount he would
be willing to pay to buy it). To the seller, the value is perhaps
best represented by the profit per unit sold. To the publisher's
shipper (think FedEx), the value might best be described in terms of
its weight...

Just as in the physical world, in Python an object can be defined such
that it evaluates to different values in different contexts, even
though its state may not have changed between those different
contexts. Therefore the value of an object is dependent upon its data
attributes AND its behaviors defined as methods, as well as the
context in which it is accessed, and is the value to which the object
evaluates in a given expression or context.

If you like, you could think of the value of an object as the set of
all possible values to which the object may evaluate in every possible
context, given a particular state of the object.

--
Derek D. Martin
http://www.pizzashack.org/
GPG Key ID: 0x81CFE75D


-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.1 (GNU/Linux)

iD8DBQFJH9NXdjdlQoHP510RAo5DAJ94IssGt8e1UTv8pNGOacSE54WUpQCfdciX
sMBDjQszo9MTQfd93D5Pavk=
=rdz7
-----END PGP SIGNATURE-----
 
S

Steven D'Aprano

The Python Lang. Ref. says:
object = identity + type + value

I believe that the language reference says that objects have an identity,
a type and state, but I'm too lazy too look it up. I'd be happy with that
definition.

You are defining objects as:
object = identity + type + (object - (identity + type)) value = object
- identity = type + (object - (identity + type))

Seems to me it is easier just to give the "object - (identity + type)"
part a name, say, "value". :)

I would call that state. Then I would say that the value of an object is
the object's state, possibly with the identity and/or type if they are
important in context.

I also question, "type is assumed from context". To me, type is very
objective: it is the set of methods and other attributes that define the
behavior of the object.

Sure. But that doesn't contradict my statement that often type can be
assumed from context, although I didn't explain myself terribly well.
What I meant was that the range of types we accept as having the same
value will depend on what we want to do with the values. That's duck-
typing: if we only care that a thing has webbed feet, then everything
else about the various waterfowl is mere decoration. The only thing of
significance is the presence or absence of webbed feet, and in principle
we are indifferent as to whether we get Goose(3) or Duck(3) or Swan(3),
or even Pelican(3). Other aspects of the object's behaviour (its type)
such as whether they honk, quack, or hiss, are irrelevant.

From a philosophical position, Goose(3) has a different value to Duck(3),
and I have no problems with saying so. But in a practical sense, if I
don't care what sort of web-footed thing I get, then everything else is a
mere red stripe, an arbitrary decoration or implementation detail.


OK, but a name is a rather abstract concept, is it not?

Not at all, it is a fundamental part of Python, analogous to variable.

Because of
Python's interpreted nature, names can't be compiled away as in C, they
need a concrete runtime existence, but does the language definition need
to assume that?

Of course. It wouldn't be Python if they didn't. However, remember that
objects don't have names.

And per innumerable previous discussions, is it not preferable to "bind
the name to an object" sidestepping any need for "value" in this
context?

Nevertheless, people will insist on asking "what's the value of x?" and
expect to get the answer 3 if they have previously executed x = 3. I
don't see that this is a problem. The name x is a symbol, and it denotes
the object 3. Where's the problem in using the term value?


I don't see how saying "the value of an object is itself" is
particularly useful. We already have a word for what an object is, it
is "object". :)

I didn't say it was very useful. As far as I'm concerned, asking what the
value of an object is is not a useful question.


The point of the word "value" is to describe, in a
general way, without defining implementation details, what you describe
as "some specific byte pattern in memory which causes that object to be
int(3) rather than some other object" and does not mix in other
bit-pattern differences, such as differences in type which are not
relevant to what we intuitively think of as "value".

Sorry, that sentence is incoherent. What I meant to write was:

"To put it another way, the value of that object is whatever properties
of the object distinguish it from anything other than the whole number 1."

This is saying something different, that the value of an object depends
on how it's type relates to some non-programming-language concept
("whole numbers" in this case) that the object attempts to model.

Try as we might, we can't entirely escape that objects are merely
modeling things in the outside world, or abstract concepts. Scrub out the
reference to "type" in your sentence, and I would agree with you: the
value of an object depends on how it relates to the thing the object
attempts to model.


The result of x==y depends solely on the behavior (methods) of x.
Nonsense.
.... def __eq__(self, other):
.... return True
....True


The methods of 5 don't even get called. This of course is a special case,
because 5 is a built-in, but in general, the result of x==y depends on
*both* x and y.

(To
be anal, the behavior of x might be to delegate calculating the result
to y).

No, that's not what x does. You *don't* need to do this:

class MyClass(object):
def __eq__(self, other):
if some_condition:
return other.__eq__(self)

x does not delegate anything to y, unless you explicitly code it like I
have above. It just happens, automatically performed by the Python VM.


That behavior (if reasonable) will take into consideration the
"value"s of x and y. This seems to imply that "value" is something more
specific than the totality of the x and y objects.

You're assuming that == compares values, which is often a safe
assumption, but not always.

class Silly:
def __eq__(self, other):
if time.localtime()[6] == 1: return True
return False

x = Silly()
y = 5

On Tuesdays, x==y returns True. Does that mean the value of x has changed
at Monday 11:59:59pm and will change again at Tuesday 11:59:59pm? I don't
think so. I think the value of x remains the same, but the behaviour
varies from time to time. I think the value of x is "a thing which claims
to be equal to everything on Tuesdays, and equal to nothing every other
day".


What you or I think is important in a calculation need not have a
bearing on an object's value.

Are you trying to say that the value of objects is independent of human
thought?

The CPython object int(3) happens to have the *exact* same representation
in memory as the string "steve is a poopy-head" in some other Python
implementation. (I can't tell you what that implementation is, but I know
it exists in principle.) The only difference between the two is that in
CPython that collection of bytes represents the whole number three, while
in the other implementation, it represents a rather childish insult. The
physical thing itself is exactly the same, but the meaning -- its value
-- depends on the interpretation.

(Have you ever read "Godel, Escher, Bach: An Eternal Golden Braid"? I
recommend it highly.)

If you think that is too hypothetical to take seriously:

http://www.ioccc.org/1986/applin.c

A single set of bytes which are legal and useful (well, not very useful)
C, Fortran 77 and Bash code.


id() does not need to consider that
identity is part of an object's value -- its programmer needed merely
use identity if that's what was needed, while it's argument goes on
having whatever value it has.

This is a red-herring. id() itself does one thing and one thing only:
return a numeric ID representing the identity of the object. The id()
function doesn't care what the object is, only what it's identity is.


[snip]
Is the value of float(1.0/3.0) the same as float(.3333333333333333)?
Mathematics says no, but Python (at least on my machine) says yes. (At
least if you accept that the "==" operation is written to compare
values.)

What you've discovered is that the abstraction "floating point numbers
represent real numbers" sometimes fails. I don't think that has any
baring on what the value of float(1.0/3.0) is. The value is "one third",
or at least as close to one third as the implementation (the abstraction)
allows.

There is nothing in the concept of value that implies that the
correspondence between the symbol and the thing itself must be exact.
Consider x = float(1.0/3.0). When talking about the name 'x' and the
thing float(1.0/3.0), the correspondence is exact: x really does denote
the float object. But when talking about the symbol float(1.0/3.0) and
the thing it represents, the abstract real number one third, the
correspondence is not exact: floats fall short in a number of ways.



[snip]
So you would say that a and b have different values below?

class My_int(int):
def __init__(self): self.foo = None
a = int(3)
b = My_int(3)

As I explained in another post, yes, with some provisos.

How can one have an objective definition of "value" if it depends on
context?

How can you not?
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,065
Latest member
OrderGreenAcreCBD

Latest Threads

Top