determining context of getattr

Tripp Lilley tlilley at perspex.com
Mon Aug 21 04:48:21 EDT 2000


On Mon, 21 Aug 2000, Thomas Wouters wrote:

> > can foo's __getattr__ know that whatever it returns for 'say' is going
> > to immediately be __call__'ed?
> 
> Short answer: No. Long answer: No :) Very long answer: No, unless you use
> bytecodehacks, and don't expect the code to work properly on anything but
> the Python you wrote it on, and don't expect it to work in all situations,
> and don't care about Pythonic code. So, in short, don't bother.

I figured as much (ie: bytecodehacks, looking at the stack, etc.). I
accept the "don't bother" conclusion, as what I have works :)


>     x = foo.value
>     print x
>     print x + 9
>     print x()
> 
> In 'normal' Python, this would work exactly the same. (In fact, this is the
> same as what your example would do, except that 'x' wouldn't be a variable,
> but an item on the stack.) Not to mention:
> 
>     print (foo.value + 9)()

Actually, in my current implementation, when I do the last example, I get:

	TypeError: call of non-function (type int)


foo.value returns an object of class is selfish._slot_readwrite, which
(trivialized) looks like this:

	class _slot_readwrite:
		def __init__ (self, value):
			self.value = value
		def __call__ (self):
			return self.value
		def __repr__ (self):
			return "selfish._slot_readwrite(%s)" % self.value
		def __str__ (self):
			return str( self.value )

There are lots of other operator overloads, but those don't seem germaine.

How are you getting the "print (foo.value + 9)()" to work? Actually, I
guess I should have mentioned my coercion operator, which prefers to
coerce down to primitive types when it can... (actually, it defers to the
system coerce, like: coerce( self. value, other ) ).


Actually, my "ultimate" goal is for these classes to "appear" as much like
the primitives as possible. The idea, in a nutshell, is that all slot
accesses (message passes) work "the same", regardless of whether or not
the slot is a method or a value. Thus:

	print o.myval + o.yourval

might be two integers, or it might be two lengthy database queries, but it
really doesn't matter, because you just want to add the results... And you
don't care if the nature of either of those changes midstream, either. 
That is, say o.myval went off and computed something lengthy, then no
longer needed to do that computation. o.myval replaces itself with the
computed value, and is never "called" again, but o.myval continues to
return the cached result:

	def replacer (self):
		self.replacer = 42 * 69 + 33 / 3.14159
		return self.replacer
	o.replacer = replacer	## invokes some new.instancemethod magic


now, the first call to o.replacer does three things:
	- it computes the result
	- it replaces the slot with the computed result
	- it returns the result

subsequent calls to o.replacer simply return the result directly, without
passing go.

Of course, none of this makes any sense if you think in terms of classes,
but being a Prototype-head, I think in terms of objects, not classes :)
Thus the idea of "replacing" an instance's method with its cached result
makes perfect sense to me :)


> > I vaguely recall hearing something about Py3k making primitive types
> > into real, first-class objects that I might subclass to effect this
> > behaviour. Any truth to that recollection of mine? ie:
> > 
> > 	class TrippInt (int):
> > 		def __call__ (self):
> > 			return self.__value__
> 
> Yes, that's high on the wishlist of Py3K, though syntax may vary.

Cool.

-- 
   Tripp Lilley  *  tripp at perspex.com  *  http://stargate.sg505.net/~tlilley/
------------------------------------------------------------------------------
   "Viral marketing is not going to save mediocre businesses from extinction.
   It is the scourge of the stupid and the slow, because it only rewards
   companies that offer great service and have the strength to allow and
   even encourage their customers to publicly pass judgment on that service
   every single day."

   - Clay Shirky, Business 2.0, "The Toughest Virus of All"





More information about the Python-list mailing list