poplib for multihomed machines

E

Elbert Lev

There no way to tell the classPOP3 which of local interfaces (NICs) to
use for connections). In most cases it is OK, but requires proper
routing.

Here is the __init__ from POP3

class POP3
def __init__(self, host, port = POP3_PORT):
self.host = host
self.port = port
msg = "getaddrinfo returns an empty list"
self.sock = None
for res in socket.getaddrinfo(self.host, self.port, 0,
socket.SOCK_STREAM):
af, socktype, proto, canonname, sa = res
try:
self.sock = socket.socket(af, socktype, proto)
self.sock.connect(sa)
except socket.error, msg:
if self.sock:
self.sock.close()
self.sock = None
continue
break
if not self.sock:
raise socket.error, msg
self.file = self.sock.makefile('rb')
self._debugging = 0
self.welcome = self._getresp()

Can I subclass it in such a way, that derived class takes care of the
problem?

def __init__ (self, host, port = POP3_PORT, interface = ""):
POP3.__init..(....)

will create the socket and there is no way to bind it to local
interface


The problem with POP3 class is: it connects during __init__ and it is
"hard coded". I do not see any way to change this behavior with no
rewrite of POP3 class.

Do you?
 
D

Donn Cave

There no way to tell the classPOP3 which of local interfaces (NICs) to
use for connections). In most cases it is OK, but requires proper
routing.

Here is the __init__ from POP3

class POP3
def __init__(self, host, port = POP3_PORT):
self.host = host
self.port = port
msg = "getaddrinfo returns an empty list"
self.sock = None
for res in socket.getaddrinfo(self.host, self.port, 0,
socket.SOCK_STREAM):
af, socktype, proto, canonname, sa = res
try:
self.sock = socket.socket(af, socktype, proto)
self.sock.connect(sa)
except socket.error, msg:
if self.sock:
self.sock.close()
self.sock = None
continue
break
if not self.sock:
raise socket.error, msg
self.file = self.sock.makefile('rb')
self._debugging = 0
self.welcome = self._getresp()

Can I subclass it in such a way, that derived class takes care of the
problem?

def __init__ (self, host, port = POP3_PORT, interface = ""):
POP3.__init..(....)

will create the socket and there is no way to bind it to local
interface


The problem with POP3 class is: it connects during __init__ and it is
"hard coded". I do not see any way to change this behavior with no
rewrite of POP3 class.

Do you?

Well, no. It should probably use an open() method like imaplib's.

Donn Cave, (e-mail address removed)
 
E

Elbert Lev

Donn Cave said:
Well, no. It should probably use an open() method like imaplib's.

Donn Cave, (e-mail address removed)


This is a major design error. NO-NO is C++. Constructor is supposed
only initialise members and take no actions. Unfortunatelly this
paradigm is violated in many Python classes.
 
P

Peter Hansen

Elbert said:
This is a major design error. NO-NO is C++. Constructor is supposed
only initialise members and take no actions. Unfortunatelly this
paradigm is violated in many Python classes.

__init__ is an initializer, not a constructor. Python didn't have
real constructors until the new style classes were created, and
__new__.
 
D

Donn Cave

This is a major design error. NO-NO is C++. Constructor is supposed
only initialise members and take no actions. Unfortunatelly this
paradigm is violated in many Python classes.

Well, C++ is NO-NO for sure, but for the rest I think in
the Python world it's better to stick to what works and
what doesn't.

The standard core library classes often seem to me to be
designed in fairly conscious recognition of the fact that
they're lightweight. If you need to make minor, or major,
changes to support your application, I think that happens
fairly often, and it isn't a big problem. If a new release
of poplib introduces a feature you want, it's easy to copy
it into your version. I know that sounds awful, but we're
software engineers, right? Not theoreticians, not priests
of some software cult. We should know the difference between
a real problem and a theoretical problem. The whole thing
is only 335 lines in 2.2.

