[OPINION] - does language really matter if they all do the samething?

Greg Ewing (using news.cis.dfn.de) g2h5dqi002 at sneakemail.com
Wed Feb 11 22:14:47 EST 2004


Dietrich Epp wrote:
> In Objective C, I can create an object which doesn't respond to some 
> message "foo".  However, if I send "foo" to the object, it gets a chance 
> to respond.  In Python, there is no concept of messages.  You would have 
> to override the function that gets an object's attribute and create a 
> function for it to return.  You can capture function calls, but 
> capturing method calls is a two-step process in Python which requires a 
> little bit of magic to implement.

It's slightly more convoluted, but not all that bad:

   class Foo(object):

     def __getattr__(self, name):
       def f(*args, **kwds):
         return self.message_not_understood(name, *args, **kwds)
       return f

     def message_not_understood(self, name, *args, **kwds):
       # Do whatever you want here
       print self, "does not understand", name, args, kwds

If you use this a lot, you can put it in a small mixin class for
incorporating in your other classes. (That's something you couldn't
do in Smalltalk, btw -- multiple inheritance!)

> In Objective C:
> 
> - (void)forwardInvocation:(NSInvocation *)invocation
> {
>   if ([someOtherObject respondsToSelector:[invocation selector]])
>     [invocation invokeWithTarget:someOtherObject];
>   else
>     [self doesNotRecognizeSelector:[invocation selector]];
> }
> 
> In Python:
> 
> def __getattr__(self, name):
>     try:
>         return super(this_class, self).__getattr__(name)
>     except AttributeError:
>         try:
>             method = super(this_class, 
> self).some_other_object.__getattr(name)
>             if iscallable(method):
>                 return method
>         except:
>             pass
>         raise

Here you're thinking in terms of the Objective-C way of doing things
and trying to translate them too literally into Python. It's actually
much EASIER to do delegation in Python:

   def __getattr__(self, name):
     return getattr(some_other_object, name)

That's all you need!

> In Python you have to be careful because this won't normally capture 
> just method calls, but all attribute accesses.

Well, if that's a concern when delegating, you'll need to do a bit of
filtering in the __getattr__. But in many cases it's a feature -- you
can easily create a proxy that transparently wraps the whole interface
of another object, including both its attributes and methods.


> In a typical Objective-C 
> application you'll probably see a lot of places where the program sends 
> a message to an object only if the object responds to that message.  
> Let's compare.
> 
> In Objective C:
> 
> - (void)resetToDefaultSettings
> {
>   if ([delegate respondsToSelector:@selector(defaultSettingsFor:)])
>     [self setSettings:[delegate defaultSettingsFor:self]];
>   else
>     [self setSettings:someFallbackValue];
> }
> 
> In Python, first try:
> 
> def reset_settings(self):
>     try:
>         self.set_settings(self.delegate.default_settings(self))
>     except AttributeError:
>         self.set_settings(some_fallback_value)
> 
> But wait!  What if there is an error in self.delegate.default_settings() 
> which raises an AttributeError? 

I'd actually translate the Objective-C rather more literally in
this case:

   if hasattr(self.delegate, 'default_settings'):
     self.set_settings(self.delegate.default_settings(self))
   else:
     self.set_settings(some_fallback_value)

It might be a whisker slower, but doesn't suffer from the "catching the
wrong exception" problem, and (I think) is easier to read as well.

-- 
Greg Ewing, Computer Science Dept,
University of Canterbury,	
Christchurch, New Zealand
http://www.cosc.canterbury.ac.nz/~greg




More information about the Python-list mailing list