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 "<interactive 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 -- http://mail.python.org/mailman/listinfo/python-list