* 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.
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.