Callable assertion?

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Roy Smith

    Callable assertion?

    I've got a function which gets passed a call-back function as a
    parameter. I want to check to make sure the thing passed in is indeed
    callable. Is:

    assert '__call__' in dir (param)

    the right thing to do, or is there something cleaner? Will that work
    for all callable values of param, regardless if it's a static function,
    class method, built-in, etc?

    I'm running 2.3.1. Backward compatability isn't particularly an issue
    for me, but I guess it would be nice to know how far back in time this
    works.
  • A.M. Kuchling

    #2
    Re: Callable assertion?

    On Sun, 05 Oct 2003 08:55:45 -0400,
    Roy Smith <roy@panix.co m> wrote:[color=blue]
    > the right thing to do, or is there something cleaner? Will that work
    > for all callable values of param, regardless if it's a static function,
    > class method, built-in, etc?[/color]

    There's a callable(param) built-in function, dating back to Python 1.2.

    --amk

    Comment

    • Roy Smith

      #3
      Re: Callable assertion?

      In article <wMOdnYxfQN0hux 2iRTvUqg@speake asy.net>,
      "A.M. Kuchling" <amk@amk.ca> wrote:
      [color=blue]
      > On Sun, 05 Oct 2003 08:55:45 -0400,
      > Roy Smith <roy@panix.co m> wrote:[color=green]
      > > the right thing to do, or is there something cleaner? Will that work
      > > for all callable values of param, regardless if it's a static function,
      > > class method, built-in, etc?[/color]
      >
      > There's a callable(param) built-in function, dating back to Python 1.2.
      >
      > --amk[/color]

      Ah. That's exactly what I was looking for! The docs say:

      "Return true if the object argument appears callable, false if not. If
      this returns true, it is still possible that a call fails, but if it is
      false, calling object will never succeed."

      What does "appears callable" mean? Under what circumstances would
      callable(foo) return True, yet foo() would fail?

      Comment

      • Terry Reedy

        #4
        Re: Callable assertion?


        "Roy Smith" <roy@panix.co m> wrote in message
        news:roy-F9A420.08554505 102003@reader2. panix.com...[color=blue]
        > I've got a function which gets passed a call-back function as a
        > parameter. I want to check to make sure the thing passed in is[/color]
        indeed[color=blue]
        > callable.[/color]

        The acid test is to try calling it:

        try: param()
        except TypeError, msg: <do whatever>

        You can check that msg.endswith('n ot callable') if you want but I
        don't know the stability of the error message.

        Terry J. Reedy




        Comment

        • Roy Smith

          #5
          Re: Callable assertion?

          In article <h5GcnUOo2b742R 2iXTWJhQ@comcas t.com>,
          "Terry Reedy" <tjreedy@udel.e du> wrote:
          [color=blue]
          > "Roy Smith" <roy@panix.co m> wrote in message
          > news:roy-F9A420.08554505 102003@reader2. panix.com...[color=green]
          > > I've got a function which gets passed a call-back function as a
          > > parameter. I want to check to make sure the thing passed in is[/color]
          > indeed[color=green]
          > > callable.[/color]
          >
          > The acid test is to try calling it:
          >
          > try: param()
          > except TypeError, msg: <do whatever>[/color]

          The problem there is that it really calls the function! I want to test
          the paramater for correctness in my constructor, but I don't actually
          want it called until it's supposed to be called. Calling the function
          to prove it's callable is kind of like checking to see if a gun's safety
          is on by pulling the trigger :-)

          Not to mention that param might indeed be callable and the TypeError is
          being generated (and not caught) somewhere further down.

          Comment

          • Gonçalo Rodrigues

            #6
            Re: Callable assertion?

            On Sun, 05 Oct 2003 10:20:11 -0400, Roy Smith <roy@panix.co m> wrote:
            [color=blue]
            >In article <wMOdnYxfQN0hux 2iRTvUqg@speake asy.net>,
            > "A.M. Kuchling" <amk@amk.ca> wrote:
            >[color=green]
            >> On Sun, 05 Oct 2003 08:55:45 -0400,
            >> Roy Smith <roy@panix.co m> wrote:[color=darkred]
            >> > the right thing to do, or is there something cleaner? Will that work
            >> > for all callable values of param, regardless if it's a static function,
            >> > class method, built-in, etc?[/color]
            >>
            >> There's a callable(param) built-in function, dating back to Python 1.2.
            >>
            >> --amk[/color]
            >
            >Ah. That's exactly what I was looking for! The docs say:
            >
            >"Return true if the object argument appears callable, false if not. If
            >this returns true, it is still possible that a call fails, but if it is
            >false, calling object will never succeed."
            >
            >What does "appears callable" mean? Under what circumstances would
            >callable(foo ) return True, yet foo() would fail?[/color]


            An extreme and artificial example:
            [color=blue][color=green][color=darkred]
            >>> class FakeCallable(ob ject):[/color][/color][/color]
            .... def __call__(self, *args, **kwargs):
            .... raise TypeError("My only purpose in life is to trick
            the Python interpreter.")
            ....[color=blue][color=green][color=darkred]
            >>> a = FakeCallable()
            >>> callable(a)[/color][/color][/color]
            True[color=blue][color=green][color=darkred]
            >>> a()[/color][/color][/color]
            Traceback (most recent call last):
            File "<interacti ve input>", line 1, in ?
            File "<interacti ve input>", line 3, in __call__
            TypeError: My only purpose in life is to trick the Python interpreter.[color=blue][color=green][color=darkred]
            >>>[/color][/color][/color]

            Best,
            G. Rodrigues

            Comment

            • Lulu of the Lotus-Eaters

              #7
              Re: Callable assertion?

              "Terry Reedy" <tjreedy@udel.e du> wrote previously:
              |The acid test is to try calling it:
              |try: param()
              |except TypeError, msg: <do whatever>

              This is usually a bad idea though. Many, if not most, things you call
              can either have side effects and/or consume non-trivial resources (time,
              memory, especially).

              For example, you don't want to change state by making a call if you know
              you are not ready for that state change until something else happens.
              But you may want to know whether 'param' is callable before you bother
              with the setup code.

              Yours, Lulu...

              --
              Keeping medicines from the bloodstreams of the sick; food from the bellies
              of the hungry; books from the hands of the uneducated; technology from the
              underdeveloped; and putting advocates of freedom in prisons. Intellectual
              property is to the 21st century what the slave trade was to the 16th.

              Comment

              • Lulu of the Lotus-Eaters

                #8
                Re: Callable assertion?

                "Terry Reedy" <tjreedy@udel.e du> wrote previously:
                |The acid test is to try calling it:
                |try: param()
                |except TypeError, msg: <do whatever>

                This is usually a bad idea though. Many, if not most, things you call
                can either have side effects and/or consume non-trivial resources (time,
                memory, especially).

                For example, you don't want to change state by making a call if you know
                you are not ready for that state change until something else happens.
                But you may want to know whether 'param' is callable before you bother
                with the setup code.

                Yours, Lulu...

                --
                Keeping medicines from the bloodstreams of the sick; food from the bellies
                of the hungry; books from the hands of the uneducated; technology from the
                underdeveloped; and putting advocates of freedom in prisons. Intellectual
                property is to the 21st century what the slave trade was to the 16th.

                Comment

                • Terry Reedy

                  #9
                  Re: Callable assertion?


                  "Roy Smith" <roy@panix.co m> wrote in message
                  news:roy-2F0C3F.13005105 102003@reader2. panix.com...[color=blue]
                  > In article <h5GcnUOo2b742R 2iXTWJhQ@comcas t.com>,
                  > "Terry Reedy" <tjreedy@udel.e du> wrote:[color=green]
                  > > The acid test is to try calling it:
                  > >
                  > > try: param()
                  > > except TypeError, msg: <do whatever>[/color]
                  >
                  > The problem there is that it really calls the function![/color]

                  Of course. You only do this test when you actually want the function
                  called.
                  [color=blue]
                  > I want to test
                  > the paramater for correctness in my constructor,[/color]

                  I was afraid of that ;-).
                  [color=blue]
                  > but I don't actually
                  > want it called until it's supposed to be called. Calling the[/color]
                  function[color=blue]
                  > to prove it's callable is kind of like checking to see if a gun's[/color]
                  safety[color=blue]
                  > is on by pulling the trigger :-)[/color]

                  But it is the Python way. Someone recently asked how to test if one
                  can connect to a site without actually connecting and Alex M. gave
                  much the same answer I did. The frequent question "how can I tell if
                  I can read a file without actually reading it" gets the stock answer
                  'you can't, not for sure', just as iscallable is 'not for sure'.
                  Sorry, time-varying reality and the possibility of lies sometimes
                  bites
                  [color=blue]
                  > Not to mention that param might indeed be callable and the TypeError[/color]
                  is[color=blue]
                  > being generated (and not caught) somewhere further down.[/color]

                  That is why I suggested looking at the message, although you are
                  right, the same message could also be passed up.

                  Terry J. Reedy


                  Comment

                  • Terry Reedy

                    #10
                    Re: Callable assertion?


                    "Lulu of the Lotus-Eaters" <mertz@gnosis.c x> wrote in message
                    news:mailman.10 65381789.5393.p ython-list@python.org ...[color=blue]
                    > "Terry Reedy" <tjreedy@udel.e du> wrote previously:
                    > |The acid test is to try calling it:
                    > |try: param()
                    > |except TypeError, msg: <do whatever>
                    >
                    > This is usually a bad idea though.[/color]

                    I disagree. The OP previously got the iscallable() answer, with the
                    caveat that True may be a lie, and I posted in that context. One
                    might still want to wrap the actual call in a try block. It is the
                    same for reading files or making socket connections. No matter what
                    pre-info one gathers, the acid test is to try to do it, and a careful
                    coder will prepare for possible failure.
                    [color=blue]
                    > Many, if not most, things you call can either have side effects[/color]
                    and/or[color=blue]
                    > consume non-trivial resources (time, memory, especially).
                    > For example, you don't want to change state by making a call if you[/color]
                    know[color=blue]
                    > you are not ready for that state change until something else[/color]
                    happens.

                    Of course. I assumed the OP already knows this.
                    [color=blue]
                    > But you may want to know whether 'param' is callable before you[/color]
                    bother[color=blue]
                    > with the setup code.[/color]

                    Of course, but regardless of 'want', you cannot know for sure, as 1 or
                    2 others have said and shown (see Rodriguez' post).

                    Terry J. Reedy


                    Comment

                    • Peter Hansen

                      #11
                      Re: Callable assertion?

                      Roy Smith wrote:[color=blue]
                      >
                      > I want to test
                      > the paramater for correctness in my constructor, but I don't actually
                      > want it called until it's supposed to be called. Calling the function
                      > to prove it's callable is kind of like checking to see if a gun's safety
                      > is on by pulling the trigger :-)[/color]

                      Okay, new scenario: we find a gun, and for some reason you are
                      willing to take my word for it that the safety is on, because
                      you intend to point it at your head and pull the trigger.

                      Which do you trust more: me looking at the safety and telling
                      you that it appears to be on, as I hand you the gun, or me
                      pulling the trigger and, if the gun doesn't fire, handing you
                      the gun? ...

                      The point is, that in the end, testing for callable only
                      tests for the *appearance*, correct though it may be in many
                      or most cases. No matter what, you can't prove that it can
                      be called until you try to call it. And in that case you
                      must still be prepared to handle the cases where the call fails,
                      or other situations.

                      What if I give you an object which appears to be callable, so
                      you stuff a reference somewhere in your constructor, because
                      after all "it's safe to call". Then, by the time you actually
                      try to call it, the object has morphed itself into something
                      without a __call__ method. The attempt to call it will fail.

                      Same logic as checking that a file exists before you actually
                      try to use it: no guarantee it will still exist later, so save
                      the wasted effort and just be ready for the exception that will
                      be thrown when it turns out not to exist.

                      There are times when what you are trying to do is the right
                      thing, maybe, probably, but it's rarely the case. If you are
                      sure, then callable() is what you need. Otherwise just catch
                      exceptions as appropriate.

                      -Peter

                      Comment

                      • Roy Smith

                        #12
                        Re: Callable assertion?

                        "Terry Reedy" <tjreedy@udel.e du> wrote:[color=blue][color=green]
                        >> but I don't actually want it called until it's supposed to be
                        >> called. Calling the function to prove it's callable is kind of like
                        >> checking to see if a gun's safety is on by pulling the trigger :-)[/color][/color]
                        [color=blue]
                        > But it is the Python way. Someone recently asked how to test if one
                        > can connect to a site without actually connecting and Alex M. gave
                        > much the same answer I did. The frequent question "how can I tell if
                        > I can read a file without actually reading it" gets the stock answer
                        > 'you can't, not for sure', just as iscallable is 'not for sure'.[/color]

                        I hear what you're saying, but it's still nice to be able to check ahead
                        of time. What you're saying is analagous to "Why bother checking the
                        safety because even if it's on now, by the time your finger slips and
                        touches the trigger, it might not be on any more".

                        Let's say I write this:

                        class eventThingie:
                        def __init__ (self, callback):
                        self.callback = callback

                        def go (self):
                        if magic stuff happens:
                        self.callback()

                        and then do:

                        myThingie = eventThingie (42)
                        myThingie.go()

                        When the magic stuff happens, I'll get a TypeError burried at the bottom
                        of a stack trace, and none of the lines in the stack trace will be where
                        my real error is. On the other hand, if I add "assert callable
                        (callback)" to my __init__() method, it'll be a lot easier to figure out
                        what went wrong because the stack trace will happen right when and where
                        the erroneous code is executed. It's just like trying to track down
                        pointer botches in C; by the time you get a segfault, you're nowhere
                        near the cause of the problem.

                        It's a tradeoff. By checking early, you give up a little flexibility
                        and theoretical purity, but what you get back is better testability.
                        [color=blue]
                        > Sorry, time-varying reality and the possibility of lies sometimes
                        > bites[/color]

                        If by "time-varying reality" you mean the dynamic nature of the
                        language, that's an interesting problem. It is certainly possible in
                        theory that I could pass in an object which has no __call__() method, so
                        callable() would return False, but also guarantee that by the time the
                        object is actually called, I've managed to add a __call__() method to
                        the object. Theoretically possible, but diabolical, and not the kind of
                        thing I'm going to worry about.

                        Comment

                        • Roy Smith

                          #13
                          Re: Callable assertion?

                          "Terry Reedy" <tjreedy@udel.e du> wrote:[color=blue]
                          > I disagree. The OP previously got the iscallable() answer, with the
                          > caveat that True may be a lie, and I posted in that context. One
                          > might still want to wrap the actual call in a try block. It is the
                          > same for reading files or making socket connections. No matter what
                          > pre-info one gathers, the acid test is to try to do it, and a careful
                          > coder will prepare for possible failure.[/color]

                          There's a big difference between verifying that a passed parameter has
                          the properties it's supposed to have and trying to figure out if you can
                          read a file or open a socket.

                          The former catches a programming error. If I meant to pass fred and I
                          pass fred() by mistake, the problem is going to be there every time I
                          run the program until I fix the code.

                          The latter catches problems caused by external events. Files can appear
                          and disapper, or have their permissions change, at any time, and all
                          this is beyond the control (and knowledge) of my program. For things
                          like that, then yes, I agree that the way to find out if you can do
                          something is to try it and see what happens.

                          Comment

                          • Carl Banks

                            #14
                            Re: Callable assertion?

                            Peter Hansen wrote:[color=blue]
                            > Roy Smith wrote:[color=green]
                            >>
                            >> I want to test
                            >> the paramater for correctness in my constructor, but I don't actually
                            >> want it called until it's supposed to be called. Calling the function
                            >> to prove it's callable is kind of like checking to see if a gun's safety
                            >> is on by pulling the trigger :-)[/color]
                            >
                            > Okay, new scenario: we find a gun, and for some reason you are
                            > willing to take my word for it that the safety is on, because
                            > you intend to point it at your head and pull the trigger.
                            >
                            > Which do you trust more: me looking at the safety and telling
                            > you that it appears to be on, as I hand you the gun, or me
                            > pulling the trigger and, if the gun doesn't fire, handing you
                            > the gun? ...
                            >
                            > The point is, that in the end, testing for callable only
                            > tests for the *appearance*, correct though it may be in many
                            > or most cases. No matter what, you can't prove that it can
                            > be called until you try to call it. And in that case you
                            > must still be prepared to handle the cases where the call fails,
                            > or other situations.
                            >
                            > What if I give you an object which appears to be callable, so
                            > you stuff a reference somewhere in your constructor, because
                            > after all "it's safe to call". Then, by the time you actually
                            > try to call it, the object has morphed itself into something
                            > without a __call__ method. The attempt to call it will fail.
                            >
                            > Same logic as checking that a file exists before you actually
                            > try to use it: no guarantee it will still exist later, so save
                            > the wasted effort and just be ready for the exception that will
                            > be thrown when it turns out not to exist.
                            >
                            > There are times when what you are trying to do is the right
                            > thing, maybe, probably, but it's rarely the case. If you are
                            > sure, then callable() is what you need. Otherwise just catch
                            > exceptions as appropriate.[/color]

                            The OP said he wanted to use it inside an assertion. If he's using
                            assertions correctly, then this is one of those cases.

                            Assertions, used properly, test for conditions that are supposed to be
                            impossible. If something that was designed to be impossible occurs,
                            then there must be a bug somewhere. This is true whether an assertion
                            catches the impossible condition or not.

                            As a practical matter, using callable() is a good way to assert that a
                            value is callable. You see, callable() cannot return a false positive
                            unless there was already a bug in the program--it's not as if using
                            callable() here can introduce a bug where there was none previously.
                            (And, of course, callable() can't return a false negative.)

                            OTOH, using callable() inside an assertion will catch the vast
                            majority of non-callable values.


                            --
                            CARL BANKS http://www.aerojockey.com/software

                            As the newest Lady Turnpot descended into the kitchen wrapped only in
                            her celery-green dressing gown, her creamy bosom rising and falling
                            like a temperamental souffle, her tart mouth pursed in distaste, the
                            sous-chef whispered to the scullery boy, "I don't know what to make of
                            her."
                            --Laurel Fortuner, Montendre, France
                            1992 Bulwer-Lytton Fiction Contest Winner

                            Comment

                            • Terry Reedy

                              #15
                              Re: Callable assertion?


                              "Roy Smith" <roy@panix.co m> wrote in message
                              news:roy-93EAD2.18123305 102003@reader2. panix.com...[color=blue]
                              > I hear what you're saying,[/color]

                              ?
                              [color=blue]
                              > but it's still nice to be able to check ahead of time.[/color]

                              Of course; I never said otherwise. Nor, that I remember, did I say to
                              not use callable(). I merely stated the reality that the ultimate
                              test for this particular property, in Python, is an actual call.

                              If I were writing the callback recipient purely for my own use, I
                              might decide to make no check and deal with the traceback should I
                              slip up and pass a non-callable. If I were writing a library routine
                              for the whole world to use, I might both test with callable() *and*
                              wrap the callback call.

                              A similar frequently asked question is "How can I check, before using
                              it, that a passed parameter is a number?" Seems simple, but depending
                              on the
                              definition of 'number', it may not be easily checkable in Python.
                              (See archives for more.)

                              Terry J. Reedy


                              Comment

                              Working...