Meanwhile, for the casual application that's really served
by these classes, convenience is king. You will find __init__
functions taking "actions" because that relieves the user
of a need to know extra steps. If there's a practical need
to decouple POP3 instantiation from the network connection,
then I'm sure its author will be interested (though of course
by now there will be some backwards compatibility issues.)
If the practical issues can be resolved by factoring the
network connection out into a separate function, then that's
a practical solution, don't you think?

Donn Cave, (e-mail address removed)
 
E

Elbert Lev

Donn!
If the practical issues can be resolved by factoring the
network connection out into a separate function, then that's
a practical solution, don't you think?

Fixing this particular piece of code is very simple. But let's talk
about big system. If all classes in standard library are written like
POP3 class (and most of them are) you will "tailor for your needs"
most of them. Not subclass but copy and modify! So the standard
library becomes a "reference material". The classes in standard
library use other pieces of standard library (who does not?). If these
pieces change you have to track the changes and incorporate into your
code. (if you subclass in most cases subclased class takes care of
modifications).

I'm not talking about a casual script, which runs on you PC and copies
files from one directory to a backup storage. I'm talking about realy
big system...

So the answer is NO. I don't think that copy and paste is the best
solution. In other words if you are in OOP world do not use concrete
classes.
 
D

Donn Cave

Fixing this particular piece of code is very simple. But let's talk
about big system. If all classes in standard library are written like
POP3 class (and most of them are) you will "tailor for your needs"
most of them. Not subclass but copy and modify! So the standard
library becomes a "reference material". The classes in standard
library use other pieces of standard library (who does not?). If these
pieces change you have to track the changes and incorporate into your
code. (if you subclass in most cases subclased class takes care of
modifications).

I'm not talking about a casual script, which runs on you PC and copies
files from one directory to a backup storage. I'm talking about realy
big system...

So the answer is NO. I don't think that copy and paste is the best
solution. In other words if you are in OOP world do not use concrete
classes.

I'm not sure I'm following this. Is some part of your
message here a response to the paragraph you quoted from me?

I don't think anyone would argue that it's better if we can
accomplish what we want with a subclass, rather than copying
code out of the library, and I think the author of the POP3
class might agree that this is a deficiency that should be
corrected, especially if that can be done without breaking
current applications. And we know how to do that, right?

I imagine the authors of other standard libraries would
also appreciate suggestions if they present similar problems.
They might also be interested in your ideas about OOP, but
there's nothing better than a good solution to real, practical
problem as a way to present those ideas.

Donn Cave, (e-mail address removed)
 
E

Elbert Lev

Donn!
My reply was a reaction to 2 pieces of your origianl reply:

1. Well, C++ is NO-NO for sure, but for the rest I think in
the Python world it's better to stick to what works and
what doesn't.

and

2. if a new release of poplib introduces a feature you want, it's easy
to copy
it into your version. I know that sounds awful, but we're
software engineers, right? Not theoreticians, not priests
of some software cult. We should know the difference between
a real problem and a theoretical problem. The whole thing
is only 335 lines in 2.2.


C++ was an example. Actually it is NO-NO in OOP. And I do not want to
discuss the second. Writing this I do not say, that I personaly never
copy-and-paste, instead of writing a right class hierarhy. But there
is a difference: standard library and application programming. Sure
you understand... I did not want to offend you :).
 
J

Jorgen Grahn

This is a major design error. NO-NO is C++. Constructor is supposed
only initialise members and take no actions. Unfortunatelly this
paradigm is violated in many Python classes.

I assume 'NO-NO is C++' means "it is well known that this would be bad
design if written in C++".

Unfortunately, Bjarne Stroustrup doesn't agree. See
http://www.research.att.com/~bs/3rd_safe.pdf section E.3.5
where he spends a few pages arguing against designing classes with init()
functions ("two-stage construct").

If on the other hand it is bad form in Python for some reason, please
enlighten me. I love both C++ and Python, so I try to Do The Right Thing in
both languages.

/Jorgen
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,053
Latest member
BrodieSola

Latest Threads

Top