What's better about Ruby than Python?
Alex Martelli
aleax at aleax.it
Thu Aug 21 06:53:18 EDT 2003
Andrew Dalke wrote:
> Alex Martell:
>> ... def __get__(self, obj, cls):
>> ... self.obj = obj
>> ... return self.cached_call
>
> That's the part where I still lack understanding.
>
> class Spam:
> def f(self):
> pass
> f = CachedCall(f)
That's an oldstyle class -- use a newstyle one for smoothest
and most reliable behavior of descriptors
>
> obj = Spam()
> obj.f()
>
> Under old-style Python
> obj.f is the same as getattr(obj, "f")
This equivalence holds today as well -- the getattr
builtin has identical semantics to direct member access.
> which fails to find 'f' in the instance __dict__
> so looks for 'f' in the class, and finds it
> This is not a Python function, so it does not
> get bound to self. It's simply returned.
>
> obj.f() takes that object and calls it. In my original
> code (not shown) I tried implementing a __call__
> which did get called, but without the instance self.
Sure.
> Under new-style Python
> obj.f is the same as getattr(obj, "f")
Yes.
> which fails to find 'f' in the instance __dict__ so
> looks for 'f' in the class, and finds the CachedCall.
Sure.
> Python checks if the object implements __get__,
> in which case it's called a descriptor. If so, it's
Exactly.
> called with the 'obj' as the first parameter. The
> return value of this call is used as the value for
> the attribute.
>
> Is that right?
Yes! So what is it that you say you don't get?
>> should closely mimic your semantics, including ignoring
>> what I call obj and you call self in determining whether
>> a certain set of argumens is cached.
>
> Why should obj make a difference? There's only
> one CachedCall per method per .... Ahh, because it's
> in the class def, not the instance. Adding support for
> that using a weak dict is easy.
If obj is such that it can be used as a key into a dict
(weak or otherwise), sure. Many class instances of some
interest can't -- and if they can you may not like the
result. COnsider e.g.
class Justanyclass:
def __init__(self, x): self.x = x
def compute(self, y): return self.x + y
pretty dangerous to cache THIS compute method -- because,
as a good instance method should!, it depends crucially
on the STATE of the specific instance you call it on.
> Yeah, and my approach won't work with kwargs nor any
> other unhashable element. Since I didn't know what the
> Lisp code did nor how Lisp handles unhashable elements,
> I decided just to implement the essential idea.
An automatically cachable method on general objects is
quite tricky. I don't think the Lisp code did anything
to deal with that trickiness, though, so you're right
that your code is equivalent. Anyway, I just wanted to
show how the descriptor concept lets you use a class,
rather than a function, when you want to -- indeed any
function now has a __get__ method, replacing (while
keeping the semantics of) the old black magic.
Alex
More information about the Python-list
mailing list