Handling a method with an optional argument followed by a list of keyword arguments

python optional arguments
python kwargs
python keyword-only arguments
python keyword arguments
python keyword arguments default values
python optional arguments none
args vs kwargs
python function arguments type

I want to pass an optional argument (any datatype, even a Hash) followed by a list of keyword arguments (which can be empty) to a method.

This is what I got:

def my_method(subject = nil, **options)
  [subject, options]
end

The method output is as expected in the following cases:

  • nothing

    my_method()
    # => [nil, {}]
    
  • a subject

    my_method('foo')
    # => ["foo", {}]
    
  • a literal subject with options

    my_method('foo', bar: 'bar')
    # => ["foo", {:bar=>"bar"}]
    
  • a Hash as subject with options

    my_method({foo: 'foo'}, bar: 'bar')
    # => [{:foo=>"foo"}, {:bar=>"bar"}]
    
  • no subject, only options

    my_method(bar: 'bar')
    # => [nil, {:bar=>"bar"}]
    

When passing a Hash as subject and no options, the desired outcome is:

my_method({foo: 'foo'})
# => [{:foo=>"foo"}, {}]

But I get the following; I don't get the correct subject:

my_method({foo: 'foo'})
# => [nil, {:foo=>"foo"}]

Is my_method(foo: 'foo') equivalent to my_method({foo: 'foo'})? Any ideas on how I could get the desired outcome?

See, you have **options as an argument which do not have any default value & first argument have default value. So understand following single argument case,

Whenever single argument is passed it is tried to assign to second argument (as first one is holding default nil) & if it fails due to type mismatch then it assign to first argument. That's how my_method(4) works.

Now Suppose you have single argument passed as hash, which match to assign to 2nd argument then of course it get assigned to second argument & first is set default nil.

If you want to make it work, then you can do following,

> my_method({sd: 4}, {})
 => [{:sd=>4}, {}]

Or you can provide argument name while passing,

> my_method(subject: {sd: 4})
 => [{:sd=>4}, {}]

Python Function Arguments (Default, Keyword and Arbitrary), In the function definition, we use an asterisk (*) before the parameter name to denote this kind of argument. Here is an example. def greet(*names): """This function  So, in this post, I am going to tell you how to create a Python function with optional arguments. Creating a function with optional arguments in Python is quite an easy task. Let’s see with our first exam. Below we have created a Python function with a default argument: def my_function(a=10): print(a) my_function()

As far as I know this is a limitation of how Ruby passes arguments. It can't tell the difference between my_method({foo: 'foo'}) and my_method(foo: 'foo')

Why not hack around it with this?

if subject.is_a?(Hash) && options.empty?
  subject, options = nil, subject
end

This assumes that subject shouldn't be a hash though.

Multiple optional arguments python, **kwargs is used to let Python functions take an arbitrary number of keyword arguments and then ** unpacks a dictionary of keyword arguments  C# 4 introduces named and optional arguments. Named arguments enable you to specify an argument for a particular parameter by associating the argument with the parameter's name rather than with the parameter's position in the parameter list. Optional arguments enable you to omit arguments for some parameters. Both techniques can be used with methods, indexers, constructors, and delegates.

Maybe not the best answer but you can try with keyword argument :

def my_method(subject: nil, **options)
  [ subject, options ]
end

Then

my_method(subject: {foo: 'foo'})

=> [{:foo=>"foo"}, {}]
Alternative :

You can use

my_method({foo: 'foo'}, {})

Understanding named arguments and optional arguments (VBA , A named argument consists of an argument name followed by a colon and an Optional arguments are preceded by the Optional keyword in the The IsMissing function determines whether an optional Variant argument has  Optional Method Parameters There are some valid arguments against using Optional as a method parameter type, but they are not good enough to say that you should avoid it at all costs. by

Python - Advanced Parameter Handling For Functions, Earlier, when we defined a function that had optional parameters, it had a of parameters, but some (or all) could be omitted because we provided default values for every element in the list args ; the current guess must be the largest value. of positional parameters first, followed by some optional keyword parameters. Those arguments must be provided as named arguments to distinguish them from the unlimited positional arguments. The built-in print function accepts the optional sep, end, file, and flush attributes as keyword-only arguments: 1 2. >>> print('comma', 'separated', 'words', sep=', ') comma, separated, words.

Positional and Keyword Arguments, First Function · Functions with Multiple Arguments · Functions with Default Python functions can contain two types of arguments: positional arguments and keyword arguments. Examples of iterable objects in Python include lists and tuples. A keyword argument is an argument passed to a function or method which is  Stack Overflow for Teams is a private, secure spot for you and your coworkers to find and share information. Learn more How do I create a Python function with optional arguments?

Ruby's Powerful Method Arguments & How To Use Them Correctly, Ruby is very flexible when it comes to method arguments. We have everything: From the standard required arguments to optional arguments & even keyword changes its argument list, you don't have to change arguments in Bacon too. The way optional arguments work in ruby is that you specify an equal sign, and if no argument is passed then what you specified is used. So, if no second argument is passed in the second example, then {age: 27, weight: 160, city: "New York"} is used. If you do use the hash syntax after the first argument, then that exact hash is passed.

Comments
  • I updated in my answer why it got assigned to second argument.
  • Thanks for your answer. Unfortunately I need to pass a hash to subject sometimes.
  • @Taschetto Ok... but how would you distinguish a nil subject and just options from a Hash subject and no options?
  • my_method({foo: 'foo'}) should be a hash subject and no options; my_method(foo: 'foo') should be a nil subject and just options. But maybe I'm getting it wrong.
  • @Taschetto I'm pretty sure that's a limitation of Ruby. It cannot distinguish between those two cases. I would just make subject non-optional in that case.
  • Thanks for you answer. Yes, that works. But in my case I'd have to refactor a large number of method calls. I need to maintain the method interface.
  • @Taschetto then my_method({foo: 'foo'}, {}) can be a solution ?