Velocity Reviews

Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   Python (http://www.velocityreviews.com/forums/f43-python.html)
-   -   Behaviour-based interface/protocol implementation? (http://www.velocityreviews.com/forums/t742495-behaviour-based-interface-protocol-implementation.html)

Alan Franzoni 01-24-2011 10:13 AM

Behaviour-based interface/protocol implementation?
 
Hello,
I'd like to have a system which lets me do certain actions if the
duck-type of a certain objects matches what I expect, i.e. I'd like to
have a formalization of what it's sometimes done through getattr()
calls:

if getattr(myobj, "somemethod", None) is not None:
myobj.somemethod(somevalue)


The above approach is sometimes too naive, because a) clutters code
with many getattr calls and ifs b) I might want to check for multiple
attributes and c) only checks for the method name and not for the
method's signature.

After looking at PyProtocols, zope.interface and python's own abc
module, I'm left with a doubt: does any behaviour-based "interface
testing" system exist for Python?


I mean:
all these three libraries use a register-based or inheritance-based
approach; in abc, if I want instances of a class of mine "FooClass" to
be "BarInterface" instances, I can either a) inherit from BarInterface
or b) run "BarInterface.register(FooClass)".

This poses some issues in a purely duck-typed context, IMHO. If an
object perfectly satisfies the "BarInterface" signature, but it
doesn't inherit from MyInterface and its class wasn't registered as a
BarInterface implementor, the check "isinstance(myobj, BarInterface)"
will yield a False result.

This might not be a big deal if a) python >= 2.6 is used b) just
checking for builtin interfaces - e.g. those defined in the
"collections" module is required and c) you just require checking on
basic types or on python builtin types (which correctly register
builtin ABCs).

What happens if I define my own ABC for my own purpose? There might be
builtin objects, or third party libraries, which already offer objects
that satisfy such interface, but I'd need to import such modules and
register such classes as implementing my ABC, which is suboptimal.

What I'd like to do is:

class MyType(object):
def someMethod(self, a, b):
pass

def otherMethod(self):
pass

class OtherType(object):
def someMethod(self):
pass

def otherMethod(self):
pass


@DuckType
class MyDuckType(object):
def someMethod(self, a, b):
pass

def otherMethod(self):
pass

class TestDuckTypes(TestCase):
def test_mytype_is_compatible_with_ducktype(self):
myobj = MyType()
self.assertEquals(True, MyDuckType.maybe_implemented_by(myobj))

def test_othertype_is_not_compatible_with_ducktype(sel f):
myobj = OtherType()
self.assertEquals(False, MyDuckType.maybe_implemented_by(myobj))




I'd like to do a kind of runtime-check for signatures. Of course there
couldn't be an absolute certainty of interface implementation, because
a runtime dynamic proxy method (accepting *args and **kwargs in its
signature, as an example) might just fool my signature check.

So, my questions are:

a) does anything like that already exist in the python ecosystem?
b) can anybody see any flaw either in what I'd like to do ("you
shouldn't do that because...") or in the way I want to do it ("It
won't work because...")



--
Alan Franzoni
--
contact me at public@[mysurname].eu

Carl Banks 01-27-2011 09:30 PM

Re: Behaviour-based interface/protocol implementation?
 
On Jan 24, 2:13*am, Alan Franzoni <mail...@franzoni.eu> wrote:
> Hello,
> I'd like to have a system which lets me do certain actions if the
> duck-type of a certain objects matches what I expect, i.e. I'd like to
> have a formalization of what it's sometimes done through getattr()
> calls:
>
> if getattr(myobj, "somemethod", None) is not None:
> * * myobj.somemethod(somevalue)
>
> The above approach is sometimes too naive, because a) clutters code
> with many getattr calls and ifs b) I might want to check for multiple
> attributes and c) only checks for the method name and not for the
> method's signature.


Write some kind of signature proxy to do it.

class SomeSignature(object):
def __init__(self,target):
self.target = target
def somemethod(self,value):
if hasattr(self.target,"somemethod"):
self.target.somemethod(value)

SomeSignature(myobj).somemethod(somevalue)

Generalizing the proxy to easily accommodate all kinds of signatures
to your heart's delight left as an exercise (and it's likley to
involve metaclass programming).

> After looking at PyProtocols, zope.interface and python's own abc
> module, I'm left with a doubt: does any behaviour-based "interface
> testing" system exist for Python?


Based on this thread, you have quite specific requirements, so it's
doubtful someone else has implemented exactly what you want.


And because it hasn't been mentioned in this thread yet--surprisingly--
many people in Python prefer the EAFP strategy, "Easier to Ask
Forgiveness than Permission", that is, to just do it and handle the
resulting exception:

try:
myobj.somemethod(somevalue)
except AttributeError:
# doesn't fit signature, so do nothing
pass

Personally, I have my doubts about the method in general. It's
definitely preferrable in many cases (like opening a file, where it
avoids a race condition) but for something like this I don't see it
working out too well. But I'm just throwing it out there.


Carl Banks

Alan Franzoni 01-27-2011 10:23 PM

Re: Behaviour-based interface/protocol implementation?
 
On Thu, Jan 27, 2011 at 10:30 PM, Carl Banks <pavlovevidence@gmail.com> wrote:
> Write some kind of signature proxy to do it.


I don't have a specific implementation idea yet, I see how that grows.

> Based on this thread, you have quite specific requirements, so it's
> doubtful someone else has implemented exactly what you want.


Yes, but asking is better than blinding reimplementing :-)

> And because it hasn't been mentioned in this thread yet--surprisingly--
> many people in Python prefer the EAFP strategy, "Easier to Ask
> Forgiveness than Permission", that is, to just do it and handle the
> resulting exception:
>
> try:
> * *myobj.somemethod(somevalue)
> except AttributeError:
> * *# doesn't fit signature, so do nothing
> * *pass


Sure. That's an approach. But this has drawbacks.

- it violates the CQS principle:
http://en.wikipedia.org/wiki/Command-query_separation

- Maybe my interface has not just a single method, and I might want to
call multiple methods on my object. I need to check for all signatures
before proceeding.

- When calling the method, if an exception is raised - either
AttributeError or TypeError most of the times - it could not be
generated from my own call, but from a call deeper into the stack;
It's easy to just think "that object doesn't support that interface" I
could mistake an object for not supporting an interface, and I could
silently swallow a true runtime exception instead. Maybe some stack
analysis could be performed, but I'd prefer to check as much as I can
*before* calling.

- Sometimes I'd like to group objects depending on their *behaviour*
(not their type), and then feed them somewhere else without actually
calling their methods. If I can know their behaviour just after
they've been called, it might be just too late.


--
Alan Franzoni
--
contact me at public@[mysurname].eu


All times are GMT. The time now is 05:03 AM.

Powered by vBulletin®. Copyright ©2000 - 2014, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.