Is 'everything' a refrence or isn't it?

F

Fredrik Lundh

It (sec. 3.1, "Objects, values and types") is not what I would
call a good definition . About values it says only

- that they are something that all objects have.
- they can be mutable or immutable.

It then has a few sentences about mutability, so after reading
it you will know that, whatever a value is, it can be changed
for some objects but not others. But what exactly it is that is
being changed is still a mystery.

you really have trouble with abstract concepts, don't you?

*what* the value is is defined by the operations that the object supports (via its
type).

*how* the value is represented inside the object is completely irrelevant; a Python
implementation may use electric charges in small capacitors, piles of rocks, diapers,
or an endless supply of small guys in odd costumes to encode the value inside an
object. Changes to the value may be carried out by CPU instructions, caterpillars,
toddlers with gasmasks, or an endless supply of small guys in odd costumes. The
only thing that's important is that you can, in your Python program, access an ob-
jects value via its type, and get other objects back when you do.

</F>
 
D

Donn Cave

Not yet. The reason is that I am still trying to figure out
what a value is myself. Do all objects have values? If
not which do and which don't? What's the value of int(1)?
An object? Some otherwise unreachable thing that
represents the abstract concept of the number 1?
What the value of object()? A few weeks ago I turned
to that page for enlightenment, with the results I reported.


I have a hard time accepting that. I do not think there
is any aspect of human thought that cannot be described
by a sufficiently skilled writer.

But you're asking for more than that. We're not just talking
about how people think about value, you want a definition that's
suitable for a language reference. Whereupon you would indeed
run into the kinds of questions you pose above, and more.
Yes, see above. How can you feel confident working with
things that aren't understood? (c.f. this thead about
problems resulting from python beginner's misconceptions
about references.)

I'm saying that the definition of value doesn't contribute to
my understanding of my work. I guess we might say that the
whole point of a computer programming language is a mechanism
for the representation and manipulation of values, and our
task is to understand the mechanism enough to work with it.
That's what the language reference is for.

Donn Cave, (e-mail address removed)
 
P

Paul Rubin

Donn Cave said:
But you're asking for more than that. We're not just talking
about how people think about value, you want a definition that's
suitable for a language reference. Whereupon you would indeed
run into the kinds of questions you pose above, and more.

I know the Scheme standard includes a formal mathematical description
of the language semantics, maybe because the felt the usual verbiage
couldn't be precise enough.
 
M

Mikael Olofsson

Fredrik said:
*what* the value is is defined by the operations that the object supports (via its
type).

*how* the value is represented inside the object is completely irrelevant; a Python
implementation may use electric charges in small capacitors, piles of rocks, diapers,
or an endless supply of small guys in odd costumes to encode the value inside an
object. Changes to the value may be carried out by CPU instructions, caterpillars,
toddlers with gasmasks, or an endless supply of small guys in odd costumes. The
only thing that's important is that you can, in your Python program, access an ob-
jects value via its type, and get other objects back when you do.

+1 QOTW
 
R

rurpy

Fredrik Lundh said:
you really have trouble with abstract concepts, don't you?

Usually not when they are explained well.
*what* the value is is defined by the operations that the object supports (via its
type).

Well, that is already better than what is in the Lang Ref.
But there must be more to it than that. int(1) and int(2)
have exactly the same operations, yes? Yet their values
are different. (By "operations" you mean the set of methods
an object has?)

This interest is not just idle mental calesthenics.
I wanted to write a function that would dump the contents
of any object (value and attributes), and got rather confused
about values, types, repr's, etc.

It would help if you or someone would answer these
five questions (with something more than "yes" or "no" :)

