pythonzopezope3zope.component

Issue with zope.component subscriber adapters adapting multiple objects


Given the following code:

from zope.component import getGlobalSiteManager, adapts, subscribers
from zope.interface import Interface, implements


class A(object): pass
class B(object): pass
class C(B): pass

class AB(object):
    implements(Interface)
    adapts(A, B)

    def __init__(self, a, b):
        pass

class AC(object):
    implements(Interface)
    adapts(A, C)

    def __init__(self, a, c):
        pass

gsm = getGlobalSiteManager()
gsm.registerSubscriptionAdapter(AB)
gsm.registerSubscriptionAdapter(AC)

a = A()
c = C()

for adapter in subscribers([a, c], Interface):
    print adapter

The output it produces is:

<__main__.AB object at 0xb242290>
<__main__.AC object at 0xb2422d0>

Why is an instance of AB returned? AB only declares that it adapts A and B. Is there a way I can achieve behavior where only AC would be returned?


Solution

  • You are listing subscribers. Subscribers are notified of all things that implement the interface(s) they are interested in.

    C is a subclass of B, so the B subscriber is interested, and will be notified. The fact that C implements a little more is of no concern to the B subscriber, as the object will implement at least the B interface.

    Subscribers are generic, they just want objects that implement their interface or subclasses thereof. Adapters are more specific:

    >>> gsm.registerAdapter(AB)
    >>> gsm.registerAdapter(AC)
    >>> from zope.component import getAdapters
    >>> for adapter in getAdapters((a, c), Interface):
    ...     print adapter
    ... 
    (u'', <__main__.AC object at 0x104b25a90>)
    

    getAdapters() enumerates all registered adapters, together with their names:

    >>> class AnotherAC(object):
    ...     implements(Interface)
    ...     adapts(A, C)
    ...     def __init__(self, a, c): pass
    ... 
    >>> gsm.registerAdapter(AnotherAC, name=u'another')
    >>> for adapter in getAdapters((a, c), Interface):
    ...     print adapter
    ... 
    (u'', <__main__.AC object at 0x104b25ed0>)
    (u'another', <__main__.AnotherAC object at 0x104b25a90>)