Re: Interface and duck typing woes
In article <5221352b$0$6599$c3e8da3$54964...@news.astraweb.com>, Steven D'Aprano wrote: > Heh, everybody has one of two reactions: > > "This is awesome!" [[i.e. what I said]] > > "You'll add type checking to my Python code over my dead body!!!" Duck typing is a funny thing. Sure, I don't have to give you a Duck, I just have to give you something that quacks like a Duck. But, at some point, you and I need to agree on what that means. If you're expecting a https://en.wikipedia.org/wiki/Duck and I give you a https://en.wikipedia.org/wiki/DUKW, we've had a failure to communicate. To take a quasi-realistic example, let's say I've got this musical masterpiece in my database: { "_id" : ObjectId("4ccb7052e5f37551d479add6"), "album" : "My World", "album_comp_id" : NumberLong(34732133), "artist" : "Justin Bieber", "avail_date_aac" : ISODate("1970-01-01T00:00:00Z"), "avail_date_mp3" : ISODate("1970-01-01T00:00:00Z"), "duration" : 192, "genre" : "Pop", "mn_comp_id" : NumberLong(34732147), "seq_num" : 1297, "song_id" : 6544798, "title" : "Love Me", "track" : -1 } If I want to ask you, "Please return to me a url from which I can stream this song as an mp3", I could look at your Song class and find: @staticmethod def get_stream_url(song): [some code goes here] but that would leave me wondering what you mean by "song". You could legitimately mean 6544798, "4ccb7052e5f37551d479add6", ObjectId("4ccb7052e5f37551d479add6"), an instance of the Song class itself, or possibly even 34732147. Depending on the context, any of those might very well be the right answer. And, we haven't even gotten to describing what I should expect to get back. So, to clear things up, you had to go and write something in the doc string: @staticmethod def get_stream_url(song): """Song is an instance of class Song. This will return an absolute URL as a string.""" But, why not just embed that information in some way which is both compact and machine readable? Of course, when I say, "Song is an instance of class Song", what I really (in full duck typing glory) mean is, "Song is something which has a "mn_comp_id" attribute whose value is something which I can pass to str() and get back a properly formatted decimal integer string. So, this would work, wouldn't it? class Platypus: def __getattr__(self, name): return 34732147 duck = Platypus() Song.get_stream_url(duck) Hey, it met the description you gave me, didn't it? And, sure enough, if you do with duck what I expect you will, we will soon hear Justin Bieber's, "Love Me" coming out the speaker. But, in reality, I suspect we would quickly get into an argument about just what exactly did you mean when you said "Duck". -- http://mail.python.org/mailman/listinfo/python-list
Re: Interface and duck typing woes
On 31 August 2013 01:13, Steven D'Aprano wrote: > On Fri, 30 Aug 2013 06:35:47 -0400, Roy Smith wrote: > >> In article <52200699$0$6599$c3e8da3$54964...@news.astraweb.com>, >> Steven D'Aprano wrote: >> >>> These days, it would be relatively simple to implement pre- and post- >>> condition checking using decorators, and indeed one of the motivating >>> use- cases for function annotations in Python 3 is to allow such >>> things. >>> >>> http://www.python.org/dev/peps/pep-3107/ >>> >>> (Function annotations are perhaps the best Python feature that nobody >>> uses.) >> >> This is awesome. > > Heh, everybody has one of two reactions: > > "This is awesome!" > > "You'll add type checking to my Python code over my dead body!!!" > > But I'm still to see a practical use for annotations in real world code. > Or indeed to think of a use for them other than type checking. I occasionally use them for documentation. I think that there some are cases where the return type (encoded as a string) is as good an indicator of functionality as a short docstring, so use both. -- http://mail.python.org/mailman/listinfo/python-list
Re: Interface and duck typing woes
On 8/30/13 8:13 PM, Steven D'Aprano wrote: On Fri, 30 Aug 2013 06:35:47 -0400, Roy Smith wrote: In article <52200699$0$6599$c3e8da3$54964...@news.astraweb.com>, Steven D'Aprano wrote: These days, it would be relatively simple to implement pre- and post- condition checking using decorators, and indeed one of the motivating use- cases for function annotations in Python 3 is to allow such things. http://www.python.org/dev/peps/pep-3107/ (Function annotations are perhaps the best Python feature that nobody uses.) This is awesome. Heh, everybody has one of two reactions: "This is awesome!" "You'll add type checking to my Python code over my dead body!!!" But I'm still to see a practical use for annotations in real world code. Or indeed to think of a use for them other than type checking. At PyCon 2007 (I think), Guido was giving a keynote about the features coming in Py3k, and he couldn't remember the name "function annotations." He said, "what are they called, the things that aren't type declarations." --Ned. -- http://mail.python.org/mailman/listinfo/python-list
Re: Interface and duck typing woes
On Fri, 30 Aug 2013 06:35:47 -0400, Roy Smith wrote: > In article <52200699$0$6599$c3e8da3$54964...@news.astraweb.com>, > Steven D'Aprano wrote: > >> These days, it would be relatively simple to implement pre- and post- >> condition checking using decorators, and indeed one of the motivating >> use- cases for function annotations in Python 3 is to allow such >> things. >> >> http://www.python.org/dev/peps/pep-3107/ >> >> (Function annotations are perhaps the best Python feature that nobody >> uses.) > > This is awesome. Heh, everybody has one of two reactions: "This is awesome!" "You'll add type checking to my Python code over my dead body!!!" But I'm still to see a practical use for annotations in real world code. Or indeed to think of a use for them other than type checking. -- Steven -- http://mail.python.org/mailman/listinfo/python-list
Re: Interface and duck typing woes
In article <52200699$0$6599$c3e8da3$54964...@news.astraweb.com>, Steven D'Aprano wrote: > These days, it would be relatively simple to implement pre- and post- > condition checking using decorators, and indeed one of the motivating use- > cases for function annotations in Python 3 is to allow such things. > > http://www.python.org/dev/peps/pep-3107/ > > (Function annotations are perhaps the best Python feature that nobody > uses.) This is awesome. -- http://mail.python.org/mailman/listinfo/python-list
Re: Interface and duck typing woes
On Thursday, August 29, 2013 12:09:22 AM UTC+3, Joe Junior wrote: > While designing a simple library, I found myself asking a > > philosophical question: to check or not to check the parameter's > > interface? > Design by contract discipline says: do not. > > > I think that, considering it is Python, the usual answer would be > > "no", but here is the situation that got me thinking: > > > > class Flock: > > > > def __init__(self): > > self.ducks= [] > > > > def do_stuff(self): > > for duck in self.ducks: > > duck.quack() > > > > class Duck: > > > > def quack(self): > > #quack-quack > > pass > > > > f = Flock() > > d = Duck() > > f.ducks.append(d) > > f.do_stuff() > > > > Ok, no big deal there, the problem is if the user forgets to implement > > the quack() method. The stack trace would complain that "duck.quack()" > > is wrong, but that can happen hundreds of lines after the user > > actually added the object to the Flock, and it can be hard to find out > > what is happening and which object is wrong. > > > > Of course I don't want to check isistance(), I like duck typing, but > > should I check if hasattr() and callable() before adding to the > > container? What is the pythonic way to deal with it? Am I worrying too > > much ;-)? > > > > Thanks, > > > > Joe -- http://mail.python.org/mailman/listinfo/python-list
Re: Interface and duck typing woes
On Thu, 29 Aug 2013 09:40:32 -0300, Joe Junior wrote: > Well, the main reason for me asking this question here was because of > the Java/C#/Whatever developer in me craving for an Interface for the > container's items, and I noticed that I'm not alone in this. But I was > actually expecting the "We're all consenting adults, here", I guess I > just needed the confirmation :-) > > Another reason for this question is that I read some people saying they > wouldn't use python for large projects, and they always point at the > lack of Interfaces as a concern. I actually disagree, but I can see > their point. What do you think? Interfaces aren't a built-in part of the language, but big frameworks like Zope and Twisted include them. See for example discussion here: http://dirtsimple.org/2004/12/python-interfaces-are-not-java.html In a more ad-hoc manner, there are recipes for interface-like functionality. For example, from the Python Cookbook, we have this: http://code.activestate.com/recipes/52291 It's a myth that Python is entirely opposed to type-checking. Many built- ins do it. Way back in Python 1.5, Python's creator Guido van Rossum wrote an essay describing a way to implement Eiffel-like pre- and post- condition checking: http://www.python.org/doc/essays/metaclasses/ These days, it would be relatively simple to implement pre- and post- condition checking using decorators, and indeed one of the motivating use- cases for function annotations in Python 3 is to allow such things. http://www.python.org/dev/peps/pep-3107/ (Function annotations are perhaps the best Python feature that nobody uses.) -- Steven -- http://mail.python.org/mailman/listinfo/python-list
Re: Interface and duck typing woes
On 29/08/2013 10:40 PM, Joe Junior wrote: Another reason for this question is that I read some people saying they wouldn't use python for large projects, and they always point at the lack of Interfaces as a concern. I actually disagree, but I can see their point. What do you think? Having worked on large Python projects both with & without interfaces, it's definitely possible with either approach. It certainly isn't lacking in for support for them: http://docs.zope.org/zope.interface/ -- http://mail.python.org/mailman/listinfo/python-list
Re: Interface and duck typing woes
On 29 August 2013 10:07, Chris Angelico wrote: > Hmm. l don't know of any good articles off-hand. But what I'm talking > about is simply developing the skill of reading exceptions, plus a few > simple things like knowing where it's appropriate to catch-and-log; > sometimes, what that means is actually writing some code to (for > example) email you whenever there's an exception, but more likely it > means writing no code at all, and just looking at STDERR of your live > usage. Works really well for >95% of Python scripts. > > The most important thing to consider is: What happens if my code > doesn't run all the way through? Is it safe for this to run part way, > then bomb with an exception? For many scripts, it's pretty easy: fix > the problem and rerun the script, and it'll completely rewrite its > output file. For others, this is a good reason for putting all your > "real data" into a transactional database - you begin a transaction at > the top, don't commit till the end, and if an exception kills your > script, your transaction will be rolled back. I have a system for > patching our database based on a script (written in Pike, not Python, > but the same applies); if I have any sort of critical failure in the > patch script, it'll bomb out as soon as I test it - but since I use > PostgreSQL, all that DDL (eg "ALTER TABLE") is covered by > transactional integrity (which it isn't with MySQL - another reason to > be wary of MySQL), so my patch will be backed out, and I can fix it > and start over. I don't need to have a Look Before You Leap approach > to database changes - I can simply do stuff, and if it crashes, all's > well. (That same script also has a system for catching errors at a > mid-level point that means that the process doesn't terminate when > there's an error; it supports full code reload, so once I fix the > patch, I send the process a SIGHUP and it fetches from disk again.) > *That* is error handling the safe way. > Oh, I get it! Thanks. -- http://mail.python.org/mailman/listinfo/python-list
Re: Interface and duck typing woes
On Thu, Aug 29, 2013 at 10:40 PM, Joe Junior wrote: > @ChrisA >>Do you believe that you can write code to catch every bug you might >>make? If so, you are naive and probably haven't spent much time >>programming yet :) And if not, then you must acknowledge that bugs >>WILL happen; therefore you will need to cope with them after the >>event. So rather than trying to prevent them all, just improve your >>means of coping, and you'll accomplish the same end with much less >>trouble. > > Oh, no! I'm not that presumptuous (or naive)! But what do you mean by > "improve means of coping"? Do you know any article on the subject you > could point me? Hmm. l don't know of any good articles off-hand. But what I'm talking about is simply developing the skill of reading exceptions, plus a few simple things like knowing where it's appropriate to catch-and-log; sometimes, what that means is actually writing some code to (for example) email you whenever there's an exception, but more likely it means writing no code at all, and just looking at STDERR of your live usage. Works really well for >95% of Python scripts. The most important thing to consider is: What happens if my code doesn't run all the way through? Is it safe for this to run part way, then bomb with an exception? For many scripts, it's pretty easy: fix the problem and rerun the script, and it'll completely rewrite its output file. For others, this is a good reason for putting all your "real data" into a transactional database - you begin a transaction at the top, don't commit till the end, and if an exception kills your script, your transaction will be rolled back. I have a system for patching our database based on a script (written in Pike, not Python, but the same applies); if I have any sort of critical failure in the patch script, it'll bomb out as soon as I test it - but since I use PostgreSQL, all that DDL (eg "ALTER TABLE") is covered by transactional integrity (which it isn't with MySQL - another reason to be wary of MySQL), so my patch will be backed out, and I can fix it and start over. I don't need to have a Look Before You Leap approach to database changes - I can simply do stuff, and if it crashes, all's well. (That same script also has a system for catching errors at a mid-level point that means that the process doesn't terminate when there's an error; it supports full code reload, so once I fix the patch, I send the process a SIGHUP and it fetches from disk again.) *That* is error handling the safe way. ChrisA -- http://mail.python.org/mailman/listinfo/python-list
Re: Interface and duck typing woes
Well, the main reason for me asking this question here was because of the Java/C#/Whatever developer in me craving for an Interface for the container's items, and I noticed that I'm not alone in this. But I was actually expecting the "We're all consenting adults, here", I guess I just needed the confirmation :-) Another reason for this question is that I read some people saying they wouldn't use python for large projects, and they always point at the lack of Interfaces as a concern. I actually disagree, but I can see their point. What do you think? @Nobody >> Of course I don't want to check isistance(), I like duck typing, but >> should I check if hasattr() and callable() before adding to the container? >That won't tell you if the object has a quack() method but with >incompatible semantics (e.g. wrong number or types of arguments). Yeah, didn't think about that, it's kinda swimming upstream! Definitely it is more hassle than it is worth. @ChrisA >Do you believe that you can write code to catch every bug you might >make? If so, you are naive and probably haven't spent much time >programming yet :) And if not, then you must acknowledge that bugs >WILL happen; therefore you will need to cope with them after the >event. So rather than trying to prevent them all, just improve your >means of coping, and you'll accomplish the same end with much less >trouble. Oh, no! I'm not that presumptuous (or naive)! But what do you mean by "improve means of coping"? Do you know any article on the subject you could point me? @Steven >> Of course I don't want to check isistance(), I like duck typing, but >> should I check if hasattr() and callable() before adding to the >> container? What is the pythonic way to deal with it? Am I worrying too >> much ;-)? >Yes :-) Well, thanks! :-) And thanks for the article. -- http://mail.python.org/mailman/listinfo/python-list
Re: Interface and duck typing woes
On Wed, 28 Aug 2013 18:09:22 -0300, Joe Junior wrote: > Of course I don't want to check isistance(), I like duck typing, but > should I check if hasattr() and callable() before adding to the container? That won't tell you if the object has a quack() method but with incompatible semantics (e.g. wrong number or types of arguments). > What is the pythonic way to deal with it? Ignore it. If you want early type checking, use a statically-typed language. -- http://mail.python.org/mailman/listinfo/python-list
Re: Interface and duck typing woes
On Thu, 29 Aug 2013 08:31:25 +0200, Fabrice POMBET wrote: > I am no depository of the pythonic way to think(tm) but I would create > flock and inherit Duck from flock, or possibly set Flock as a method of > ducks. Neither of those are good design. Donald is an individual Duck, he is not a flock of ducks. isinstance(donald, Flock) should return False, not True. Likewise Donald has wings, a beak, even a sailor suit (but no pants). He does not have a Flock. hasattr(donald, 'Flock') should return False. > that would look like this: > > class Flock(): > def __init__(self, flock): > self.flock=flock This puts all the responsibility for creating the flock outside the class. As you show below, you have to do this: flock=[] flock.append(Duck('Donald')) before calling Flock(flock). In this case, what is the point of the Flock class? It doesn't do anything. You might as well just work with the list. > class Duck(Flock): > def __init(self, flock): > super().__init__(flock) This design makes no sense. Presumably Duck should have an attribute "name". That's how you seem to be using it below, when you create Duck("Donald"). But then you pass the name of the individual Duck up to the parent Flock. If Donald, Daffy and Daisy join a flock, why should the Flock be named "Donald"? Why should it have a name at all? > then you only need to create some functions for any object to display > the lists and or dicts that you will create outside these classes, in > the main or in another function... > > you just instantiate them like that: > > Donald=Duck('Donald') > or (rather): > flock=[] > flock.append(Duck('Donald')) I think, rather, a better approach is: class Flock: def __init__(self, *birds): self.birds = [] # no up-front type checking self.birds.extend(birds) # --- or if you prefer Look Before You Leap --- for bird in birds: if isinstance(Duck, bird): self.birds.append(bird) def quack_all(self): for bird in self.birds: bird.quack() class Duck: def __init__(self, name): self.name = name def quack(self): print "%s quacks" % self.name -- Steven -- http://mail.python.org/mailman/listinfo/python-list
Re: Interface and duck typing woes
On Thu, Aug 29, 2013 at 4:31 PM, Fabrice POMBET wrote: > I am no depository of the pythonic way to think(tm) but I would create flock > and inherit Duck from flock, or possibly set Flock as a method of ducks. > Why should a Duck _be_ a Flock? They are quite different. No, a flock _has_ a duck (or rather, a number of ducks). ChrisA -- http://mail.python.org/mailman/listinfo/python-list
Re: Interface and duck typing woes
Le 29 août 2013 à 00:56, python-list-requ...@python.org a écrit : """While designing a simple library, I found myself asking a philosophical question: to check or not to check the parameter's interface? I think that, considering it is Python, the usual answer would be "no", but here is the situation that got me thinking: class Flock: def __init__(self): self.ducks= [] def do_stuff(self): for duck in self.ducks: duck.quack() class Duck: def quack(self): #quack-quack pass f = Flock() d = Duck() f.ducks.append(d) f.do_stuff() Ok, no big deal there, the problem is if the user forgets to implement the quack() method. The stack trace would complain that "duck.quack()" is wrong, but that can happen hundreds of lines after the user actually added the object to the Flock, and it can be hard to find out what is happening and which object is wrong. Of course I don't want to check isistance(), I like duck typing, but should I check if hasattr() and callable() before adding to the container? What is the pythonic way to deal with it? Am I worrying too much ;-)? Thanks, Joe""" Hey Joe, I am no depository of the pythonic way to think(tm) but I would create flock and inherit Duck from flock, or possibly set Flock as a method of ducks. that would look like this: class Flock(): def __init__(self, flock): self.flock=flock class Duck(Flock): def __init(self, flock): super().__init__(flock) then you only need to create some functions for any object to display the lists and or dicts that you will create outside these classes, in the main or in another function... you just instantiate them like that: Donald=Duck('Donald') or (rather): flock=[] flock.append(Duck('Donald')) one big advantage with this method is, you can creat plenty of other bird classes and append them to a list. Alternatively, you could have just one class Flock and then set duck as an attribute of flock, and set a list of your flock as a private attribute (the self.duck thing in your code... Well... Could be handled in a better way...) but that is another story, the one before is way simpler for your purpose. -- http://mail.python.org/mailman/listinfo/python-list
Re: Interface and duck typing woes
On Thu, 29 Aug 2013 11:39:25 +1000, Chris Angelico wrote: > The novice thinks his primary job is to stop the program from crashing. > The expert knows that a crash is just another way for things to go > wrong, and one of the easiest to deal with. "I find it amusing when novice programmers believe their main job is preventing programs from crashing. ... More experienced programmers realize that correct code is great, code that crashes could use improvement, but incorrect code that doesn’t crash is a horrible nightmare." http://cdsmith.wordpress.com/2011/01/09/an-old-article-i-wrote/ Anyone who hasn't already done so, you should read the whole article. It's about static versus dynamic typing, testing, proving correctness, and how they all fit in together. -- Steven -- http://mail.python.org/mailman/listinfo/python-list
Re: Interface and duck typing woes
On Thu, Aug 29, 2013 at 11:20 AM, Cameron Simpson wrote: > However, when working in Java its type strictness caught a great > many simple brainfart logic errors by checking function signatures; > typically calling the wrong function/method or mangling arguments. > Getting this stuff up front was handy. It certainly is useful, which is why I like a language with declared types. But it's not everything, and it's certainly far from sufficient. So once you've decided that run-time errors are normal, you write code with that in mind (in a web server, for instance, you'd have some code around the outside that catches and logs errors and returns a 500 to the client), and then you don't stress about them. Any you can catch early, do so, but don't put more effort into catching errors early than you save by not having them later. The novice thinks his primary job is to stop the program from crashing. The expert knows that a crash is just another way for things to go wrong, and one of the easiest to deal with. ChrisA -- http://mail.python.org/mailman/listinfo/python-list
Re: Interface and duck typing woes
In article , Cameron Simpson wrote: > Anyway, I digress. My point is that there are plusses to having > signature/type checking at coding time. It is not the Python Way, > but I surely cannot be alone in sometimes being frustrated chasing > a deeply nested runtime error that static type checking might have > found up front. One time when I really do miss static typing (and often emulate by sprinkling isinstance() assertions into my functions) is when I do a big refactoring. I'll change (to pick a real example) Song.get(id) from taking an integer to taking an ObjectId. I'll hunt through my source code to find all the places where I call Song.get(), but usually I'll miss a few. The assertions will help me catch that quickly because I'll get an easy to understand exception thrown right at the first point of contact, rather than something cryptic happening 12 stack frames down, deep in the database layer. -- http://mail.python.org/mailman/listinfo/python-list
Re: Interface and duck typing woes
On 29Aug2013 09:17, Chris Angelico wrote: | On Thu, Aug 29, 2013 at 7:54 AM, Terry Reedy wrote: | > Depending on who the users will be, I might just not worry about it until an | > exception is raised. If you try to protect against everything that you might | > do wrong, you are on the road to madness, as the protection code might also | > be buggy. (Too much testing has the same problem ;-). | | I'd go further. | | Do you believe that you can write code to catch every bug you might | make? If so, you are naive and probably haven't spent much time | programming yet :) And if not, then you must acknowledge that bugs | WILL happen; therefore you will need to cope with them after the | event. So rather than trying to prevent them all, just improve your | means of coping, and you'll accomplish the same end with much less | trouble. I'm not so extreme. Yes, of course certain things will only show at runtime and you should be prepared to have to deal with that. However, when working in Java its type strictness caught a great many simple brainfart logic errors by checking function signatures; typically calling the wrong function/method or mangling arguments. Getting this stuff up front was handy. Of course there's a price there in terms of flexibility and all that wordy stuff defining the functions in the first place. As an aside, you can also get a lot of this checking in C with aggressive linting and making a bunch of macros like: #define CNULL ((char *)NULL) #define CPNULL ((char **)NULL) and so forth as needed - lint can then catch a lot of otherwise unchecked comparisons. Anyway, I digress. My point is that there are plusses to having signature/type checking at coding time. It is not the Python Way, but I surely cannot be alone in sometimes being frustrated chasing a deeply nested runtime error that static type checking might have found up front. Cheers, -- Cameron Simpson "waste cycles drawing trendy 3D junk" - Mac Eudora v3 config option -- http://mail.python.org/mailman/listinfo/python-list
Re: Interface and duck typing woes
On Wed, 28 Aug 2013 18:09:22 -0300, Joe Junior wrote: > While designing a simple library, I found myself asking a philosophical > question: to check or not to check the parameter's interface? The only correct answer to that is, "Yes no maybe". :-) > I think that, considering it is Python, the usual answer would be "no", > but here is the situation that got me thinking: > > class Flock: > > def __init__(self): > self.ducks= [] > > def do_stuff(self): > for duck in self.ducks: > duck.quack() > > class Duck: > > def quack(self): > #quack-quack > pass > > f = Flock() > d = Duck() > f.ducks.append(d) > f.do_stuff() > > Ok, no big deal there, the problem is if the user forgets to implement > the quack() method. The stack trace would complain that "duck.quack()" > is wrong, but that can happen hundreds of lines after the user actually > added the object to the Flock, and it can be hard to find out what is > happening and which object is wrong. True, but that's a good case for improving the error message, or using a debugger. Here is Flock.do_stuff re-written to give a more verbose/useful error message: def do_stuff(self): for i, duck in enumerate(self.ducks): try: duck.quack() except AttributeError: raise DuckError( 'object %r at index %d has no quack' % (duck, i) ) Okay, seeing the index is useful. But we would have got nearly as much information from the AttributeError traceback, minus the index: py> (42).quack() Traceback (most recent call last): File "", line 1, in AttributeError: 'int' object has no attribute 'quack' So how much extra work are you prepared to put in to make a rare occurrence (passing a magpie instead of a duck) easier to debug? Since errors are presumably rare, maybe the answer is "not a lot of extra work". But if the consequence of an error is catastrophic ("for want of a duck quacking, the nuclear reactor explodes, making the northern hemisphere uninhabitable"), maybe the answer is "as much as it takes". Other questions: what happens if duck.quack is buggy and raises AttributeError? A good question, but just how far should we go in worrying about things like this? What happens if duck.quack is buggy and raises StopIteration? Sometimes the right reaction is to deal with it if and when it actually occurs. In other words, wait for the bug report before trying to fix it. ("Fix it" may mean telling people "don't do that!".) > Of course I don't want to check isistance(), I like duck typing, but > should I check if hasattr() and callable() before adding to the > container? What is the pythonic way to deal with it? Am I worrying too > much ;-)? Yes :-) Except in the (rare?) case that you aren't worrying enough, in which case you can check hasattr and callable up front, or do whatever other tests you feel the need to check. It depends on the specific code you are writing. -- Steven -- http://mail.python.org/mailman/listinfo/python-list
Re: Interface and duck typing woes
On Thu, Aug 29, 2013 at 7:54 AM, Terry Reedy wrote: > Depending on who the users will be, I might just not worry about it until an > exception is raised. If you try to protect against everything that you might > do wrong, you are on the road to madness, as the protection code might also > be buggy. (Too much testing has the same problem ;-). I'd go further. Do you believe that you can write code to catch every bug you might make? If so, you are naive and probably haven't spent much time programming yet :) And if not, then you must acknowledge that bugs WILL happen; therefore you will need to cope with them after the event. So rather than trying to prevent them all, just improve your means of coping, and you'll accomplish the same end with much less trouble. At this point I could go off into a lengthy discussion of philosophy and original sin (not "original SYN", which is a different thing altogether), but anyone who's ever written bug-handling code will understand what I mean already :) ChrisA -- http://mail.python.org/mailman/listinfo/python-list
Re: Interface and duck typing woes
On 8/28/2013 5:09 PM, Joe Junior wrote: While designing a simple library, I found myself asking a philosophical question: to check or not to check the parameter's interface? I think that, considering it is Python, the usual answer would be "no", but here is the situation that got me thinking: class Flock: def __init__(self): self.ducks= [] def do_stuff(self): for duck in self.ducks: duck.quack() class Duck: def quack(self): #quack-quack pass f = Flock() d = Duck() f.ducks.append(d) f.do_stuff() Ok, no big deal there, the problem is if the user forgets to implement the quack() method. The stack trace would complain that "duck.quack()" is wrong, but that can happen hundreds of lines after the user actually added the object to the Flock, and it can be hard to find out what is happening and which object is wrong. Of course I don't want to check isistance(), I like duck typing, but should I check if hasattr() and callable() before adding to the container? What is the pythonic way to deal with it? Am I worrying too much ;-)? You could underscore '_ducks' and add a .add_duck method with the checks you suggest. Or wrap 'duck.quack()' in try-except and log or warn (or even raise) on AttributeError or TypeError (not callable) with an informative message. Grepping for 'ducks.append(' will find all locations where a non-duck might have been added. Depending on who the users will be, I might just not worry about it until an exception is raised. If you try to protect against everything that you might do wrong, you are on the road to madness, as the protection code might also be buggy. (Too much testing has the same problem ;-). -- Terry Jan Reedy -- http://mail.python.org/mailman/listinfo/python-list
Interface and duck typing woes
While designing a simple library, I found myself asking a philosophical question: to check or not to check the parameter's interface? I think that, considering it is Python, the usual answer would be "no", but here is the situation that got me thinking: class Flock: def __init__(self): self.ducks= [] def do_stuff(self): for duck in self.ducks: duck.quack() class Duck: def quack(self): #quack-quack pass f = Flock() d = Duck() f.ducks.append(d) f.do_stuff() Ok, no big deal there, the problem is if the user forgets to implement the quack() method. The stack trace would complain that "duck.quack()" is wrong, but that can happen hundreds of lines after the user actually added the object to the Flock, and it can be hard to find out what is happening and which object is wrong. Of course I don't want to check isistance(), I like duck typing, but should I check if hasattr() and callable() before adding to the container? What is the pythonic way to deal with it? Am I worrying too much ;-)? Thanks, Joe -- http://mail.python.org/mailman/listinfo/python-list