FAQ
Hi,
Here's a framework for the questions:

--- In a module, part of an API ---
class Basis ( object ):
def foo ( self, arg ):
pass

--- In user's own code ---
class Child ( Basis ):
def foo ( self, not, sure ):
...


Question 1:

Given that the user of the API can choose to override foo() or not, how can
I control the signature that they use? In the example the user has chosen
bad arguments and Python will complain, but it's describing the sig of the
*overridden* method and not the one in the parent class.

Is there some way I can control the error message to make it clear to the
user that they are using the signature of foo() incorrectly?

Question 2:

Say I am in class Basis, doing a loop and I have a list of Child objects. I
want to run the foo() method for each one that *has* a foo() method. i.e.
user has done this:

class Sam ( Child ):
...
*Sam does not define foo()

class Judy ( Child ):
def foo ( self, arg ):
...
* Judy does define foo()

Instances of Sam and Judy have been put into the list (within the instance)
of Basis. I want Basis to detect that Judy has foo() and run it.

I can handle question 2 by using a flag that must be set by the user.
Something like:
class Judy ( child ):
def __init__( self ):
self.pleaseCallFoo = true

And now, Basis can check for that var and only then call foo(), but this is
ugly and means more for the user to learn API-wise.

Any ideas?
/d

Search Discussions

  • Paul McGuire at Nov 16, 2007 at 5:10 pm

    On Nov 16, 11:03 am, Donn Ingle wrote:
    Hi,
    Here's a framework for the questions:

    --- In a module, part of an API ---
    class Basis ( object ):
    def foo ( self, arg ):
    pass

    --- In user's own code ---
    class Child ( Basis ):
    def foo ( self, not, sure ):
    ...

    Question 1:

    Given that the user of the API can choose to override foo() or not, how can
    I control the signature that they use? In the example the user has chosen
    bad arguments and Python will complain, but it's describing the sig of the
    *overridden* method and not the one in the parent class.
    Actually, Python is complaining about your user's poor choice of
    argument names. 'not' is a reserved keyword. Change it to 'naught' or
    'knot' or 'not_' and Python will accept this just fine.

    Whether this is a good idea or not is a separate question. But given
    Python's philosophy of "you are the human, so you must know what you
    are doing" (which is both an assumption and a directive), I don't
    think you will find much language machinery to prevent it.

    -- Paul


    -- Paul
  • Donn Ingle at Nov 16, 2007 at 5:25 pm

    Actually, Python is complaining about your user's poor choice of
    argument names. 'not' is a reserved keyword.
    My example was poor, but my actual test code did't use 'not'. Python simply
    checks the use of foo() to the local sig of foo() and does not go up the
    chain. This is understandable and your next answer is more-or-less what I
    was expecting.
    Python's philosophy of "you are the human, so you must know what you
    are doing" (which is both an assumption and a directive), I don't
    think you will find much language machinery to prevent it.
    Yeah. I guess I was hoping there'd be some clever trick to do it.

    /d
  • BearophileHUGS at Nov 16, 2007 at 5:22 pm

    Donn Ingle:
    Say I am in class Basis, doing a loop and I have a list of Child objects. I
    want to run the foo() method for each one that *has* a foo() method.
    This may help (on an old Python version):
    class Sam: pass
    ...
    class Judy:
    ... def foo(self): pass
    ...
    children = [Sam(), Judy(), Sam()]
    for child in children: hasattr(child, "foo")
    ...
    False
    True
    False

    Bye,
    bearophile
  • Donn Ingle at Nov 16, 2007 at 5:35 pm

    This may help (on an old Python version):
    class Sam: pass
    class Judy:
    ... def foo(self): pass
    ...
    children = [Sam(), Judy(), Sam()]
    for child in children: hasattr(child, "foo")
    ...
    False
    True
    False
    That's not what my tests are showing. While Sam has no foo, it's coming from
    (in my OP) Child (which is the parent class), so hasattr(Sam(),"foo") is
    returning True.

    /d
  • Davisn90210 at Nov 16, 2007 at 8:29 pm

    On Nov 16, 11:35 am, Donn Ingle wrote:
    This may help (on an old Python version):
    class Sam: pass
    class Judy:
    ... def foo(self): pass
    ...
    children = [Sam(), Judy(), Sam()]
    for child in children: hasattr(child, "foo")
    ...
    False
    True
    False
    That's not what my tests are showing. While Sam has no foo, it's coming from
    (in my OP) Child (which is the parent class), so hasattr(Sam(),"foo") is
    returning True.

    /d
    But also in your OP: "I want to run the foo() method for each one that
    *has* a foo() method ...." So hasattr(child, "foo") really does
    answer the question as posed, even if it's not really what you want.
    I am curious as to why you want to go through such contortions. What
    do you gain. What happens, for example, if a subclass of Judy is
    passed in that does not override foo? Should foo be called in that
    case or not?

    --Nathan Davis
  • Donn Ingle at Nov 17, 2007 at 4:56 am

    I am curious as to why you want to go through such contortions. ?What
    do you gain.
    for obj in list:
    if obj has a foo() method:
    a = something
    b = figureitout ( )
    object.foo ( a, b )

    I am accepting objects of any class on a stack. Depending on their nature I
    want to call certain methods within them. They can provide these methods or
    not.
    What happens, for example, if a subclass of Judy is
    passed in that does not override foo? ?Should foo be called in that
    case or not?
    No.

    Bruno has given me a good solution:

    for obj in list:
    if 'foo' in obj.__class__.__dict__:
    etc.

    Although I am concerned that it's a loop ('in') and so may be slower than
    some other way to detect foo().

    So, that's the story.

    /d
  • Gabriel Genellina at Nov 17, 2007 at 8:08 am
    En Sat, 17 Nov 2007 01:56:22 -0300, Donn Ingle <donn.ingle at gmail.com>
    escribi?:
    for obj in list:
    if 'foo' in obj.__class__.__dict__:
    etc.

    Although I am concerned that it's a loop ('in') and so may be slower than
    some other way to detect foo().
    'in' for dictionaries is fast and runs in constant time. You may be
    thinking about 'in' for lists, that runs in time proportional to the
    number of elements.

    --
    Gabriel Genellina
  • Peter Otten at Nov 17, 2007 at 9:51 am

    Donn Ingle wrote:

    I am curious as to why you want to go through such contortions. ?What
    do you gain.
    for obj in list:
    if obj has a foo() method:
    a = something
    b = figureitout ( )
    object.foo ( a, b )

    I am accepting objects of any class on a stack. Depending on their nature I
    want to call certain methods within them. They can provide these methods or
    not.
    What happens, for example, if a subclass of Judy is
    passed in that does not override foo? ?Should foo be called in that
    case or not?
    No.
    Hmm, you are missing the point of inheritance. Behaviour not
    meant to be shared by all subclasses should not be implemented in
    the base class, i. e. either Sam should not inherit from Child or Child
    should not implement foo().

    However, here is another hack to hide an inherited method:
    class Child(object):
    ... def foo(self): print "Child's foo"
    ... def __str__(self): return self.__class__.__name__
    ...
    class Sam(Child):
    ... @property
    ... def foo(self): raise AttributeError
    ...
    class Judy(Child):
    ... def foo(self): print "Judy's foo"
    ...
    for item in [Sam(), Judy()]:
    ... try:
    ... foo = item.foo
    ... except AttributeError:
    ... print "no foo for", item
    ... else:
    ... foo()
    ...
    no foo for Sam
    Judy's foo

    If you find try ... except too verbose -- it works with hasattr(), too.
    Bruno has given me a good solution:

    for obj in list:
    if 'foo' in obj.__class__.__dict__:
    etc.

    Although I am concerned that it's a loop ('in') and so may be slower
    than some other way to detect foo().
    __dict__ is a dictionary (who would have thought), the "in" operator
    therefore does not trigger a loop and is very fast.

    Peter
  • Donn Ingle at Nov 17, 2007 at 10:45 am
    Thanks, good tips all-round. I have it working okay at the moment with all
    the suggestions. It may break in future, but that's another day :)


    /d
  • Bruno Desthuilliers at Nov 16, 2007 at 5:28 pm

    Donn Ingle a ?crit :
    Hi,
    Here's a framework for the questions:

    --- In a module, part of an API ---
    class Basis ( object ):
    def foo ( self, arg ):
    pass

    --- In user's own code ---
    class Child ( Basis ):
    def foo ( self, not, sure ):
    ...


    Question 1:

    Given that the user of the API can choose to override foo() or not, how can
    I control the signature that they use?
    While technically possible (using inspect.getargspec), trying to make
    your code idiot-proof is a lost fight and a pure waste of time.
    Question 2:

    Say I am in class Basis, doing a loop and I have a list of Child objects. I
    want to run the foo() method for each one that *has* a foo() method. i.e.
    user has done this:

    class Sam ( Child ):
    ...
    *Sam does not define foo()

    class Judy ( Child ):
    def foo ( self, arg ):
    ...
    * Judy does define foo()

    Instances of Sam and Judy have been put into the list (within the instance)
    of Basis. I want Basis to detect that Judy has foo() and run it.

    I can handle question 2 by using a flag that must be set by the user.
    Something like:
    class Judy ( child ):
    def __init__( self ):
    self.pleaseCallFoo = true

    And now, Basis can check for that var and only then call foo(), but this is
    ugly and means more for the user to learn API-wise. Indeed.
    Any ideas?
    Quite a few, but I don't have enough context to tell which one would be
    the best - nor why you want to do such a thing. Anyway, the simplest is
    to just check :

    for child in self.childrens:
    if 'foo' in child.__class__.__dict__:
    child.foo()

    but this won't call foo for :

    class Dude(Judy):
    pass

    Don't know if that's what you want. If not (ie, you want to call
    child.foo if foo is not Basis.foo), then:

    for child in self.childrens:
    if child.foo.im_func is not self.foo.im_func:
    child.foo()

    HTH
  • Donn Ingle at Nov 16, 2007 at 5:46 pm

    for child in self.childrens:
    if 'foo' in child.__class__.__dict__:
    child.foo()
    Bruno, you're the man! I really must take the time to look into all those
    under-under score things!

    Thanks.

    /d
  • Bruno Desthuilliers at Nov 16, 2007 at 6:19 pm

    Donn Ingle a ?crit :
    for child in self.childrens:
    if 'foo' in child.__class__.__dict__:
    child.foo()
    Bruno, you're the man! I really must take the time to look into all those
    under-under score things!
    Knowing Python's object model can help, indeed !-)

    Now while this kind of stuff is ok in the low-level parts of a
    framework, it shouldn't be seen too much in application code IMHO.
  • Steven D'Aprano at Nov 16, 2007 at 10:03 pm

    On Fri, 16 Nov 2007 18:28:59 +0100, Bruno Desthuilliers wrote:

    Question 1:

    Given that the user of the API can choose to override foo() or not, how
    can I control the signature that they use?
    While technically possible (using inspect.getargspec), trying to make
    your code idiot-proof is a lost fight and a pure waste of time.

    Worse: it's actually counter-productive!

    The whole idea of being able to subclass a class means that the user
    should be able to override foo() *including* the signature. Why do you
    want to stop them? It's their subclass, not yours. You don't know what
    arguments it needs.

    Let me give a practical example: in mathematics there is a construct
    known as a continued fraction. What it is isn't especially important, if
    you're curious you can google for it. If you were defining a class for
    continued fractions, you might do this:

    class ContinuedFraction(object):
    def __init__(self, list_of_numerators, list_of_denominators):
    pass
    # lots of other methods

    cf = ContinuedFraction([3, 7, 2, 8, 9, 5], [2, 3, 1, 5, 3, 7])

    If I wanted to subclass your ContinuedFraction class to provide regular
    continued fractions, I could do this:

    class RegularCF(ContinuedFraction):
    def __init__(self, *denominators):
    numerators = [1]*len(denominators)
    super(RegularCF, self).__init__(numerators, denominators)
    # all other methods are inherited from super-class without change

    cf = RegularCF(4, 9, 1, 2, 6, 3)


    But if you did what you're proposing to do, I couldn't do that. I'd need
    to do something silly like this:

    class RegularCF(ContinuedFraction):
    def __init__(self, list_of_numerators, list_of_denominators):
    numerators = [1]*len(list_of_denominators)
    super(RegularCF, self).__init__(numerators, list_of_denominators)

    cf = RegularCF(None, [4, 9, 1, 2, 6, 3])


    just so that the signatures matched. What a waste of time.

    And worse, what if my subclass needed *more* arguments than your
    signature provided? The hoops I would have to jump through would not only
    be flaming, they'd be spinning and flying through the air, with rotating
    knives and trip-wires.



    --
    Steven
  • George Sakkis at Nov 17, 2007 at 2:30 am

    On Nov 16, 5:03 pm, Steven D'Aprano <st... at REMOVE-THIS- cybersource.com.au> wrote:
    On Fri, 16 Nov 2007 18:28:59 +0100, Bruno Desthuilliers wrote:
    Question 1:
    Given that the user of the API can choose to override foo() or not, how
    can I control the signature that they use?
    While technically possible (using inspect.getargspec), trying to make
    your code idiot-proof is a lost fight and a pure waste of time.
    Worse: it's actually counter-productive!

    The whole idea of being able to subclass a class means that the user
    should be able to override foo() *including* the signature. Why do you
    want to stop them?
    Primarily because of this: http://en.wikipedia.org/wiki/Liskov_substitution_principle.
    Let me give a practical example:

    (snip misleading example involving __init__)
    Constructors are in general different from other regular methods
    because you refer explicitly to the class name when creating an
    instance; that is, the client writes "f = ContinuedFraction(...)" or
    "f = RegularCF(...)" so it's not necessary to have the same signature
    in __init__. For all other methods though, given that you have an
    instance x so that isinstance(x, ContinuedFraction), the client should
    be able to say x.foo(arg, kwd=v) without having to know whether
    x.__class__ is ContinuedFraction. If not, you have a leaky abstraction
    [1], i.e. in your example, a RegularCF is not really a
    ContinuedFraction.

    George


    [1] http://www.joelonsoftware.com/articles/LeakyAbstractions.html
  • Steven D'Aprano at Nov 17, 2007 at 10:20 pm

    On Fri, 16 Nov 2007 18:30:28 -0800, George Sakkis wrote:

    On Nov 16, 5:03 pm, Steven D'Aprano <st... at REMOVE-THIS-
    cybersource.com.au> wrote:
    On Fri, 16 Nov 2007 18:28:59 +0100, Bruno Desthuilliers wrote:
    Question 1:
    Given that the user of the API can choose to override foo() or not,
    how can I control the signature that they use?
    While technically possible (using inspect.getargspec), trying to make
    your code idiot-proof is a lost fight and a pure waste of time.
    Worse: it's actually counter-productive!

    The whole idea of being able to subclass a class means that the user
    should be able to override foo() *including* the signature. Why do you
    want to stop them?
    Primarily because of this:
    http://en.wikipedia.org/wiki/Liskov_substitution_principle.
    "In object-oriented programming, the Liskov substitution principle is a
    PARTICULAR definition of subtype..." [emphasis added]

    There are other definitions possible. Also be careful of confusing
    subclasses with subtypes:

    http://en.wikipedia.org/wiki/Subtype
    http://en.wikipedia.org/wiki/Subclass_%28computer_science%29

    Python doesn't have types in the sense of the Liskov substitution
    principle, because Python's subclass relationship need not imply
    substitutability. In fact, the requirement for substitutability is quite
    restrictive. (Whether it is a good thing or a bad thing is open for
    debate.)

    With duck typing and/or delegation, one might create a new class which is
    substitutable for the original class, without it being a subclass. And
    contrariwise, one might create a subclass which isn't substitutable for
    the original class. Inheritance is a *mechanism* for getting identical or
    similar behaviour without the anti-pattern of copy-and-paste programming
    (code duplication). There's no logical requirement that two objects with
    identical behaviour in one aspect must necessarily be substitutable for
    each other:

    chicken.lay_egg()
    shark.lay_egg() # some sharks lay eggs


    I don't see this as a bad thing (unless of course they are *supposed* to
    be substitutable, in which case the failure to be so is a bug).


    --
    Steven.
  • Bruno Desthuilliers at Nov 19, 2007 at 12:44 pm

    George Sakkis a ?crit :
    On Nov 16, 5:03 pm, Steven D'Aprano <st... at REMOVE-THIS-
    cybersource.com.au> wrote:
    On Fri, 16 Nov 2007 18:28:59 +0100, Bruno Desthuilliers wrote:
    Question 1:
    Given that the user of the API can choose to override foo() or not, how
    can I control the signature that they use?
    While technically possible (using inspect.getargspec), trying to make
    your code idiot-proof is a lost fight and a pure waste of time.
    Worse: it's actually counter-productive!

    The whole idea of being able to subclass a class means that the user
    should be able to override foo() *including* the signature. Why do you
    want to stop them?
    Primarily because of this: http://en.wikipedia.org/wiki/Liskov_substitution_principle.
    Let me give a practical example:

    (snip misleading example involving __init__)
    Constructors are in general different from other regular methods
    because you refer explicitly to the class name when creating an
    instance;
    Not necessarily. There are (quite a few) cases where you don't know
    which "concrete" class you're instanciating...
    that is, the client writes "f = ContinuedFraction(...)" or
    "f = RegularCF(...)" so it's not necessary to have the same signature
    in __init__.
    import platform
    cls = platform.get_the_class()
    obj = cls('yadda', 42)
  • George Sakkis at Nov 19, 2007 at 3:08 pm

    On Nov 19, 7:44 am, Bruno Desthuilliers <bruno. 42.desthuilli... at wtf.websiteburo.oops.com> wrote:
    George Sakkis a ?crit :


    On Nov 16, 5:03 pm, Steven D'Aprano <st... at REMOVE-THIS-
    cybersource.com.au> wrote:
    On Fri, 16 Nov 2007 18:28:59 +0100, Bruno Desthuilliers wrote:
    Question 1:
    Given that the user of the API can choose to override foo() or not, how
    can I control the signature that they use?
    While technically possible (using inspect.getargspec), trying to make
    your code idiot-proof is a lost fight and a pure waste of time.
    Worse: it's actually counter-productive!
    The whole idea of being able to subclass a class means that the user
    should be able to override foo() *including* the signature. Why do you
    want to stop them?
    Primarily because of this:http://en.wikipedia.org/wiki/Liskov_substitution_principle.
    Let me give a practical example:
    (snip misleading example involving __init__)
    Constructors are in general different from other regular methods
    because you refer explicitly to the class name when creating an
    instance;
    Not necessarily. There are (quite a few) cases where you don't know
    which "concrete" class you're instanciating...
    that is, the client writes "f = ContinuedFraction(...)" or
    "f = RegularCF(...)" so it's not necessary to have the same signature
    in __init__.
    import platform
    cls = platform.get_the_class()
    obj = cls('yadda', 42)
    That's why I qualified my statement with "in general" ;-) Besides,
    this emphasizes even further the need for consistent (though not
    necessarily identical) signatures in all (public) methods, which was
    my point anyway.

    George
  • Donn Ingle at Nov 17, 2007 at 4:47 am

    While technically possible (using inspect.getargspec), trying to make
    your code idiot-proof is a lost fight and a pure waste of time.
    Worse: it's actually counter-productive!
    The whole idea of being able to subclass a class means that the user
    should be able to override foo() *including* the signature.
    Steven,
    In this case, the def in question is named Draw. It's args are context and
    framenumber. The body is 'pass'. I want users to use the exact signature
    (but they can change the varnames to suit) because the draw() method is
    *not* being called by the user but *by* my API (in a timeout loop).

    So, my API is sending blah.Draw( cairo.context, currentFrame ) *to* the
    user's own object.Draw.Thereafter, whatever Cairo drawing commands they use
    in their override of Draw() is what gets drawn -- if that makes sense :)

    I guess that's the long way of saying it's a call-back function :)

    So, I'm trying to guarantee that they don't mess with it to make life easier
    for them. As Bruno has mentioned, this is up to the human and so it'll be a
    rule in the docs instead.

    /d
  • Donn Ingle at Nov 17, 2007 at 8:07 am

    This is strictly a documentation matter, in my mind. Python does not
    offer any means to enforce the calling sequence of an "override method".
    Yes, I hear you.
    You might be able to wrap YOUR calling code with a try/except block
    to trap errors if the callback doesn't like the "documented API"
    arguments.
    Good plan. Thanks, dunno why I didn't think of that!

    /d
  • Steven D'Aprano at Nov 17, 2007 at 8:18 am

    On Sat, 17 Nov 2007 06:47:18 +0200, Donn Ingle wrote:

    While technically possible (using inspect.getargspec), trying to make
    your code idiot-proof is a lost fight and a pure waste of time.
    Worse: it's actually counter-productive! The whole idea of being able
    to subclass a class means that the user should be able to override
    foo() *including* the signature.
    Steven,
    In this case, the def in question is named Draw. It's args are context
    and
    framenumber. The body is 'pass'. I want users to use the exact signature
    (but they can change the varnames to suit) because the draw() method is
    *not* being called by the user but *by* my API (in a timeout loop).
    You don't know that. How can you possibly guarantee that the user won't
    find some other use for the draw() method as well as passing it to your
    API? Maybe your application turns out to be a huge success, and people
    start extending it in all sorts of ways you never ever imagined -- or at
    least they would if you didn't needlessly lock down the classes they can
    use.

    Or, if you can't imagine that, imagine that in six months time *you*
    decide to extend the application, and have another purpose for that same
    draw() callback, but need a slightly different signature.

    Which suggests that maybe your API should specify keyword arguments
    rather than positional args. That way you can do something like this:

    # (I'm guessing) in the main video editing loop:
    blah.Draw(context=cario.context, frame=currentFrame)

    # we want to display the third frame as we draw
    blah.Draw(context=another_context, frame=3, window=preview)

    # don't forget to flip the title frame
    blah.Draw(flip=True, context=cairo.context, frame=title)


    BTW, it is a convention for method names to be lower case, and classes to
    be Title case. Seeing something like obj.Draw, most(?) Python developers
    will expect that the Draw attribute of obj is itself a class:
    class MyClass(object):
    ... class Draw(object):
    ... pass
    ...
    x = MyClass()
    x.Draw
    <class '__main__.Draw'>


    --
    Steven.
  • Donn Ingle at Nov 17, 2007 at 10:19 am

    *not* being called by the user but *by* my API (in a timeout loop).

    You don't know that. How can you possibly guarantee that the user won't
    find some other use for the draw() method
    Well, as per your good examples, I would answer that as the parameters
    passed to draw() grow in number, so the API is actually growing and so the
    draw() call will be updated. Or, other calls can be introduced like
    drawPreview() etc. (Better cos it won't break old code.)

    The way it is now, in heavy alpha :), is that the draw() is *only* called
    outwards and does not return or call parentClass.draw( self, ...) back in
    any way. It's a pure source of context.cairo_<whatever> commands.
    BTW, it is a convention for method names to be lower case, and classes to
    be Title case. Seeing something like obj.Draw, most(?) Python developers
    will expect that the Draw attribute of obj is itself a class:
    Thanks, I'm pretty damn unorganized in that way. Is it convention to do:

    class BigLetterAndCamels():
    def smallLetterAndCamels()

    or
    def smallletterandnocamels()

    ?

    /d
  • Steven D'Aprano at Nov 17, 2007 at 10:46 am

    On Sat, 17 Nov 2007 12:19:07 +0200, Donn Ingle wrote:

    BTW, it is a convention for method names to be lower case, and classes
    to be Title case. Seeing something like obj.Draw, most(?) Python
    developers will expect that the Draw attribute of obj is itself a
    class:
    Thanks, I'm pretty damn unorganized in that way. Is it convention to do:

    class BigLetterAndCamels():
    def smallLetterAndCamels()

    or
    def smallletterandnocamels()

    ?
    See the PEP and Guido's essay for recommended conventions:

    http://www.python.org/dev/peps/pep-0008/
    http://www.python.org/doc/essays/styleguide.html



    --
    Steven.
  • Bruno Desthuilliers at Nov 19, 2007 at 12:41 pm

    Steven D'Aprano a ?crit :
    On Fri, 16 Nov 2007 18:28:59 +0100, Bruno Desthuilliers wrote:

    Question 1:

    Given that the user of the API can choose to override foo() or not, how
    can I control the signature that they use?
    While technically possible (using inspect.getargspec), trying to make
    your code idiot-proof is a lost fight and a pure waste of time.

    Worse: it's actually counter-productive!

    The whole idea of being able to subclass a class means that the user
    should be able to override foo() *including* the signature.
    If you see subclassing as subtyping, the signatures should always stay
    fully compatibles.
  • J. Clifford Dyer at Nov 19, 2007 at 2:05 pm

    On Mon, Nov 19, 2007 at 01:41:46PM +0100, Bruno Desthuilliers wrote regarding Re: overriding methods - two questions:
    Steven D'Aprano a ?crit :
    On Fri, 16 Nov 2007 18:28:59 +0100, Bruno Desthuilliers wrote:

    Question 1:

    Given that the user of the API can choose to override foo() or not, how
    can I control the signature that they use?
    While technically possible (using inspect.getargspec), trying to make
    your code idiot-proof is a lost fight and a pure waste of time.

    Worse: it's actually counter-productive!

    The whole idea of being able to subclass a class means that the user
    should be able to override foo() *including* the signature.
    If you see subclassing as subtyping, the signatures should always stay
    fully compatibles.
    Isn't that more what Zope-type interfaces are for than inheritance? I'm uncertain here, but I'm not persuaded that changing signature is bad.
  • Bruno Desthuilliers at Nov 19, 2007 at 3:33 pm

    J. Clifford Dyer a ?crit :
    On Mon, Nov 19, 2007 at 01:41:46PM +0100, Bruno Desthuilliers wrote regarding Re: overriding methods - two questions:
    Steven D'Aprano a ?crit :
    On Fri, 16 Nov 2007 18:28:59 +0100, Bruno Desthuilliers wrote:

    Question 1:

    Given that the user of the API can choose to override foo() or not, how
    can I control the signature that they use?
    While technically possible (using inspect.getargspec), trying to make
    your code idiot-proof is a lost fight and a pure waste of time.
    Worse: it's actually counter-productive!

    The whole idea of being able to subclass a class means that the user
    should be able to override foo() *including* the signature.
    If you see subclassing as subtyping, the signatures should always stay
    fully compatibles.
    Isn't that more what Zope-type interfaces are for than inheritance?
    With dynamically typed languages like Python, you don't need any formal
    mechanism (zope-like interface or whatever) for subtyping to work - just
    make sure your two classes have the same public interface and it's ok.
    So indeed inheritance is first a code-reuse feature.
    I'm uncertain here, but I'm not persuaded that changing signature is
    bad.
    Depends if the subclass is supposed to be a proper subtype (according to
    LSP) too.

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
grouppython-list @
categoriespython
postedNov 16, '07 at 5:03p
activeNov 19, '07 at 3:33p
posts26
users10
websitepython.org

People

Translate

site design / logo © 2022 Grokbase