[Python-3000] iostack and Oh Oh
Steven Bethard
steven.bethard at gmail.com
Sat Dec 9 18:11:32 CET 2006
On 12/9/06, Josiah Carlson <jcarlson at uci.edu> wrote:
>
> I'd prefer to see...
>
> class MyMapping:
> @implements(mapping)
> def __getitem__(self, key):
> ...
>
> @implements(mapping)
> def __len__(self):
> ...
>
[snip]
>
> P.S. Here's a 10 minute implementation of the above semantics that is
> *almost* backwards compatible with Python 2.3 (except for the decorator
> thing, which Python 2.3 has to do without).
>
>
> _type = type
>
> def make_interface(name, methods):
> return _type(name, (object,),
> dict([(nam, object()) for nam in methods]))
>
> mapping = make_interface('mapping', mapping_methods)
> sequence = make_interface('sequence', sequence_methods)
> #...
>
> _supports = {}
>
> def supports(cls, interface):
> if interface in _supports:
> return cls in _supports[interface]
> return False
>
> def implements(*interfaces):
> def foo(fcn):
> return implements_wrapper(fcn, interfaces)
> return foo
>
> class implements_wrapper(object):
> __slots__ = ['fcn', 'interfaces']
> def __init__(self, fcn, interfaces):
> self.fcn = fcn
> self.interfaces = interfaces
> def __call__(self):
> return self.fcn, self.interfaces
>
> def type(*args):
> if len(args) != 3:
> return _type(*args)
> name, bases, dct = args
> dct2 = {}
> for nam, obj in dct.items():
> if isinstance(obj, implements_wrapper):
> f, i = obj()
> dct2[nam] = i
> dct[nam] = f
> cls = _type(name, bases, dct)
> for nam, i in dct2.iteritems():
> for j in i:
> #default dict that produced sets would work well here
> _supports.setdefault(getattr(i, nam), {})[cls] = None
> return cls
>
> __builtins__.type = type
Sorry, I don't understand this implementation. I just tried it and
the following fails because ``__getitem__`` is now an
``implements_wrapper`` that accepts the wrong arguments::
class C(object):
@implements(mapping)
def __getitem__(self, item):
return 42
C()[1]
But I think the ``implements()`` decorator is a good way to approach
this. Here's a different approach to it::
def supports(cls, func_or_funcs):
try:
iter(func_or_funcs)
except TypeError:
return func_or_funcs in cls.__supports__
else:
return cls.__supports__.issuperset(func_or_funcs)
def implements(*interfaces):
def decorate(func):
func.__interfaces__ = interfaces
return func
return decorate
class interface_monitor(type):
def __init__(cls, name, bases, bodydict):
cls.__supports__ = set()
for name, value in cls.__dict__.items():
try:
interfaces = value.__interfaces__
except AttributeError:
pass
else:
for interface in interfaces:
method = getattr(interface, name)
cls.__supports__.add(method)
Basically, each function is identified with a set of interface
namespaces, e.g. ``mapping``, and the metaclass then uses
``getattr()`` to get the specific functions, e.g.
``mapping.__getitem__``, and add them to the set of operations the
class supports, i.e. ``cls.__supports__``. Here's how you might
actually use this code::
class Mapping(object):
def __iter__(self):
pass
def __getitem__(self, key):
pass
def get(self, key, default=None):
pass
minimal_mapping = Mapping.__iter__, Mapping.__getitem__
complete_mapping = minimal_mapping + (Mapping.get,)
class C(object):
__metaclass__ = interface_monitor
@implements(Mapping)
def __getitem__(self, key):
return 4
@implements(Mapping)
def __iter__(self):
return [4, 4, 4]
print supports(C, Mapping.__iter__) # prints True
print supports(C, Mapping.__getitem__) # prints True
print supports(C, minimal_mapping) # prints True
print supports(C, complete_mapping) # prints False
Note that with this code, an interface is just a set of methods, so
you can use ``supports()`` equally well to check for support of
individual methods or to check support for whole sets of methods.
STeVe
--
I'm not *in*-sane. Indeed, I am so far *out* of sane that you appear a
tiny blip on the distant coast of sanity.
--- Bucky Katt, Get Fuzzy
More information about the Python-3000
mailing list