1. Do all objects have values?
2. What is the value of object()?
3. If two objects are equal with "==", does that
mean their values are the same?
4. Are object attributes part of an object's type
or it's value, or something else? (I think the first.)
5. The (only?) way to get an object's value is to
evaluate something (a name or a "reference"(*)
that refers to the object.

(*) I did not go back through this whole thread
but I know "reference" is controversial. I am not
trying to revive that debate. I mean the word in
a very generic sense.
*how* the value is represented inside the object is completely irrelevant;
....snip...
Yes, I agree and did not intend to imply otherwise.
 
R

rurpy

Donn Cave said:
But you're asking for more than that. We're not just talking
about how people think about value, you want a definition that's
suitable for a language reference. Whereupon you would indeed
run into the kinds of questions you pose above, and more.


I'm saying that the definition of value doesn't contribute to
my understanding of my work. I guess we might say that the
whole point of a computer programming language is a mechanism
for the representation and manipulation of values, and our
task is to understand the mechanism enough to work with it.
That's what the language reference is for.

I think the difference in our perspectives is that you already
*know* what a value is, not necessarily in a way that allows
you to write a defintion, but certainly in a way that allows
to work effectively with them.

As a Python beginner, I do not know, and I need something
more than "it is something an object has". I do NOT need
eiher some formal specifcation, nor a metaphysical discussion
that relates it to platonic ideals and other such concepts.

Surely there is some middle ground?
 
D

David Murmann

Well, that is already better than what is in the Lang Ref.
But there must be more to it than that. int(1) and int(2)
have exactly the same operations, yes? Yet their values
are different. (By "operations" you mean the set of methods
an object has?)

well, yes, but the behavior of the operations of an object are
based on its value. and in python you have no other possibility
to get closer to an objects value than to look what its methods
do (in the case of an int, print it, compare it, etc.). that
means the whole concept of a value is not really necessary to be
able to write a python program.
1. Do all objects have values?
2. What is the value of object()?

i'd say these two are closely related, and i'd say yes, all objects
have values and you can't really tell what the value of an object() is.
what you can say is, that two object()s have different values, because
their behavior differs (id(object)!).

but, one could define that id() is a special case and does not
contribute to the behavior of an object, so that different int
objects that print the same really have the same value.
3. If two objects are equal with "==", does that
mean their values are the same?

no, absolutely not. think this class:

class C(object):
def __eq__(self, other):
return True
4. Are object attributes part of an object's type
or it's value, or something else? (I think the first.)

they are part of an objects operations, just a shorthand for
__getattr__ and __setattr__.
5. The (only?) way to get an object's value is to
evaluate something (a name or a "reference"(*)
that refers to the object.

there is no such way (at least not to my knowledge).
at least not in general. of course you can print an int
and "see" its value, but you could define a C extension type
which holds a whole bunch of things as its value that are
completely inaccessible from python (are they then even part
of such an objects value? i don't care, its no use to define
"value" in either way).

i hope i did not confuse more than clarify, but this is the way
i see it.

also note that i understood Fredrik's quote from above in exactly
this way, this is just meant to clarify. (so please correct me if
i'm wrong)
 
S

Steve Holden

Usually not when they are explained well.
You want to be careful - the bot will get you! Don't be rude to the bot!
Well, that is already better than what is in the Lang Ref.
But there must be more to it than that. int(1) and int(2)
have exactly the same operations, yes? Yet their values
are different. (By "operations" you mean the set of methods
an object has?)
He does. But "the value of an object" is a bit like saying "the value of
a car": a car is a complex object, with properties (number of doors, for
example, which can differ from car to car) and operations (like "start
engine", "accelerate", "brake" and so on).
This interest is not just idle mental calesthenics.
I wanted to write a function that would dump the contents
of any object (value and attributes), and got rather confused
about values, types, repr's, etc.
Well it's an ambitious project, but not an impossible one. Python has
features for "introspection", which means that programs can examine the
structure of the data rather than only dealing with values of known
structure.
It would help if you or someone would answer these
five questions (with something more than "yes" or "no" :)
Well I've been staying away from this thread, but I'll try. For
demagogic purposes I am omitting consideration of what are usually
called "classic classes". You can talk about them once you understand
the situation in more detail.

Note to nitpickers
------------------
Please note that I *am* oversimplifying here, and the nitpickers will
undoubtedly find many threadsworth of valuable material here. The point
is to develop an understanding of the *principles*. Once someone has
that they can pick up the details as they need them, which 98% of Python
users don't feel the need to. I don't even claim to know the whole
story, but I *do* know enough to explain it in principle. So by all
means correct me where I am demonstrably wring, but *please* don't just
add complexity that doesn't aid understanding.

So sit comfortably, and we'll learn about object-oriented systems.
1. Do all objects have values?

All objects have a namespace. Each item in the namespace (attribute) is
identified by (guess what) a name, and refers to a value. The value is
also an object (which is why people sometimes say "in Python everything
is an object"). You might even argue that an object is nothing *but* a
namespace with specific behaviour, though that's a somewhat extreme view.

Each object is an instance of some type, and "knows" which type it's an
instance of. (A reference to) the type is usually stored in the
instance's attribute named (for historical reasons) __class__. Once you
get really smart you'll learn that you can even the type of some objects
(the ones whose types are defined in Python rather than being built into
the interpreter) by changing the value of their __class__ attribute.

The instance's type is *also* an object, and therefore has its own
namespace. The instance (of the type) is created by calling the type,
possibly with arguments that can be used to initialise the values of
items in the instance's namespace. They can also be ignored, but there
wouldn't be much point requiring them then, would there?
2. What is the value of object()?

Well, object is a type. So calling it give you an instance of type
object. But of course you could have answered this question for yourself
in the interactive interpreter:

Pay attention here:
<object object at 0x0099C438>

No, I didn't just copy and paste the same text. I'm using the C Python
implementation, and the first time I created an instance of type object
I didn't bind it to a name. C Python keeps a count of references to all
objects, and when the reference count falls to zero it reclaims the
space. This was promptly re-used to create the second instance.

If I bind a name to a third object (which will *also* be created at the
same address) the memory won't be reused:
3. If two objects are equal with "==", does that
mean their values are the same?

Almost universally, yes, although if you know enough about how the
interpreter works "under the hood" you can define the response of
instances of your own classes to the "==" operator (by defining their
__eq__ method), and even define a class whose instances aren't equal to
anything, even to themselves!
4. Are object attributes part of an object's type
or it's value, or something else? (I think the first.)

Well, this is where things become a little more complex.

Each instance of a type has some attributes defined in its own
namespace ("instance attributes"), which are therefore unique to it.
These attributes would normally be considered collectively as the
"value" of an object if you really *must* have something that you can
call the value. The attributes of an instance are accessible only by
referencing the instance and then qualifying that reference - usually
using the dot operator, but sometimes using functions like getattr().

You can, however, also use the instance to access the attributes of its
*type*, and perhaps this is what is confusing you. Because these type
attributes can be referenced via *any* instance of the type they are
considered common to all instances of a given type. Again for historical
reasons they are commonly called "class attributes".

The normal situation is that the instance attributes are used as the
instance's value, and the class attributes are used as the methods of
each instance of the type. This is why we say the type of an instance
defines its behaviour.

When you write

foo = instance.method(arg1, arg2)

you are almost always calling a function defined inside the instance
type's class definition (though this being Python there's absolutely
nothing to stop instances having callable attributes of their own too:
we are discussing "beginners' Python" here).

Under the hood the interpreter looks for an attribute called "method" in
the instance. Failing to find it, it then looks in the instance's type.

Of course it can fail to find it there, too. If the type is defined as a
specialisation of some other type (a "subclass" of the other type -
"type2 is like type1 but with the following differences") then the
interpreter will consult the other type, and so on and so on. I am
deliberately ignoring multiple inheritance ("typeC is like typeB, and
it's also like typeA") here, but the essentials are the same. We say the
subclass "inherits" the attributes of the superclass.

If the interpreter keeps walking up the inheritance tree in this way
without finding the attribute it's looking for, it will eventually
arrive at the type "object", because ultimately every object in Python
is defined as a subclass of (a subclass of (a subclass of ...)) object.

So, when you wrote above "... int(1) and int(2) have exactly the same
operations, yes? Yet their values are different" you were correct: the
operations are defined by their type ("int"), and are shared between all
instances. Unfortunately you chose an immutable type - an int object's
value cannot be changed, and so it isn't exposed to CPython's
introspection features. It's used inside the type's methods, which are
written in C and can therefore sneakily access bits of the objects that
don't live in the Python-accessible namespace.
5. The (only?) way to get an object's value is to
evaluate something (a name or a "reference"(*)
that refers to the object.
Well, most times you don't really get "an object's value", since the
value is collectively embedded within all of its attributes, and as
we've just seen, instances of immutable types don't expose their values
directly. But it's not *incorrect* to say that, just a bit fuzzy.
(*) I did not go back through this whole thread
but I know "reference" is controversial. I am not
trying to revive that debate. I mean the word in
a very generic sense.



...snip...
Yes, I agree and did not intend to imply otherwise.
OK, so are you ready for some fun? The dir() builtin gives you access to
the names defined in an object's namespace. Let's go hunting.

This is just a convenience so we don't splurge across the page.
['__class__',
'__delattr__',
'__doc__',
'__getattribute__',
'__hash__',
'__init__',
'__new__',
'__reduce__',
'__reduce_ex__',
'__repr__',
'__setattr__',
'__str__']
These are attributes that by definition every object must have (since
when told to look for them the interpreter will keep going if necessary
until it finds them in object). We can find some information out about
them by constructing a string referring to them and evaluating that
string (it's easier than typing them by hand into the interactive
interpreter).
.... print name, ":", eval("object. %s" % name)
....
__class__ : <type 'type'>
__delattr__ : <slot wrapper '__delattr__' of 'object' objects>
__doc__ : The most base type
__getattribute__ : <slot wrapper '__getattribute__' of 'object' objects>
__hash__ : <slot wrapper '__hash__' of 'object' objects>
__init__ : <slot wrapper '__init__' of 'object' objects>
__new__ : <built-in method __new__ of type object at 0x1E1AE868>
__reduce__ : <method '__reduce__' of 'object' objects>
__reduce_ex__ : <method '__reduce_ex__' of 'object' objects>
__repr__ : <slot wrapper '__repr__' of 'object' objects>

This tells us that object's type is "type" (or as we'd say colloquially
"object is a type", just as we'd say "dict is a type"). Most of the
other attributes are methods or "slot wrappers". You can regard them as
the same for our purposes, as the difference is essentially
implementation detail. Now let's look at an *instance* of type object.
.... print name, ":", eval("b. %s" % name)
....
__class__ : <type 'object'>
__delattr__ : <method-wrapper object at 0x00AC3CF0>
__doc__ : The most base type
__getattribute__ : <method-wrapper object at 0x00AC3E90>
__hash__ : <method-wrapper object at 0x00AC3CF0>
__init__ : <method-wrapper object at 0x00AC3D10>
__new__ : <built-in method __new__ of type object at 0x1E1AE868>
__reduce__ : <built-in method __reduce__ of object object at 0x0099C438>
__reduce_ex__ : <built-in method __reduce_ex__ of object object at
0x0099C438>
__repr__ : <method-wrapper object at 0x00AC3E90>

Here you can see that the instance is actually *wrapping* it's type's
methods. Again this is an implementation detail: the point of the
wrapper is to make the C-implemented method look like a function defined
in Python, I believe - I wouldn't claim exact certainty on that.

You can see that the __new__ method is actually directly inherited from
the type (it has the same memory address), but all the other methods and
slot wrappers of the type appear to have been wrapped.

This isn't coincidental: __new__ is the only method that doesn't *need*
to be wrapped, because it's called to *create* the instance, and so it
gets passed a reference to the *type*, not the instance.

Now let's define our own type. Because "classic classes" continue to
exist, it's still necessary at present to explicitly state we want a
type. The simplest way to do this is to subclass object (because
otherwise we'd have to discuss metatypes, and your would end up
swallowing your brain). I'm just going to define one method for this type.
.... "Pretty simple object subclass"
.... def foo(self):
.... print "foo.bar:", self
........ print name, ":", eval("foo.%s" % name)
....
__class__ : <type 'type'>
__delattr__ : <slot wrapper '__delattr__' of 'object' objects>
__dict__ : {'__dict__': <attribute '__dict__' of 'foo' objects>,
'__module__': '
__main__', 'foo': <function foo at 0x00B2FCF0>, '__weakref__':
<attribute '__weakref__' of 'foo' objects>, '__doc__': 'Pretty simple
object subclass'}
__doc__ : Pretty simple object subclass
__getattribute__ : <slot wrapper '__getattribute__' of 'object' objects>
__hash__ : <slot wrapper '__hash__' of 'object' objects>
__init__ : <slot wrapper '__init__' of 'object' objects>
__module__ : __main__
__new__ : <built-in method __new__ of type object at 0x1E1AE868>
__reduce__ : <method '__reduce__' of 'object' objects>
__reduce_ex__ : <method '__reduce_ex__' of 'object' objects>
__repr__ : <slot wrapper '__repr__' of 'object' objects>
__setattr__ : <slot wrapper '__setattr__' of 'object' objects>
__str__ : <slot wrapper '__str__' of 'object' objects>

You can see what foos inherit from the "object" superclass: almost
everything; but the foo type also has a few of its own attributes:
__dict__, __weakref__, __module__, __doc__ and bar.

__dict__ is a dictionary with several keys in it: __dict__ ,
__weakref__, __module__, __doc__ and bar. Oh, those are the class
attributes that aren't inherited from the superclass!

Right, let's create a foo instance and see what that looks like.
.... print name, ":", eval("f.%s" % name)
....
__class__ : <class '__main__.foo'>
__delattr__ : <method-wrapper object at 0x00B36A10>
__dict__ : {}
__doc__ : Pretty simple object subclass
__getattribute__ : <method-wrapper object at 0x00B36A10>
__hash__ : <method-wrapper object at 0x00B369B0>
__init__ : <method-wrapper object at 0x00B36950>
__module__ : __main__
__new__ : <built-in method __new__ of type object at 0x1E1AE868>
__reduce__ : <built-in method __reduce__ of foo object at 0x00B36A30>
__reduce_ex__ : <built-in method __reduce_ex__ of foo object at 0x00B36A30>
__repr__ : <method-wrapper object at 0x00B36A50>
__setattr__ : <method-wrapper object at 0x00B36A10>
__str__ : <method-wrapper object at 0x00B369B0>
__weakref__ : None

Again you can see that the instance wraps the methods of its type (even
the ones its type inherits from type "object"). The instance also has
its own (empty) __dict__ dictionary, and a "bound method". The binding
is actually created dynamically every time the method is referenced, and
the point is to attach a reference to the instance to a reference to the
method. This instance reference is passed as the value of the first
argument (usually called "self") when the method is called.

Now let's set an attribute of f and see what changes.
.... print name, ":", eval("f.%s" % name)
....
__class__ : <class '__main__.foo'>
__delattr__ : <method-wrapper object at 0x00B36950>
__dict__ : {'attribute': 'three'}
__doc__ : Pretty simple object subclass
__getattribute__ : <method-wrapper object at 0x00B36950>
__hash__ : <method-wrapper object at 0x00B36A10>
__init__ : <method-wrapper object at 0x00B369B0>
__module__ : __main__
__new__ : <built-in method __new__ of type object at 0x1E1AE868>
__reduce__ : <built-in method __reduce__ of foo object at 0x00B36A30>
__reduce_ex__ : <built-in method __reduce_ex__ of foo object at 0x00B36A30>
__repr__ : <method-wrapper object at 0x00B36930>
__setattr__ : <method-wrapper object at 0x00B36950>
__str__ : <method-wrapper object at 0x00B36A10>
__weakref__ : None
attribute : three

Well, we can see that the new attribute is included in the result of the
dir() function. But if you look carefully you'll also see that *it's
been added to the instance's __dict__ dictionary*.

Read this over a few times and you should have a pretty good idea of
what goes where. Now get on with writing that function!

regards
Steve
 
B

Bengt Richter

Note to nitpickers
------------------
Please note that I *am* oversimplifying here, and the nitpickers will
undoubtedly find many threadsworth of valuable material here. The point
is to develop an understanding of the *principles*. Once someone has
that they can pick up the details as they need them, which 98% of Python
users don't feel the need to. I don't even claim to know the whole
story, but I *do* know enough to explain it in principle. So by all
means correct me where I am demonstrably wring, but *please* don't just
^^^^^-- spelling is "wring" ;-)
add complexity that doesn't aid understanding. [...]
When you write

foo = instance.method(arg1, arg2)

you are almost always calling a function defined inside the instance
type's class definition (though this being Python there's absolutely
nothing to stop instances having callable attributes of their own too:
we are discussing "beginners' Python" here).

Under the hood the interpreter looks for an attribute called "method" in
the instance. Failing to find it, it then looks in the instance's type.
UIAM, for new-style classes this is wrongly putting the instance attribute
lookup before the mro logic. For new-style, the interpreter goes down the
type(instance).mro() chain looking for the attribute called "method"
until it finds a "method" attribute whose value has __get__ method AND a __set__ method
(which makes it a data descriptor, and not overridable by an instance attribute). If
found, it will call the method.__get__ method with the instance as an argument. The __get__ method
then returns (normally) the bound method. If it finds "method" without __get__ and __set__ methods,
it will ignore it, except that it may revisit it if after the whole mro chain fails, and there isn't
any "method" attribute on the instance either. In that case, it will look for "method" again along the
mro, and if it has a __get__ method, it will form a bound method (this is the typical "method" attribute
in the form of a function, which has a __get__ method), or if there is no __get__ method, it will
return the value as ordinary class variable. The re-scan of mro is not literal, hopefully. I'm just
trying to express the logic. Also special shortcuts apply for methods of builtins, I believe.

Old-style classes live alongside new ones -- I suspect -- by virtue of type(someinstance) being
<type 'instance'> and type(someinstance).__getattribute__ thus implementing old-style stuff instead
of the type(someinstance).__getattribute__ of new-style instances, which inherit their __getattribute__
either from object.__getattribute__ or type.__getattribute__, or a user definition.
Of course it can fail to find it there, too. If the type is defined as a
specialisation of some other type (a "subclass" of the other type -
"type2 is like type1 but with the following differences") then the
interpreter will consult the other type, and so on and so on. I am
deliberately ignoring multiple inheritance ("typeC is like typeB, and
it's also like typeA") here, but the essentials are the same. We say the
subclass "inherits" the attributes of the superclass.

If the interpreter keeps walking up the inheritance tree in this way
without finding the attribute it's looking for, it will eventually
arrive at the type "object", because ultimately every object in Python
is defined as a subclass of (a subclass of (a subclass of ...)) object.
Unless the attribute access started on a type, in which case it will check
for type.method before object.method, UIAM. BTW, in order to find either
kind of attribute, there will first be a search for type(instance).__getattribute__,
which is found as object.__getattribute__ or type.__getattribute__ unless overridden
(or instance is of an old-style class as mentioned above).
I suspect these then implement the check for __getattr__, which can be user defined
to intercept attribute access on particular objects in the search chain, after
higher-priority stuff fails.

[... Can't ... keep .. eyes ... open ... for ... rest ...]
(not the fault of your prose, had a beer ;-)

Regards,
Bengt Richter
 
B

Bryan Olson

The reason is that I am still trying to figure out
what a value is myself. Do all objects have values?
Yes.

If
not which do and which don't? What's the value of int(1)?
An object? Some otherwise unreachable thing that
represents the abstract concept of the number 1?

The value is the integer one. Python's 'int' is an abstract
data type. It's values are the integers.
What the value of object()? A few weeks ago I turned
to that page for enlightenment, with the results I reported.

I think type 'object' has only one value, so that's it.
 
M

Mike Meyer

Bryan Olson said:

Can you justify this, other than by quoting the manual whose problems
caused this question to be raised in the first place?

I think type 'object' has only one value, so that's it.

In that case, they should all be equal, right?
False

Looks like they have different values to me.

Or maybe an object is valueless, in spite of what the manual says.

<mike
 
B

Bryan Olson

Mike said:
Can you justify this, other than by quoting the manual whose problems
caused this question to be raised in the first place?

The Python manual's claim there is solidly grounded. The logic
of 'types' is reasonably well-defined in the discipline. Each
instance of a type takes exactly one element from the type's
set of values (at least at a particular time).

In that case, they should all be equal, right?

False

Looks like they have different values to me.

Whether the '==' operation conforms to your idea of what equality
means is unclear. Maybe I was wrong, and the object's identity
is part of its abstract state.
Or maybe an object is valueless, in spite of what the manual says.

We know that's not true.
 
S

Sybren Stuvel

Mike Meyer enlightened us with:
In that case, they should all be equal, right?

False

You compare instances of the type 'object'. They both have one value:
<object object at 0xb7ddb440>

So the claim "type 'object' has only one value" is true. It's just not
the same value for all instances.

Sybren
 
F

Fredrik Lundh

Sybren said:
Mike Meyer enlightened us with:

You compare instances of the type 'object'. They both have one value:

<object object at 0xb7ddb440>

So the claim "type 'object' has only one value" is true. It's just not
the same value for all instances.

You're comparing identities, not values. The value is the set of things that
you can access via an object's methods (via the type). The identity is not,
in itself, a part of the value.

Python doesn't query the object to determine it's type or identity, but it
always has to query the object to access the value.

A look at the C implementation of a typical object might help:

typedef struct {
int ob_refcnt;
struct _typeobject *ob_type; /* type */
... an unknown amount of stuff used to represent the value ...
} MyObject;

In CPython, the MyObject* pointer is the identity. The ob_refcnt field is a
CPython implementation detail. The ob_type field contains the type. The
rest of the structure is known only by the MyObject type implementation.

</F>
 
D

Donn Cave

....
I think the difference in our perspectives is that you already
*know* what a value is, not necessarily in a way that allows
you to write a defintion, but certainly in a way that allows
to work effectively with them.

As a Python beginner, I do not know, and I need something
more than "it is something an object has". I do NOT need
eiher some formal specifcation, nor a metaphysical discussion
that relates it to platonic ideals and other such concepts.

Surely there is some middle ground?

Well, see what you make of Steve Holden and Bengt Richter's
answers, and let us know if 1) it answers your question and
2) you can distill your new insight into a dozen words or so
for the language reference.

I'm still inclined to dispute the premise. Your example
where you demonstrate the problem:
I wanted to write a function that would dump the contents
of any object (value and attributes), and got rather confused
about values, types, repr's, etc.

In the light of the answers you're getting, you may be thinking
that this isn't a simple problem. It isn't, in principle, it's
a huge bucket of worms. But if you have a practical focus that
comes out of your actual application for this function, it could
be pretty trivial. Your choice, and likewise for the notion of
value in general.

Donn Cave, (e-mail address removed)
 
B

Bryan Olson

Sybren said:
Mike Meyer enlightened us with:



You compare instances of the type 'object'. They both have one value:



<object object at 0xb7ddb440>

So the claim "type 'object' has only one value" is true. It's just not
the same value for all instances.

No, that's not the issue. A type has a set of values (and a set of
operations); each instance takes one value from the type's set. I
think (I'm not sure) that object's set of values has only one element.

In Python, types are extensible, so by 'instance', I mean a direct
instance, not an instance of a class that inherits from 'object'.


Would it make sense to have a type with an empty set of values?
Sure. Such a type could never have a direct instance. Perhaps
'object' should be an abstract base class.
 
S

Steven D'Aprano

It would help if you or someone would answer these
five questions (with something more than "yes" or "no" :)

1. Do all objects have values?

All objects ARE values. Some values themselves are complex objects
which in turn contain other values, e.g. if I execute:

L = [None, 1, "hello"]

I have created a name 'L' which is bound to ("has the value of") a list
with three items. The first item has the value of ("is the object") None,
the second has the value of ("is the object") 1, and the third is the
string "hello".

2. What is the value of object()?

These seems complicated because we are using the same word ("object") for
both the generic programming term, the class (strictly type, although the
difference is not important), and the instance itself.

Let's make it less confusing by using a case where the three things are
different:

class Foo:
pass

Foo is a class. Classes are (generic programming term) objects.
Foo() returns an instance of the Foo class. Instances are (generic
programming term) objects.

The value of Foo() is the instance. Why? int(data) returns an instance of
int, and str(data) returns an instance of str. It makes sense to say that
the value of the int instance 1 is one, the value of str instance "abc" is
the string "abc", and so forth. So we'd like to talk the same way about
more complex objects: the value of an instance is itself.

Hence the value of Foo() is the Foo instance at some particular memory
location. In this specific case, Foo() creates an object with very little
behaviour and and no distinguishing characteristics except their location
in memory, where as ints like 1 2 and 7 are easily distinguished.

Now let's return to (non-generic) object(). object is (as well as the
generic programming term) a class (strictly type, but the difference is
unimportant). object() returns an instance of class object:
<object object at 0xf705e3b8>

So the value of object() is some particular instance (of type object).


3. If two objects are equal with "==", does that
mean their values are the same?

Intuitively yes, but not necessarily:
True

(We want the float 3.0 to be equal to the int 3, but we can distinguish
between them by something more than their location in memory.)

You can define a custom class:

class EqualAll:
def __eq__(self, other):
return True

but that's a pathological case.


4. Are object attributes part of an object's type
or it's value, or something else? (I think the first.)

The type/class defines what attributes (generic) objects have. The value
of the attribute lives with the instance itself (that's why fred.attribute
and barney.attribute can be different). Whether you want to say the
attribute itself is part of the class or part of the instance value is, in
my opinion, not a useful question. The answer depends on which way you
want to look at it.


5. The (only?) way to get an object's value is to
evaluate something (a name or a "reference"(*)
that refers to the object.

I can't think of any other way to get at an object except by accessing
that object, or even what it would mean if there was such a way.
 
D

Donn Cave

Quoth Steven D'Aprano <[email protected]>:
| On Thu, 12 Jan 2006 16:11:53 -0800, rurpy wrote:
|> It would help if you or someone would answer these
|> five questions (with something more than "yes" or "no" :)
|>
|> 1. Do all objects have values?
....
|> 2. What is the value of object()?

[ I assume you mean, the object returned by object(). ]

It doesn't really have a value. I can't think of any kind of
computation that could use this object directly.

|> 3. If two objects are equal with "==", does that
|> mean their values are the same?

Yes.

| >>> 3.0 == 3
| True

Evidently the value of 3.0 is the same as the value of 3.

|> 4. Are object attributes part of an object's type
|> or it's value, or something else? (I think the first.)
|
| The type/class defines what attributes (generic) objects have. The value
| of the attribute lives with the instance itself (that's why fred.attribute
| and barney.attribute can be different).

I think to be strictly accurate, attributes and their values may reside
in a class instance, or in (one of) its class(es.) In the most common
case, functions will be in the class and data will be in the instance,
but every variation on this is reasonably common.

| ... Whether you want to say the
| attribute itself is part of the class or part of the instance value is, in
| my opinion, not a useful question. The answer depends on which way you
| want to look at it.

For a given class and instance, it can be more obvious. Take the object
returned by object(), which has attributes like '__reduce__' - all those
attributes may reasonably be considered "type" and not "value".

On the other hand, there are no constraints on how you may use these
namespaces. You can use an instance, or a class, like you would use
a dictionary object, and then it's all value.

Donn Cave, (e-mail address removed)
 
S

Steven D'Aprano

Quoth Steven D'Aprano <[email protected]>:
| On Thu, 12 Jan 2006 16:11:53 -0800, rurpy wrote:
|> It would help if you or someone would answer these
|> five questions (with something more than "yes" or "no" :)
|>
|> 1. Do all objects have values?
...
|> 2. What is the value of object()?

[ I assume you mean, the object returned by object(). ]

It doesn't really have a value. I can't think of any kind of
computation that could use this object directly.

Here is one:

obj_inst = object()

def computation(data):
global obj_inst
if data is obj_inst:
print FirstOneThousandPrimes()
else:
print TextOfWarAndPeace()


It isn't a particularly useful computation, but it is a computation.


|> 3. If two objects are equal with "==", does that
|> mean their values are the same?

Yes.

| >>> 3.0 == 3
| True

Evidently the value of 3.0 is the same as the value of 3.
Okay.
False

Evidently the value of three is not the same as the value of three.

Let's try not to be too deep here, okay? Before asking "what is the value
of foo?", we have to agree on what we mean by "value". It is easy to tie
yourself into knots here.

|> 4. Are object attributes part of an object's type
|> or it's value, or something else? (I think the first.)
|
| The type/class defines what attributes (generic) objects have. The value
| of the attribute lives with the instance itself (that's why fred.attribute
| and barney.attribute can be different).

I think to be strictly accurate, attributes and their values may reside
in a class instance, or in (one of) its class(es.)

When you call instance.attribute, attribute may be either a class
attribute or an instance attribute. If it is a class attribute, it belongs
to the class, not the instance, even if you access it through the
attribute.

In the most common
case, functions will be in the class and data will be in the instance,
but every variation on this is reasonably common.


| ... Whether you want to say the
| attribute itself is part of the class or part of the instance value is, in
| my opinion, not a useful question. The answer depends on which way you
| want to look at it.

For a given class and instance, it can be more obvious. Take the object
returned by object(), which has attributes like '__reduce__' - all those
attributes may reasonably be considered "type" and not "value".

I don't see that "value" or "type" are opposite, I see that they are
orthogonal. The type of 1 is int, the value of 1 is integer one. The
type of object() is object, the value is itself. The type of
object().__reduce__ is method, and the value of object().__reduce__ is
the particular (generic) object bound to the name __reduce__ in the class
object namespace. That method is a class attribute, and so it part of the
value of object().


Am I the only one that wishes that object() had been given another name,
so it would be easier to talk about the generic programming concept object
and the specific Python new-style class object without confusion?
 
B

Bryan Olson

Fredrik said:
You're comparing identities, not values. The value is the set of things that
you can access via an object's methods (via the type).

Which does make '==' kind of weird. It may or may not refer to
a method of the object.
The identity is not,
in itself, a part of the value.

Python doesn't query the object to determine it's type or identity, but it
always has to query the object to access the value.
>
A look at the C implementation of a typical object might help:

typedef struct {
int ob_refcnt;
struct _typeobject *ob_type; /* type */
... an unknown amount of stuff used to represent the value ...
} MyObject;

In CPython, the MyObject* pointer is the identity. The ob_refcnt field is a
CPython implementation detail. The ob_type field contains the type.

So, was it an editing error when you said that Python does not
query the object to determine its type? The type is there in the
object, and and in Python, variables and references are not typed.
 

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

Forum statistics

Threads
473,764
Messages
2,569,566
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top