Modules and descriptors

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Chris Leary

    Modules and descriptors

    As I understand it, the appeal of properties (and descriptors in
    general) in new-style classes is that they provide a way to
    "intercept" direct attribute accesses. This lets us write more clear
    and concise code that accesses members directly without fear of future
    API changes.

    I love this feature of the language, but find that I still have to
    call getter/setter methods of module instances. Since module
    attributes are accessed by way of __dict__ and the module type has a
    valid __mro__, why doesn't the descriptor protocol apply to module
    instances?

    TIA!

    P.S. There is some previous discussion in comp.lang.pytho n about using
    a module like a new-style class.







    The suggested solution is always to provide a class wrapper in the
    module itself, and have the module-user instantiate it appropriately.
    This is a valid solution, but doesn't ensure that the client will use
    it (the descriptor protocol does, as a feature of the language). As a
    result, changes like these can break existing code that uses the
    module.
  • Steven Bethard

    #2
    Re: Modules and descriptors

    Chris Leary wrote:
    As I understand it, the appeal of properties (and descriptors in
    general) in new-style classes is that they provide a way to
    "intercept" direct attribute accesses. This lets us write more clear
    and concise code that accesses members directly without fear of future
    API changes.
    >
    I love this feature of the language, but find that I still have to
    call getter/setter methods of module instances. Since module
    attributes are accessed by way of __dict__ and the module type has a
    valid __mro__, why doesn't the descriptor protocol apply to module
    instances?
    Because it doesn't apply to class *instances*. Module-level code gets
    executed roughly like this::

    mod = ModuleType(...)
    exec module_code in mod.__dict__

    So consider the similar code::
    >>class C(object):
    ... pass
    ...
    >>c = C()
    >>exec '''
    ... def foo(self, *args):
    ... print self, args
    ... ''' in c.__dict__

    A function ``foo`` has been added to the ``C`` instance. But *instances*
    don't invoke the descriptor protocol, so we the ``self`` parameter is
    not bound to the ``C`` instance::
    >>c.foo()
    Traceback (most recent call last):
    File "<interacti ve input>", line 1, in <module>
    TypeError: foo() takes at least 1 argument (0 given)

    So the straightforward answer to your question is that module instances
    don't invoke the descriptor protocol because instances in general don't
    invoke the protocol (only classes do).

    The follow-up question is usually something like "well, can't we make
    module instances special and have them invoke the descriptor protocol?"
    Yes, in theory it would be possible, but it would break backwards
    compatibility in very bad ways. For example, every pure function you
    define at the module level would then become a bound method whenever it
    was accessed. Consider a simple module ``mod`` like::

    def foo(bar):
    return 'baz(%s)' % bar

    If I try to use this module, and module instances invoke the descriptor
    protocol, then ``bar`` will always be bound to the module instance. That
    means we'd have to totally change how we right module level functions,
    and they'd have to start looking like this::

    def foo(mod, bar):
    return 'baz(%s)' % bar

    That, of course, would break *tons* of existing code.

    STeVe

    Comment

    Working...