[Baypiggies] Trivial OOP pattern problem

Brian Palmer bpalmer at gmail.com
Fri Jun 15 09:14:42 CEST 2012


Well,  I think your approach would lead to better replability (e.g.,
dir()), and be more efficient. I don't like the special-casing of None,
though; it'd be better to have a list of methods not to override the return
value of, probably, so that the default is to support chaining. The simple
__getattr__ every time approach has the benefit of being simple; although
perhaps it'd be worthwhile to also do   setattr(self, obj, myf) before
returning myf.

By the way, does inspect.isbuiltin  work for your decorator? I can't get
pycairo to build, but it's possible you should be checking isinstance(foo,
(types.MethodType, types.FunctionType, types.BuiltinFunctionType,
types.BuiltinMethodType))

(And of course that doesn't handle classes that are themselves callable).


On Fri, Jun 15, 2012 at 12:04 AM, David Ginsburg <dav9dg at gmail.com> wrote:

> Sorry for all the messages, but what I was doing was overkill.
> After re-reading Brian's message I suppose you could just do this:
>
> def __getattr__(self, name):
>     def myf(*args, **kwargs):
>       to_return = getattr(self.ctx, name)(*args, **kwargs)
>       if to_return is None:
>         to_return = self
>       return to_return
>     return myf
>
> cheers,
> David
>
>
> On Fri, Jun 15, 2012 at 12:01 AM, David Ginsburg <dav9dg at gmail.com> wrote:
>
>> Hmm, so I just tried to actually run this and for some
>> reason inspect.getmembers(cairo.Context, predicate=inspect.ismethod)
>> returns an empty list.
>>
>> Here's my ugly workaround:
>>
>> def make_chainable_context(cls):
>>
>>     def return_self_decorator(func):
>>
>>         def wrapper(self, *args, **kwargs):
>>             to_return = func(self, *args, **kwargs)
>>             if to_return is None:
>>                 to_return = self
>>             return to_return
>>         return wrapper
>>
>>     #for method_name, method in inspect.getmembers(cairo.Context,
>> predicate=inspect.ismethod):
>>     for method_name, method in inspect.getmembers(cairo.Context):
>>         if not method_name.startswith('__'):
>>             setattr(cls, method_name, return_self_decorator(method))
>>      return cls
>>
>> Pretty sure this accomplishes what you wanted :).
>>
>> cheers,
>> David
>>
>> On Thu, Jun 14, 2012 at 11:56 PM, David Ginsburg <dav9dg at gmail.com>wrote:
>>
>>> Hello,
>>> The problem with this is if a method needs to return a value other than
>>> self, you break it.
>>> This is probably hacky, but you could accomplish what you want doing the
>>> following:
>>>
>>> import inspect
>>> import functools
>>>
>>> def make_chainable_context(cls):
>>>
>>>     def return_self_decorator(func):
>>>
>>>         def wrapper(self, *args, **kwargs):
>>>             to_return = func(self, *args, **kwargs)
>>>             if to_return is None:
>>>                 to_return = self
>>>             return to_return
>>>         return wrapper
>>>
>>>     for method_name, method in inspect.getmembers(cairo.Context,
>>> predicate=inspect.ismethod):
>>>         setattr(cls, method_name, return_self_decorator(method))
>>>     return cls
>>>
>>>
>>> @make_chainable_context
>>> class ChainableContext(cairo.Context):
>>>     pass
>>>
>>> This way methods that return something other than None are not broken.
>>>
>>> cheers,
>>> David
>>>
>>> On Thu, Jun 14, 2012 at 11:28 PM, Brian Palmer <bpalmer at gmail.com>wrote:
>>>
>>>> On Thu, Jun 14, 2012 at 10:52 PM, Ian Zimmerman <itz at buug.org> wrote:
>>>>
>>>>>
>>>>> Isaac> Hi, Why do you need each of the methods to return the instance?
>>>>> Isaac> Can you just wrap the method calls in a function and return the
>>>>> Isaac> instance?
>>>>>
>>>>> I am not married to the idea of a wrapper class, but I don't understand
>>>>> what you propose instead.  What would the example code look like under
>>>>> your scheme?
>>>>>
>>>>
>>>> Your initial solution seems like it'd work:
>>>> class Wrap(object):
>>>>   def __init__(self, ctx):
>>>>     self.ctx = ctx
>>>>
>>>>   def __getattr__(self, name):
>>>>     def myf(*args, **kwargs):
>>>>       getattr(self.ctx, name)(*args, **kwargs)
>>>>       return self
>>>>     return myf
>>>>
>>>> There are benefits to being less dynamic, but this might be good enough.
>>>>
>>>> _______________________________________________
>>>> Baypiggies mailing list
>>>> Baypiggies at python.org
>>>> To change your subscription options or unsubscribe:
>>>> http://mail.python.org/mailman/listinfo/baypiggies
>>>>
>>>
>>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/baypiggies/attachments/20120615/f496c5c1/attachment.html>


More information about the Baypiggies mailing list