Is there a builtin way to define a function that takes either 1 argument or 3?












8














There's this error in Python when calling builtin type() with no arguments:



TypeError: type() takes 1 or 3 arguments


How can we define such a method?
Is there a builtin way? Or we need to do something like this:



>>> def one_or_three(*args):
... if len(args) not in [1,3]:
... raise TypeError("one_or_three() takes 1 or 3 arguments")
...
>>> one_or_three(1)
>>> one_or_three()
TypeError: one_or_three() takes 1 or 3 arguments
>>> one_or_three(1,2)
TypeError: one_or_three() takes 1 or 3 arguments









share|improve this question


















  • 5




    I can't think of an in-built way.. a couple of alternatives are using a decorator or an assert.
    – jpp
    Nov 12 '18 at 12:06






  • 1




    This specific error is hardcoded in typeobject.c in the function type_new. It returns a valid result for nargs == 1 and then throws an error for if (nargs != 3). Alas, peeking at the source doesn't readily tell if it can be done in native Python.
    – usr2564301
    Nov 12 '18 at 12:47
















8














There's this error in Python when calling builtin type() with no arguments:



TypeError: type() takes 1 or 3 arguments


How can we define such a method?
Is there a builtin way? Or we need to do something like this:



>>> def one_or_three(*args):
... if len(args) not in [1,3]:
... raise TypeError("one_or_three() takes 1 or 3 arguments")
...
>>> one_or_three(1)
>>> one_or_three()
TypeError: one_or_three() takes 1 or 3 arguments
>>> one_or_three(1,2)
TypeError: one_or_three() takes 1 or 3 arguments









share|improve this question


















  • 5




    I can't think of an in-built way.. a couple of alternatives are using a decorator or an assert.
    – jpp
    Nov 12 '18 at 12:06






  • 1




    This specific error is hardcoded in typeobject.c in the function type_new. It returns a valid result for nargs == 1 and then throws an error for if (nargs != 3). Alas, peeking at the source doesn't readily tell if it can be done in native Python.
    – usr2564301
    Nov 12 '18 at 12:47














8












8








8







There's this error in Python when calling builtin type() with no arguments:



TypeError: type() takes 1 or 3 arguments


How can we define such a method?
Is there a builtin way? Or we need to do something like this:



>>> def one_or_three(*args):
... if len(args) not in [1,3]:
... raise TypeError("one_or_three() takes 1 or 3 arguments")
...
>>> one_or_three(1)
>>> one_or_three()
TypeError: one_or_three() takes 1 or 3 arguments
>>> one_or_three(1,2)
TypeError: one_or_three() takes 1 or 3 arguments









share|improve this question













There's this error in Python when calling builtin type() with no arguments:



TypeError: type() takes 1 or 3 arguments


How can we define such a method?
Is there a builtin way? Or we need to do something like this:



>>> def one_or_three(*args):
... if len(args) not in [1,3]:
... raise TypeError("one_or_three() takes 1 or 3 arguments")
...
>>> one_or_three(1)
>>> one_or_three()
TypeError: one_or_three() takes 1 or 3 arguments
>>> one_or_three(1,2)
TypeError: one_or_three() takes 1 or 3 arguments






python function






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Nov 12 '18 at 12:03









Adelin

4,62331542




4,62331542








  • 5




    I can't think of an in-built way.. a couple of alternatives are using a decorator or an assert.
    – jpp
    Nov 12 '18 at 12:06






  • 1




    This specific error is hardcoded in typeobject.c in the function type_new. It returns a valid result for nargs == 1 and then throws an error for if (nargs != 3). Alas, peeking at the source doesn't readily tell if it can be done in native Python.
    – usr2564301
    Nov 12 '18 at 12:47














  • 5




    I can't think of an in-built way.. a couple of alternatives are using a decorator or an assert.
    – jpp
    Nov 12 '18 at 12:06






  • 1




    This specific error is hardcoded in typeobject.c in the function type_new. It returns a valid result for nargs == 1 and then throws an error for if (nargs != 3). Alas, peeking at the source doesn't readily tell if it can be done in native Python.
    – usr2564301
    Nov 12 '18 at 12:47








5




5




I can't think of an in-built way.. a couple of alternatives are using a decorator or an assert.
– jpp
Nov 12 '18 at 12:06




I can't think of an in-built way.. a couple of alternatives are using a decorator or an assert.
– jpp
Nov 12 '18 at 12:06




1




1




This specific error is hardcoded in typeobject.c in the function type_new. It returns a valid result for nargs == 1 and then throws an error for if (nargs != 3). Alas, peeking at the source doesn't readily tell if it can be done in native Python.
– usr2564301
Nov 12 '18 at 12:47




This specific error is hardcoded in typeobject.c in the function type_new. It returns a valid result for nargs == 1 and then throws an error for if (nargs != 3). Alas, peeking at the source doesn't readily tell if it can be done in native Python.
– usr2564301
Nov 12 '18 at 12:47












2 Answers
2






active

oldest

votes


















4














First, type is not native Python (at least in CPython), but C.



The inspect module can confirm it easily (even if documented as a builtin function, type is implemented as a class in CPython):



>>> print(inspect.signature(type.__init__))
(self, /, *args, **kwargs)
>>> print(sig.parameters['self'].kind)
POSITIONAL_ONLY


The parameter kind is POSITIONAL_ONLY, which cannot be created in Python.



That means that it will not be possible to reproduce exactly the behaviour of type.



Python source allows only 2 signatures for variable number of arguments:





  • 3 parameters, 2 of them being optional:



    type(object_or_name, bases = None, dict = None)


    This would be very different, because it will accept gladly type(obj, None) which is definitely not what is expected here



  • a simple *args parameter whose length will be tested by hand - your proposal. This will be much closer to native type behaviour, because it really requires 1 or 3 parameters, whatever the values.



TL/DR: the answer to your question is that we really need the something like that way.






share|improve this answer





























    0














    This behavior is perfectly possible in Python.



    def one_or_three(one, two=object(), three=object()):
    two_sentinel, three_sentinel = one_or_three.__defaults__
    if (two == two_sentinel) != (three == three_sentinel):
    raise TypeError("one_or_three() takes 1 or 3 arguments")
    ...


    This has the benefits of named arguments (semantic value, passing in by name, etc) but is basically a variation on checking the values of some variables to know whether one or three things were passed.



    Note that the two calls to object() produce two different objects and bind them to the function:



    >>> one_or_three.__defaults__
    (<object object at 0x00168540>, <object object at 0x00168ED0>)


    This way, they are globally unique. If you instead used None as your sentinel object, then it wouldn't be possible to pass in None as an argument (though of course that may be desired).






    share|improve this answer





















      Your Answer






      StackExchange.ifUsing("editor", function () {
      StackExchange.using("externalEditor", function () {
      StackExchange.using("snippets", function () {
      StackExchange.snippets.init();
      });
      });
      }, "code-snippets");

      StackExchange.ready(function() {
      var channelOptions = {
      tags: "".split(" "),
      id: "1"
      };
      initTagRenderer("".split(" "), "".split(" "), channelOptions);

      StackExchange.using("externalEditor", function() {
      // Have to fire editor after snippets, if snippets enabled
      if (StackExchange.settings.snippets.snippetsEnabled) {
      StackExchange.using("snippets", function() {
      createEditor();
      });
      }
      else {
      createEditor();
      }
      });

      function createEditor() {
      StackExchange.prepareEditor({
      heartbeatType: 'answer',
      autoActivateHeartbeat: false,
      convertImagesToLinks: true,
      noModals: true,
      showLowRepImageUploadWarning: true,
      reputationToPostImages: 10,
      bindNavPrevention: true,
      postfix: "",
      imageUploader: {
      brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
      contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
      allowUrls: true
      },
      onDemand: true,
      discardSelector: ".discard-answer"
      ,immediatelyShowMarkdownHelp:true
      });


      }
      });














      draft saved

      draft discarded


















      StackExchange.ready(
      function () {
      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53261804%2fis-there-a-builtin-way-to-define-a-function-that-takes-either-1-argument-or-3%23new-answer', 'question_page');
      }
      );

      Post as a guest















      Required, but never shown

























      2 Answers
      2






      active

      oldest

      votes








      2 Answers
      2






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes









      4














      First, type is not native Python (at least in CPython), but C.



      The inspect module can confirm it easily (even if documented as a builtin function, type is implemented as a class in CPython):



      >>> print(inspect.signature(type.__init__))
      (self, /, *args, **kwargs)
      >>> print(sig.parameters['self'].kind)
      POSITIONAL_ONLY


      The parameter kind is POSITIONAL_ONLY, which cannot be created in Python.



      That means that it will not be possible to reproduce exactly the behaviour of type.



      Python source allows only 2 signatures for variable number of arguments:





      • 3 parameters, 2 of them being optional:



        type(object_or_name, bases = None, dict = None)


        This would be very different, because it will accept gladly type(obj, None) which is definitely not what is expected here



      • a simple *args parameter whose length will be tested by hand - your proposal. This will be much closer to native type behaviour, because it really requires 1 or 3 parameters, whatever the values.



      TL/DR: the answer to your question is that we really need the something like that way.






      share|improve this answer


























        4














        First, type is not native Python (at least in CPython), but C.



        The inspect module can confirm it easily (even if documented as a builtin function, type is implemented as a class in CPython):



        >>> print(inspect.signature(type.__init__))
        (self, /, *args, **kwargs)
        >>> print(sig.parameters['self'].kind)
        POSITIONAL_ONLY


        The parameter kind is POSITIONAL_ONLY, which cannot be created in Python.



        That means that it will not be possible to reproduce exactly the behaviour of type.



        Python source allows only 2 signatures for variable number of arguments:





        • 3 parameters, 2 of them being optional:



          type(object_or_name, bases = None, dict = None)


          This would be very different, because it will accept gladly type(obj, None) which is definitely not what is expected here



        • a simple *args parameter whose length will be tested by hand - your proposal. This will be much closer to native type behaviour, because it really requires 1 or 3 parameters, whatever the values.



        TL/DR: the answer to your question is that we really need the something like that way.






        share|improve this answer
























          4












          4








          4






          First, type is not native Python (at least in CPython), but C.



          The inspect module can confirm it easily (even if documented as a builtin function, type is implemented as a class in CPython):



          >>> print(inspect.signature(type.__init__))
          (self, /, *args, **kwargs)
          >>> print(sig.parameters['self'].kind)
          POSITIONAL_ONLY


          The parameter kind is POSITIONAL_ONLY, which cannot be created in Python.



          That means that it will not be possible to reproduce exactly the behaviour of type.



          Python source allows only 2 signatures for variable number of arguments:





          • 3 parameters, 2 of them being optional:



            type(object_or_name, bases = None, dict = None)


            This would be very different, because it will accept gladly type(obj, None) which is definitely not what is expected here



          • a simple *args parameter whose length will be tested by hand - your proposal. This will be much closer to native type behaviour, because it really requires 1 or 3 parameters, whatever the values.



          TL/DR: the answer to your question is that we really need the something like that way.






          share|improve this answer












          First, type is not native Python (at least in CPython), but C.



          The inspect module can confirm it easily (even if documented as a builtin function, type is implemented as a class in CPython):



          >>> print(inspect.signature(type.__init__))
          (self, /, *args, **kwargs)
          >>> print(sig.parameters['self'].kind)
          POSITIONAL_ONLY


          The parameter kind is POSITIONAL_ONLY, which cannot be created in Python.



          That means that it will not be possible to reproduce exactly the behaviour of type.



          Python source allows only 2 signatures for variable number of arguments:





          • 3 parameters, 2 of them being optional:



            type(object_or_name, bases = None, dict = None)


            This would be very different, because it will accept gladly type(obj, None) which is definitely not what is expected here



          • a simple *args parameter whose length will be tested by hand - your proposal. This will be much closer to native type behaviour, because it really requires 1 or 3 parameters, whatever the values.



          TL/DR: the answer to your question is that we really need the something like that way.







          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Nov 12 '18 at 13:17









          Serge Ballesta

          75.6k956130




          75.6k956130

























              0














              This behavior is perfectly possible in Python.



              def one_or_three(one, two=object(), three=object()):
              two_sentinel, three_sentinel = one_or_three.__defaults__
              if (two == two_sentinel) != (three == three_sentinel):
              raise TypeError("one_or_three() takes 1 or 3 arguments")
              ...


              This has the benefits of named arguments (semantic value, passing in by name, etc) but is basically a variation on checking the values of some variables to know whether one or three things were passed.



              Note that the two calls to object() produce two different objects and bind them to the function:



              >>> one_or_three.__defaults__
              (<object object at 0x00168540>, <object object at 0x00168ED0>)


              This way, they are globally unique. If you instead used None as your sentinel object, then it wouldn't be possible to pass in None as an argument (though of course that may be desired).






              share|improve this answer


























                0














                This behavior is perfectly possible in Python.



                def one_or_three(one, two=object(), three=object()):
                two_sentinel, three_sentinel = one_or_three.__defaults__
                if (two == two_sentinel) != (three == three_sentinel):
                raise TypeError("one_or_three() takes 1 or 3 arguments")
                ...


                This has the benefits of named arguments (semantic value, passing in by name, etc) but is basically a variation on checking the values of some variables to know whether one or three things were passed.



                Note that the two calls to object() produce two different objects and bind them to the function:



                >>> one_or_three.__defaults__
                (<object object at 0x00168540>, <object object at 0x00168ED0>)


                This way, they are globally unique. If you instead used None as your sentinel object, then it wouldn't be possible to pass in None as an argument (though of course that may be desired).






                share|improve this answer
























                  0












                  0








                  0






                  This behavior is perfectly possible in Python.



                  def one_or_three(one, two=object(), three=object()):
                  two_sentinel, three_sentinel = one_or_three.__defaults__
                  if (two == two_sentinel) != (three == three_sentinel):
                  raise TypeError("one_or_three() takes 1 or 3 arguments")
                  ...


                  This has the benefits of named arguments (semantic value, passing in by name, etc) but is basically a variation on checking the values of some variables to know whether one or three things were passed.



                  Note that the two calls to object() produce two different objects and bind them to the function:



                  >>> one_or_three.__defaults__
                  (<object object at 0x00168540>, <object object at 0x00168ED0>)


                  This way, they are globally unique. If you instead used None as your sentinel object, then it wouldn't be possible to pass in None as an argument (though of course that may be desired).






                  share|improve this answer












                  This behavior is perfectly possible in Python.



                  def one_or_three(one, two=object(), three=object()):
                  two_sentinel, three_sentinel = one_or_three.__defaults__
                  if (two == two_sentinel) != (three == three_sentinel):
                  raise TypeError("one_or_three() takes 1 or 3 arguments")
                  ...


                  This has the benefits of named arguments (semantic value, passing in by name, etc) but is basically a variation on checking the values of some variables to know whether one or three things were passed.



                  Note that the two calls to object() produce two different objects and bind them to the function:



                  >>> one_or_three.__defaults__
                  (<object object at 0x00168540>, <object object at 0x00168ED0>)


                  This way, they are globally unique. If you instead used None as your sentinel object, then it wouldn't be possible to pass in None as an argument (though of course that may be desired).







                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered Nov 21 '18 at 12:25









                  Joel Harmon

                  1212




                  1212






























                      draft saved

                      draft discarded




















































                      Thanks for contributing an answer to Stack Overflow!


                      • Please be sure to answer the question. Provide details and share your research!

                      But avoid



                      • Asking for help, clarification, or responding to other answers.

                      • Making statements based on opinion; back them up with references or personal experience.


                      To learn more, see our tips on writing great answers.





                      Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


                      Please pay close attention to the following guidance:


                      • Please be sure to answer the question. Provide details and share your research!

                      But avoid



                      • Asking for help, clarification, or responding to other answers.

                      • Making statements based on opinion; back them up with references or personal experience.


                      To learn more, see our tips on writing great answers.




                      draft saved


                      draft discarded














                      StackExchange.ready(
                      function () {
                      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53261804%2fis-there-a-builtin-way-to-define-a-function-that-takes-either-1-argument-or-3%23new-answer', 'question_page');
                      }
                      );

                      Post as a guest















                      Required, but never shown





















































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown

































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown







                      Popular posts from this blog

                      Florida Star v. B. J. F.

                      Danny Elfman

                      Lugert, Oklahoma