Re: [Tutor] Py 2.4.4: Inheriting from ftplib.FTP()
On Fri, Jun 17, 2016 at 11:42 AM boB Stepp wrote: > On Thu, Jun 16, 2016 at 11:40 AM, Alan Gauld via Tutor > wrote: > > On 16/06/16 16:38, boB Stepp wrote: > > > >> class FTPFiles(FTP, object): > >> """FTP files to Windows server location(s).""" > > I was struggling to come up with a good name here that would not cause > me any name collision issues with the contents of ftplib.FTP(). That's why we have namespaces. Your ``FTP`` would not collide with ``ftplib.FTP``, because they are in separate modules. I looked up LSP last night. I can see how I can easily get burned > even on something seemingly simple. One example, which I imagine is > often used, is of a square class inheriting from a rectangle class. > Squares have same sized sides; rectangles not necessarily so. So any > size changing methods from the rectangle class inherited by the square > class can potentially wreak havoc on squares. Am I getting the > essence of the potential issues I might encounter? > Yes, that's the gist of it. It's very hard to anticipate what features your base class may need in the future, months or years down the road. Many of them may be inappropriate for one or more child classes. ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Py 2.4.4: Inheriting from ftplib.FTP()
On 17/06/16 16:41, boB Stepp wrote: >> Inheritance is a powerful tool but it carries lots of potential for >> problems too,... > > I looked up LSP last night. I can see how I can easily get burned > even on something seemingly simple. One example, which I imagine is > often used, is of a square class inheriting from a rectangle class. > Squares have same sized sides; rectangles not necessarily so. So any > size changing methods from the rectangle class inherited by the square > class can potentially wreak havoc on squares. Am I getting the > essence of the potential issues I might encounter? Yes, that's one case. Another good example(in Java) is in the book "Effective Java". It uses the example of a superclass which is a collection and has add() and add_many() methods. Now let's say you want to create a counted collection so you override the add() method to add one to a total each time its called. Then you override add_many() to add the number of items in the params list. The problem is that, unknown to you, the inherited add_many() calls self.add() internally so you wind up double counting on add_many()... You need to know about the internals of the superclass to correctly implement your sub class, which breaks the concept of data hiding... There is no way round this its just one of the inherent(sic) issues with OOP, but a good reason to use delegation rather than inheritance if possible. Inheritance is a powerful tool but comes with sharp claws. (Its even worse in a static language like Java but even in Python there are plenty of opportunities to mess up). -- Alan G Author of the Learn to Program web site http://www.alan-g.me.uk/ http://www.amazon.com/author/alan_gauld Follow my photo-blog on Flickr at: http://www.flickr.com/photos/alangauldphotos ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Py 2.4.4: Inheriting from ftplib.FTP()
I guess I did not emphasize enough that I was just starting to think through this. The code I posted yesterday was more in the way of exploratory code, trying to understand how to implement inheritance, using new-style classes (I am trying to integrate the work with Python 3 at home as much as possible with what I am forced to in Python 2.4 at work where I have no choices as to Python version.). On Fri, Jun 17, 2016 at 10:31 AM, Steven D'Aprano wrote: > Some futher thoughts: > > On Thu, Jun 16, 2016 at 10:38:13AM -0500, boB Stepp wrote: >> class FTPFiles(FTP, object): >> """FTP files to Windows server location(s).""" >> >> def __init__(self, host=server_ip, user=user, passwd=passwd): >> """Initialize FTPFiles object. Normally the defaults will be >> used.""" >> >> super(FTPFiles, self).__init__(host, user, passwd) >> self.host = host >> self.user = user >> self.passwd = passwd > > Do you actually need to record these? Once they're used to establish a > connection and login, what are they for? No, I was just spelling everything out for myself while I was trying to figure out why my original code was not working. All the things I said I "learned" were not in my earlier versions. These lines have already been excised as I am getting closer to something I might actually want to implement. Also, now that I have had the opportunity to play around with inheritance, I don't see any need to specialize the FTP class as I mention in my response to Alan I just sent out. > >> def print_welcome_msg(self): >> """Print welcome message sent by FTP server.""" >> print self.getwelcome() > > The getwelcome method already prints the message, which is a bad design. > But only if debugging is true. So I would approach this in one of two > ways: The only point of this method was to ensure that I was actually connected to my server. During earlier versions, things were acting weird and I was not understanding what was going on. So I wanted to be certain I was in fact connected; it turned out I was not! This also has been excised today. > (1) Delegate to the existing getwelcome method: > > def print_welcome_msg(self): > save_flag = self.debugging > self.debugging = True > try: > x = self.getwelcome() # prints the msg > finally: > self.debugging = save_flag > > > (2) Re-implement the print functionality. > > def print_welcome_msg(self): > print "*welcome*", self.welcome > > > (3) If you really want to be paranoid, use: > > print "*welcome*", self.sanitize(self.welcome) > > > although I don't think it's likely to make any real difference in > practice. > > (The sanitize method makes a feeble attempt to hide the password.) Some interesting ideas to aid debugging. Thanks! >> What I learned today: >> >> 1) FTP from ftplib appears to be an old-style class. >> >> 2) I can't just use "class FTPFiles(FTP)" or I will be using old-style >> classes. > > Is this a problem? Old-style classes are good enough for many purposes. Not really. I am just trying to consolidate the studies I am doing at home with Python 3 as much as I can when I am working with Python 2. >> 3) I need to use "class FTPFiles(FTP, object)" to use new-style >> classes and "object" must come AFTER "FTP". >> >> 4) I have to use "super(FTPFiles, self).__init__(host, user, passwd)" >> or I cannot successfully inherit from the FTP() class. Also, "self" >> apparently must come AFTER "FTPFiles" in the super expression. > > For old-style classes, don't use super because it doesn't work. Instead > just write: > > FTP.__init__(self, host, user, passwd) Yeah, if I just stuck to old-style, things would have been easier. > That means that you cannot engage in multiple inheritence with new-style > classes, but MI is a serious pain to get right, and 99% of the time it > is overkill, so you're not missing much. Right now just the simpler OOP stuff is a "serious pain" while I am still in the relatively early stages of learning. ~(:>)) boB ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Py 2.4.4: Inheriting from ftplib.FTP()
On Thu, Jun 16, 2016 at 11:40 AM, Alan Gauld via Tutor wrote: > On 16/06/16 16:38, boB Stepp wrote: > >> class FTPFiles(FTP, object): >> """FTP files to Windows server location(s).""" > > OK, First comment. You describe this as an action(verb) > rather than a noun. Classes should represent nouns > (objects) not actions. FTP represents a protocol > connection with which you can do things (one of > which is put/get files) you class should be the same. > (Remember inheritance m,eans you are imp0lementing > an "is a" relationship. So FTPFiles is an FTP...or > should be.) I was struggling to come up with a good name here that would not cause me any name collision issues with the contents of ftplib.FTP(). I have for the moment changed the class name to "CustomFTP", which bothers me for some reason that I cannot put my finger on. However, this looks to become a non-issue; see below. >> 4) As this class stuff is mostly treading new ground for me, am I >> doing anything that I should not be doing or should do in a more >> preferred way? Keep in mind that I am just starting on this code >> today. > > I'll leave someone with more ftplib experience to answer the other > points but the question I'd ask is what are you planning to add to FTP? > Creating a new class by inheritance implies that you are going to be > extending (or specializing) its capabilities in some way. What are you > planning to extend/specialize? For example are you going to limit it to > manipulating files only? ie prevent listing directories say? My first objective was just to play around with inheritance as a learning opportunity. Now that I have gotten it to work and have somewhat a feel for the possibilities, I am actually going to abandon it for this specific project. I think I can use the FTP class unmodified and just write appropriate helper functions to get the specifics of what I want, passing my specific FTP instance object to these functions. > You need to know what you are changing to warrant using inheritance. > Inheritance is a powerful tool but it carries lots of potential for > problems too, especially if you plan on mixing your new class in with > the old one (or sharing it with others who will) - you need to be > careful to abide by the Liskov substitution principle (LSP). I looked up LSP last night. I can see how I can easily get burned even on something seemingly simple. One example, which I imagine is often used, is of a square class inheriting from a rectangle class. Squares have same sized sides; rectangles not necessarily so. So any size changing methods from the rectangle class inherited by the square class can potentially wreak havoc on squares. Am I getting the essence of the potential issues I might encounter? boB ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Py 2.4.4: Inheriting from ftplib.FTP()
Some futher thoughts: On Thu, Jun 16, 2016 at 10:38:13AM -0500, boB Stepp wrote: > class FTPFiles(FTP, object): > """FTP files to Windows server location(s).""" > > def __init__(self, host=server_ip, user=user, passwd=passwd): > """Initialize FTPFiles object. Normally the defaults will be used.""" > > super(FTPFiles, self).__init__(host, user, passwd) > self.host = host > self.user = user > self.passwd = passwd Do you actually need to record these? Once they're used to establish a connection and login, what are they for? > def print_welcome_msg(self): > """Print welcome message sent by FTP server.""" > print self.getwelcome() The getwelcome method already prints the message, which is a bad design. But only if debugging is true. So I would approach this in one of two ways: (1) Delegate to the existing getwelcome method: def print_welcome_msg(self): save_flag = self.debugging self.debugging = True try: x = self.getwelcome() # prints the msg finally: self.debugging = save_flag (2) Re-implement the print functionality. def print_welcome_msg(self): print "*welcome*", self.welcome (3) If you really want to be paranoid, use: print "*welcome*", self.sanitize(self.welcome) although I don't think it's likely to make any real difference in practice. (The sanitize method makes a feeble attempt to hide the password.) > if __name__ == '__main__': > ftp = FTPFiles() > ftp.print_welcome_msg() > ftp.quit() This appears to be equivalent to: ftp = FTP(host, user, passwd) ftp.debugging = True x = ftp.getwelcome() ftp.quit() > What I learned today: > > 1) FTP from ftplib appears to be an old-style class. > > 2) I can't just use "class FTPFiles(FTP)" or I will be using old-style > classes. Is this a problem? Old-style classes are good enough for many purposes. > 3) I need to use "class FTPFiles(FTP, object)" to use new-style > classes and "object" must come AFTER "FTP". > > 4) I have to use "super(FTPFiles, self).__init__(host, user, passwd)" > or I cannot successfully inherit from the FTP() class. Also, "self" > apparently must come AFTER "FTPFiles" in the super expression. For old-style classes, don't use super because it doesn't work. Instead just write: FTP.__init__(self, host, user, passwd) That means that you cannot engage in multiple inheritence with new-style classes, but MI is a serious pain to get right, and 99% of the time it is overkill, so you're not missing much. -- Steve ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Py 2.4.4: Inheriting from ftplib.FTP()
On Thu, Jun 16, 2016 at 10:38:13AM -0500, boB Stepp wrote: > I am extremely gradually trying to dip my big toe into the waters of > writing classes. [...] > What I learned today: > > 1) FTP from ftplib appears to be an old-style class. > > 2) I can't just use "class FTPFiles(FTP)" or I will be using old-style > classes. > > 3) I need to use "class FTPFiles(FTP, object)" to use new-style > classes and "object" must come AFTER "FTP". > > 4) I have to use "super(FTPFiles, self).__init__(host, user, passwd)" > or I cannot successfully inherit from the FTP() class. Also, "self" > apparently must come AFTER "FTPFiles" in the super expression. > > Questions: > > 1) Are there any more common "gotchas" that might be coming my way in > trying to use a new-style class inheriting from an old-style class in > ancient Py 2.4.4? That's a very interesting question. I *think* the answer is "No", but I wouldn't put money on it. > 2) I don't have much knowledge about FTP processes. This is being > used on a secure intranet environment. And I am using the ftplib for > the first time. In its docs it mentioned that the quit() method is > the "polite" way to close the connection, but that an exception may be > raised if the responds with an error to the "QUIT" command the method > sends. If this happens, will the connection close? According to the source code, yes. > Or should I do something like: > > try: > ftp.quit() > except: > ftp.close() > > ? It seems here (If I should use the "try" block.) that a bare > "except" is appropriate as I would think I would want to close the > connection regardless of the type of error the "QUIT" command > generates. Bare except is nearly never appropriate. Consider: try: fpt.quit() except: ftp.close() > 3) The point of the print_welcome_msg() method is to be sure that I > have actually successfully connected to the FTP server. Is there a > better way to check for connection success? If the connect method doesn't raise an exception, it connected successfully. -- Steve ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Py 2.4.4: Inheriting from ftplib.FTP()
On 16/06/16 16:38, boB Stepp wrote: > class FTPFiles(FTP, object): > """FTP files to Windows server location(s).""" OK, First comment. You describe this as an action(verb) rather than a noun. Classes should represent nouns (objects) not actions. FTP represents a protocol connection with which you can do things (one of which is put/get files) you class should be the same. (Remember inheritance m,eans you are imp0lementing an "is a" relationship. So FTPFiles is an FTP...or should be.) > def __init__(self, host=server_ip, user=user, passwd=passwd): > """Initialize FTPFiles object. Normally the defaults will be used.""" > > super(FTPFiles, self).__init__(host, user, passwd) > self.host = host > self.user = user > self.passwd = passwd > > def print_welcome_msg(self): > """Print welcome message sent by FTP server.""" > print self.getwelcome() > 1) FTP from ftplib appears to be an old-style class. Using Python 2.4 that's not too surprising, FTP is an old module. > 4) I have to use "super(FTPFiles, self).__init__(host, user, passwd)" > or I cannot successfully inherit from the FTP() class. Also, "self" > apparently must come AFTER "FTPFiles" in the super expression. That's the v2 super(). v3 super is far supeerior. > 4) As this class stuff is mostly treading new ground for me, am I > doing anything that I should not be doing or should do in a more > preferred way? Keep in mind that I am just starting on this code > today. I'll leave someone with more ftplib experience to answer the other points but the question I'd ask is what are you planning to add to FTP? Creating a new class by inheritance implies that you are going to be extending (or specializing) its capabilities in some way. What are you planning to extend/specialize? For example are you going to limit it to manipulating files only? ie prevent listing directories say? You need to know what you are changing to warrant using inheritance. Inheritance is a powerful tool but it carries lots of potential for problems too, especially if you plan on mixing your new class in with the old one (or sharing it with others who will) - you need to be careful to abide by the Liskov substitution principle (LSP). -- Alan G Author of the Learn to Program web site http://www.alan-g.me.uk/ http://www.amazon.com/author/alan_gauld Follow my photo-blog on Flickr at: http://www.flickr.com/photos/alangauldphotos ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
[Tutor] Py 2.4.4: Inheriting from ftplib.FTP()
I am extremely gradually trying to dip my big toe into the waters of writing classes. I have a little bit of extra time at work today, so I thought I would start writing a class to replace a bunch of shell FTP scripts I've used in various programs that would be flexible enough to be reused wherever I need it. I immediately ran into problems, which I have (to the best of my knowledge) resolved. However, I am still in the early stages of writing the methods for this class, so I thought I would ask for any likely "gotchas" that might come my way. Python 2.4.4 on Solaris 10: from ftplib import FTP # Current values for Windows-based intranet FTP server: server_ip = 'my_default_IP' user = 'default_user' passwd = 'default_pw' class FTPFiles(FTP, object): """FTP files to Windows server location(s).""" def __init__(self, host=server_ip, user=user, passwd=passwd): """Initialize FTPFiles object. Normally the defaults will be used.""" super(FTPFiles, self).__init__(host, user, passwd) self.host = host self.user = user self.passwd = passwd def print_welcome_msg(self): """Print welcome message sent by FTP server.""" print self.getwelcome() if __name__ == '__main__': ftp = FTPFiles() ftp.print_welcome_msg() ftp.quit() What I learned today: 1) FTP from ftplib appears to be an old-style class. 2) I can't just use "class FTPFiles(FTP)" or I will be using old-style classes. 3) I need to use "class FTPFiles(FTP, object)" to use new-style classes and "object" must come AFTER "FTP". 4) I have to use "super(FTPFiles, self).__init__(host, user, passwd)" or I cannot successfully inherit from the FTP() class. Also, "self" apparently must come AFTER "FTPFiles" in the super expression. Questions: 1) Are there any more common "gotchas" that might be coming my way in trying to use a new-style class inheriting from an old-style class in ancient Py 2.4.4? 2) I don't have much knowledge about FTP processes. This is being used on a secure intranet environment. And I am using the ftplib for the first time. In its docs it mentioned that the quit() method is the "polite" way to close the connection, but that an exception may be raised if the responds with an error to the "QUIT" command the method sends. If this happens, will the connection close? Or should I do something like: try: ftp.quit() except: ftp.close() ? It seems here (If I should use the "try" block.) that a bare "except" is appropriate as I would think I would want to close the connection regardless of the type of error the "QUIT" command generates. 3) The point of the print_welcome_msg() method is to be sure that I have actually successfully connected to the FTP server. Is there a better way to check for connection success? 4) As this class stuff is mostly treading new ground for me, am I doing anything that I should not be doing or should do in a more preferred way? Keep in mind that I am just starting on this code today. As always, many thanks in advance! -- boB ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor