On Sat, 15 Nov 2008 11:17:07 -0800, rurpy wrote: >>> * 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") >>> * Do all objects have values? (Ignore the Python >>> docs if necessary.) >> >> 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. 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. >> 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. What classes do you think have no values? [snip] >>> * 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. > > 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). >>> * 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). > > I now think this answer is yes. 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. > > 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 + 1 4 >>> n + 1 -2 >>> n 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. >>> * Can one completely hide an object's value by >>> overriding methods? >> >> You tell me ;-) > > 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: >>> n + 1.0 -2.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. 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): >>> n = UnaryInt(3) >>> n + 4 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. -- Steven -- http://mail.python.org/mailman/listinfo/python-list