Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.python > #53218 > unrolled thread
| Started by | Fabrice POMBET <fp2161@gmail.com> |
|---|---|
| First post | 2013-08-29 08:31 +0200 |
| Last post | 2013-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.
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
| From | Fabrice POMBET <fp2161@gmail.com> |
|---|---|
| Date | 2013-08-29 08:31 +0200 |
| Subject | Re: 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]
| From | Steven D'Aprano <steve@pearwood.info> |
|---|---|
| Date | 2013-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