Question about isinstance()

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Mr.Rech

    Question about isinstance()

    Hi all,
    I've read some thread about isinstance(), why it is considered harmful
    and how you can achieve the same results using a coding style that
    doesn't break polymorphism etc... Since I'm trying to improve my Python
    knowledge, and I'm going to design a class hierarchy from scratch, I'd
    like to have some feedback about this from those of you much more
    experienced than me in OOP.

    Suppose I'm writing a base class with an __eq__ special methods, using
    isinstance() I would have wrote:

    class foo(object):
    ...
    def __eq__(self, other):
    return isinstance(othe r, type(self)) and self.an_attribu te ==
    other.an__attri bute

    Now, avoiding isinstace() I've written the following code:

    class foo(object):
    ...
    def __eq__(self, other):
    try:
    return self.an_attribu te == other.an_attrib ute
    except AttributeError:
    return False

    Any better way to write this method? Any suggestion?

  • Rene Pijlman

    #2
    Re: Question about isinstance()

    Mr.Rech:[color=blue]
    >Now, avoiding isinstace() I've written the following code:
    >
    >class foo(object):
    > ...
    > def __eq__(self, other):
    > try:
    > return self.an_attribu te == other.an_attrib ute
    > except AttributeError:
    > return False[/color]

    This may give unexpected results when you compare a foo with an instance
    of a completely different type that happens to have an attribute called
    'an_attribute'.

    --
    René Pijlman

    Wat wil jij worden? http://www.carrieretijger.nl

    Comment

    • Mr.Rech

      #3
      Re: Question about isinstance()

      Mmm... I've not considered such an event... Would you say it is one of
      those rare case in which isinstance() "can be used"? Any other
      suggestion?

      Thanks,
      Andrea

      Comment

      • Dave Benjamin

        #4
        Re: Question about isinstance()

        On Thu, 26 Jan 2006, Mr.Rech wrote:
        [color=blue]
        > I've read some thread about isinstance(), why it is considered harmful
        > and how you can achieve the same results using a coding style that
        > doesn't break polymorphism etc... Since I'm trying to improve my Python
        > knowledge, and I'm going to design a class hierarchy from scratch, I'd
        > like to have some feedback about this from those of you much more
        > experienced than me in OOP.[/color]

        When trying to write OO code, you should of course always be suspicious of
        any use of "isinstance ". However, it is not always "considered harmful",
        and this is one case where it is perfectly reasonable.
        [color=blue]
        > Now, avoiding isinstace() I've written the following code:
        >
        > class foo(object):
        > ...
        > def __eq__(self, other):
        > try:
        > return self.an_attribu te == other.an_attrib ute
        > except AttributeError:
        > return False[/color]

        You were better off with what you had before. Equality in this case is
        left completely open-ended, and as a result, there is no way that you can
        guarantee that "a == b" is the same as "b == a" if "a" is a "foo" and "b"
        is of unknown type. This can lead to bizarre and unpredictable behavior.

        --
        .:[ dave benjamin -( ramen/sp00 )- http://spoomusic.com/ ]:.

        "To attain knowledge, add things every day.
        To attain wisdom, remove things every day." - Lao Tzu

        Comment

        • Rocco Moretti

          #5
          Re: Question about isinstance()

          Dave Benjamin wrote:[color=blue]
          > On Thu, 26 Jan 2006, Mr.Rech wrote:
          >[color=green]
          >> Suppose I'm writing a base class with an __eq__ special methods, using
          >> isinstance() I would have wrote:
          >>
          >> class foo(object):
          >> ...
          >> def __eq__(self, other):
          >> return isinstance(othe r, type(self)) and self.an_attribu te ==
          >> other.an__attri bute[/color][/color]
          [color=blue][color=green]
          >> Now, avoiding isinstace() I've written the following code:
          >>
          >> class foo(object):
          >> ...
          >> def __eq__(self, other):
          >> try:
          >> return self.an_attribu te == other.an_attrib ute
          >> except AttributeError:
          >> return False[/color]
          >
          >
          > You were better off with what you had before. Equality in this case is
          > left completely open-ended, and as a result, there is no way that you
          > can guarantee that "a == b" is the same as "b == a" if "a" is a "foo"
          > and "b" is of unknown type. This can lead to bizarre and unpredictable
          > behavior.[/color]

          Mind explaining that better? b == a *always* calls b.__eq__(a), if it
          exists. What a.__eq__(b) is doesn't matter at that point. So you have
          the same problems either way.

          The only difference between the two is in the case where b is of an
          unrelated class and b.an_attribute exists (1). In this case, the first
          always returns False, and the second returns (a.an_attribute ==
          b.an_attribute) . Which you prefer depends on how strictly you adhere to
          duck typing.

          (1) To be honest, they also vary when a.an_attribute is undefined. The
          second always returns False, and the first raises an AttributeError.

          Comment

          • Dave Benjamin

            #6
            Re: Question about isinstance()

            On Thu, 26 Jan 2006, Rocco Moretti wrote:
            [color=blue][color=green]
            >> You were better off with what you had before. Equality in this case is left
            >> completely open-ended, and as a result, there is no way that you can
            >> guarantee that "a == b" is the same as "b == a" if "a" is a "foo" and "b"
            >> is of unknown type. This can lead to bizarre and unpredictable behavior.[/color]
            >
            > Mind explaining that better? b == a *always* calls b.__eq__(a), if it exists.
            > What a.__eq__(b) is doesn't matter at that point. So you have the same
            > problems either way.[/color]

            Right, but we don't know what "b.__eq__" does, since "b" could be
            anything, if it exists at all. So, it's quite possible that "a == b",
            since "a.__eq__" is defined and only depends on "b" having an
            attribute named "an_attribu te", but "b == a" is:

            a) an error
            b) false, even though "a == b" is true

            If we control the class of "a" and the class of "b", we can ensure that
            the two "__eq__" methods behave identically. The problem is that, in the
            supposed interest of "polymorphi sm" we are relaxing the dependency on
            "a.__eq__"' s parameter so that it can be any class with "an_attribu te".
            This implies that we would like other classes besides those we control to
            be able to participate in equality tests with the class of "a". However,
            to do this properly, we need to be able to modify *both classes*, or we
            will have inconsistent results depending on whether we say "a == b" or
            "b == a". It is reasonable to expect that these two expressions produce
            the same result, isn't it?
            [color=blue]
            > The only difference between the two is in the case where b is of an unrelated
            > class and b.an_attribute exists (1). In this case, the first always returns
            > False, and the second returns (a.an_attribute == b.an_attribute) . Which you
            > prefer depends on how strictly you adhere to duck typing.[/color]

            I don't think duck typing buys you anything valuable here. The usual
            flexibility of duck typing is lost because of the symmetric nature of
            equality; all participating classes need to be involved to guarantee
            correctness. You *could* have "b.__eq__" just call "a.__eq__", but once
            again this assumes we have control over the implementation of "b".

            --
            .:[ dave benjamin -( ramen/sp00 )- http://spoomusic.com/ ]:.

            "To attain knowledge, add things every day.
            To attain wisdom, remove things every day." - Lao Tzu

            Comment

            • Dave Benjamin

              #7
              Re: Question about isinstance()

              On Thu, 26 Jan 2006, Dave Benjamin wrote:
              [color=blue]
              > On Thu, 26 Jan 2006, Rocco Moretti wrote:
              >[color=green][color=darkred]
              >>> You were better off with what you had before. Equality in this case is
              >>> left completely open-ended, and as a result, there is no way that you can
              >>> guarantee that "a == b" is the same as "b == a" if "a" is a "foo" and "b"
              >>> is of unknown type. This can lead to bizarre and unpredictable behavior.[/color]
              >>
              >> Mind explaining that better? b == a *always* calls b.__eq__(a), if it
              >> exists. What a.__eq__(b) is doesn't matter at that point. So you have the
              >> same problems either way.[/color]
              >
              > Right, but we don't know what "b.__eq__" does, since "b" could be anything,
              > if it exists at all. So, it's quite possible that "a == b", since "a.__eq__"[/color]
              ^^^^^^^^^^^^^^^ ^^^^

              By "it" here, I mean "b.__eq__".

              Comment

              • Mr.Rech

                #8
                Re: Question about isinstance()

                All in all it seems that the implementation that uses isinstance() is
                better in this case...

                Thanks for your comments,
                Andrea.

                Comment

                • Steven D'Aprano

                  #9
                  Re: Question about isinstance()

                  On Thu, 26 Jan 2006 19:04:13 +0100, Rene Pijlman wrote:
                  [color=blue]
                  > Mr.Rech:[color=green]
                  >>Now, avoiding isinstace() I've written the following code:
                  >>
                  >>class foo(object):
                  >> ...
                  >> def __eq__(self, other):
                  >> try:
                  >> return self.an_attribu te == other.an_attrib ute
                  >> except AttributeError:
                  >> return False[/color]
                  >
                  > This may give unexpected results when you compare a foo with an instance
                  > of a completely different type that happens to have an attribute called
                  > 'an_attribute'.[/color]


                  That's a trade-off, isn't it?


                  On the one hand, you risk false negatives, by refusing to compare against
                  things you didn't think of. On the other hand, you risk false positives,
                  by comparing against more generic objects.

                  I guess that trade-off is one each programmer must decide for herself, in
                  full understanding of the pros and cons of each method.


                  --
                  Steven.

                  Comment

                  • Rocco Moretti

                    #10
                    Re: Question about isinstance()

                    Mr.Rech wrote:[color=blue]
                    > All in all it seems that the implementation that uses isinstance() is
                    > better in this case...[/color]

                    Well what's "better" depends on what you want to happen when you compare
                    an unrelated class that also defines 'an_attribute'. Unlike in
                    statically typed languages, certain things are made easier when you
                    don't check for strict inheritance (like mock and proxy objects). Google
                    "Duck Typing" for more info.

                    Comment

                    • Mr.Rech

                      #11
                      Re: Question about isinstance()

                      After reading all your comments and thinking a little to my specific
                      case, I think it is definetively better to go with the "isinstance ()"
                      implementation. My objects represent mathematical function defined over
                      a numerical grid, and I hardly think of an unrelated class objects that
                      could be compared with them in a meaningfull way.

                      Thanks again to all of you for helping me to better understand another
                      piece of the Python's world. ;-)

                      Andrea

                      Comment

                      • bruno at modulix

                        #12
                        Re: Question about isinstance()

                        Dave Benjamin wrote:
                        (snip)
                        [color=blue]
                        > You *could* have "b.__eq__" just call "a.__eq__",[/color]

                        Which could lead to strange results (well, actually a good ole infinite
                        recursion) if b.__eq__ happens to call b.__eq__ too !-)


                        --
                        bruno desthuilliers
                        python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
                        p in 'onurb@xiludom. gro'.split('@')])"

                        Comment

                        • bruno at modulix

                          #13
                          Re: Question about isinstance()

                          Mr.Rech wrote:[color=blue]
                          > All in all it seems that the implementation that uses isinstance() is
                          > better in this case...[/color]

                          You could also use something like Zope's Interfaces... But I'm not sure
                          it's worth the extra complexity.

                          --
                          bruno desthuilliers
                          python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
                          p in 'onurb@xiludom. gro'.split('@')])"

                          Comment

                          • Mr.Rech

                            #14
                            Re: Question about isinstance()

                            bruno at modulix wrote:[color=blue]
                            > Mr.Rech wrote:[color=green]
                            > > All in all it seems that the implementation that uses isinstance() is
                            > > better in this case...[/color]
                            >
                            > You could also use something like Zope's Interfaces... But I'm not sure
                            > it's worth the extra complexity.[/color]

                            Thanks for your suggestion, but it's not worth the extra complexity at
                            all.

                            I've read something about interfaces, but my project will be a
                            small/middle sized one, and using such a sophisticated tool it would be
                            like using a cannon to shoot a sparrow (as we are used to say here in
                            Italy).

                            Anyway thanks again for your comments.

                            Andrea

                            Comment

                            • Rene Pijlman

                              #15
                              Re: Question about isinstance()

                              Steven D'Aprano:[color=blue]
                              >Rene Pijlman:[color=green]
                              >> Mr.Rech:[color=darkred]
                              >>> def __eq__(self, other):
                              >>> try:
                              >>> return self.an_attribu te == other.an_attrib ute
                              >>> except AttributeError:
                              >>> return False[/color]
                              >>
                              >> This may give unexpected results when you compare a foo with an instance
                              >> of a completely different type that happens to have an attribute called
                              >> 'an_attribute'.[/color]
                              >
                              >That's a trade-off, isn't it?
                              >
                              >On the one hand, you risk false negatives, by refusing to compare against
                              >things you didn't think of.[/color]

                              Well no, when comparing against things you didn't think of the __eq__
                              shouldn't return a false False, it should return NotImplemented. After
                              all, the things you didn't think of are not (yet) implemented.

                              "A rich comparison method may return NotImplemented if it does not
                              implement the operation for a given pair of arguments."
                              The official home of the Python Programming Language


                              --
                              René Pijlman

                              Wat wil jij worden? http://www.carrieretijger.nl

                              Comment

                              Working...