A
Alan Franzoni
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(self):
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...")
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(self):
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...")