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

Greg Ewing (using news.cis.dfn.de) g2h5dqi002 at sneakemail.com
Thu Feb 12 04:14:47 CET 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'):

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

More information about the Python-list mailing list