Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #53218 > unrolled thread

Re: Interface and duck typing woes

Started byFabrice POMBET <fp2161@gmail.com>
First post2013-08-29 08:31 +0200
Last post2013-08-29 07:53 +0000
Articles 2 — 2 participants

Back to article view | Back to comp.lang.python

This discussion starts older than the indexed window; earlier articles aren't shown. The article labeled Started by below is the oldest one visible, not the original post.


Contents

  Re: Interface and duck typing woes Fabrice POMBET <fp2161@gmail.com> - 2013-08-29 08:31 +0200
    Re: Interface and duck typing woes Steven D'Aprano <steve@pearwood.info> - 2013-08-29 07:53 +0000

#53218 — Re: Interface and duck typing woes

FromFabrice POMBET <fp2161@gmail.com>
Date2013-08-29 08:31 +0200
SubjectRe: Interface and duck typing woes
Message-ID<mailman.345.1377760173.19984.python-list@python.org>
Le 29 août 2013 à 00:56, python-list-request@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.

[toc] | [next] | [standalone]


#53225

FromSteven D'Aprano <steve@pearwood.info>
Date2013-08-29 07:53 +0000
Message-ID<521efde6$0$2743$c3e8da3$76491128@news.astraweb.com>
In reply to#53218
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

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.python


csiph-web