<br><br><div class="gmail_quote">On Mon, Apr 30, 2012 at 7:33 PM, Guido van Rossum <span dir="ltr"><<a href="mailto:guido@python.org" target="_blank">guido@python.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div class="im">On Mon, Apr 30, 2012 at 5:47 PM, Steven D'Aprano <<a href="mailto:steve@pearwood.info">steve@pearwood.info</a>> wrote:<br>
> Gregory P. Smith wrote:<br>
><br>
>> Making modules "simply" be a class that could be subclasses rather than<br>
>> their own thing _would_ be nice for one particular project I've worked on<br>
>> where the project including APIs and basic implementations were open<br>
>> source<br>
>> but which allowed for site specific code to override many/most of those<br>
>> base implementations as a way of customizing it for your own specific (non<br>
>> open source) environment.<br>
<br>
> This makes no sense to me. What does the *licence* of a project have to do<br>
> with the library API? I mean, yes, you could do such a thing, but surely you<br>
> shouldn't. That would be like saying that the accelerator pedal should be on<br>
> the right in cars you buy outright, but on the left for cars you get on<br>
> hire-purchase.<br>
<br>
</div>That's an irrelevant, surprising and unfair criticism of Greg's<br>
message. He just tried to give a specific example without being too<br>
specific.<br></blockquote><div><br></div><div>heh. right. I didn't want to drag people into a project that shall not be named because I dislike its design to begin with... I was just suggesting a case where we _would_ have found it useful to treat a module as a class that could be subclassed. A better overall design pattern using classes in the code's public APIs to start with would have prevented all such need.</div>
<div><br></div><div>I am not strongly in favor of modules being classes but it is an interesting thing to ponder from time to time.</div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div><div class="h5"><br>
> Nevertheless, I think your focus here is on the wrong thing. It seems to me<br>
> that you are jumping to an implementation, namely that modules should stop<br>
> being instances of a type and become classes, without having a clear idea of<br>
> your functional requirements.<br>
><br>
> The functional requirements *might* be:<br>
><br>
> "There ought to be an easy way to customize the behaviour of attribute<br>
> access in modules."<br>
><br>
> Or perhaps:<br>
><br>
> "There ought to be an easy way for one module to shadow another module with<br>
> the same name, but still inherit behaviour from the shadowed module."<br>
><br>
> neither of which *require* modules to become classes.<br>
><br>
> Or perhaps it is something else... it is unclear to me exactly what problems<br>
> you and Jim wish to solve, or whether they're the same kind of problem,<br>
> which is why I say the functional requirements are unclear.<br>
><br>
> Changing modules from an instance of ModuleType to "a class that could be a<br>
> subclass" is surely going to break code. Somewhere, someone is relying on<br>
> the fact that modules are not types and you're going to break their<br>
> application.<br>
><br>
><br>
><br>
>> Any APIs that were unfortunately defined as a<br>
>> module with a bunch of functions in it was a real pain to make site<br>
>> specific overrides for.<br>
><br>
><br>
> It shouldn't be. Just ensure the site-specific override module comes first<br>
> in the path, and "import module" will pick up the override module instead of<br>
> the standard one. This is a simple exercise in shadowing modules.<br>
><br>
> Of course, this implies that the override module has to override<br>
> *everything*. There's currently no simple way for the shadowing module to<br>
> inherit functionality from the shadowed module. You can probably hack<br>
> something together, but it would be a PITA.<br>
<br>
</div></div>If there is a bunch of functions and you want to replace a few of<br>
those, you can probably get the desired effect quite easily:<br>
<br>
from base_module import * # Or the specific set of functions that<br>
comprise the API.<br>
<br>
def funct1(<args>): <my version><br>
def funct2(<args>): <my version><br>
<br>
Not that I would recommend this -- it's easy to get confused if there<br>
are more than a very small number of functions. Also if<br>
base_module.funct3 were to call func2, it wouldn't call the overridden<br>
version.<br>
<br>
But all attempts to view modules as classes or instances have lead to<br>
negative results. (I'm sure I've thought about it at various times in<br>
the past.)<br>
<br>
I think the reason is that a module at best acts as a class where<br>
every method is a *static* method, but implicitly so. Ad we all know<br>
how limited static methods are. (They're basically an accident -- back<br>
in the Python 2.2 days when I was inventing new-style classes and<br>
descriptors, I meant to implement class methods but at first I didn't<br>
understand them and accidentally implemented static methods first.<br>
Then it was too late to remove them and only provide class methods.)<br></blockquote><div><br></div><div>This "oops, I implemented static methods" is a wonderful bit of history! :)</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
There is actually a hack that is occasionally used and recommended: a<br>
module can define a class with the desired functionality, and then at<br>
the end, replace itself in sys.modules with an instance of that class<br>
(or with the class, if you insist, but that's generally less useful).<br>
E.g.:<br>
<br>
# module foo.py<br>
<br>
import sys<br>
<br>
class Foo:<br>
def funct1(self, <args>): <code><br>
def funct2(self, <args>): <code><br>
<br>
sys.modules[__name__] = Foo()<br>
<br>
This works because the import machinery is actively enabling this<br>
hack, and as its final step pulls the actual module out of<br>
sys.modules, after loading it. (This is no accident. The hack was<br>
proposed long ago and we decided we liked enough to support it in the<br>
import machinery.)<br>
<br>
You can easily override __getattr__ / __getattribute__ / __setattr__<br>
this way. It also makes "subclassing" the module a little easier<br>
(although accessing the class to be used as a base class is a little<br>
tricky: you'd have to use foo.__class__). But of course the kind of<br>
API that Greg was griping about would never be implemented this way,<br>
so that's fairly useless. And if you were designing a module as an<br>
inheritable class right from the start you're much better off just<br>
using a class instead of the above hack.<br>
<br>
But all in all I don't think there's a great future in stock for the<br>
idea of allowing modules to be "subclassed". In the vast, vast<br>
majority of cases it's better to clearly have a separation between<br>
modules, which provide no inheritance and no instantiation, and<br>
classes, which provide both. I think Python is better off this way<br>
than Java, where all you have is classes (its packages cannot contain<br>
anything except class definitions).<br>
<span class="HOEnZb"><font color="#888888"><br>
--<br>
--Guido van Rossum (<a href="http://python.org/~guido" target="_blank">python.org/~guido</a>)<br>
</font></span><div class="HOEnZb"><div class="h5">_______________________________________________<br>
Python-ideas mailing list<br>
<a href="mailto:Python-ideas@python.org">Python-ideas@python.org</a><br>
<a href="http://mail.python.org/mailman/listinfo/python-ideas" target="_blank">http://mail.python.org/mailman/listinfo/python-ideas</a><br>
</div></div></blockquote></div><br>