5

I have already checked this post and this post, but couldn't find a good way of sorting the problem of my code out.

I have a code as follows:

class foo:
    def __init__(self, foo_list, str1, str2):

        self.foo_list = foo_list
        self.str1 = str1
        self.str2 = str2

    def fun(self, l=None, s1=None, s2=None):

        if l is None:
            l = self.foo_list

        if s1 is None:
            s1 = self.str1

        if s2 is None:
            s2 = self.str2

        result_list = [pow(i, 2) for i in l]

        return result_list, s1[-1], len(s2)

Then I create "f" and call "fun" function:

f = foo([1, 2, 3, 4], "March", "June")
print(f.fun())

The output is:

([1, 4, 9, 16], 'h', 4)

which is correct, but if I do:

print(f.fun("April"))

I get the following error:

TypeError: unsupported operand type(s) for ** or pow(): 'str' and 'int'

Apparently, python confuses the string argument "April" with the list, how do I fix it?

5
  • 4
    Try print(f.fun(s1="April")) Commented Nov 6, 2020 at 23:59
  • 2
    If you don't name the argument when calling, it assigns it to the parameter positionally. The first unnamed argument is l, next is s1, next is s2. Commented Nov 7, 2020 at 0:03
  • 2
    f.fun("April") is equivalent to f.fun(l="April"), because you are passing it as a positional arugment, so it gets passed positionally. Use the named argument to pass what you want specifically Commented Nov 7, 2020 at 0:04
  • You can pass arguments using a dictionary with a parameter like **mydict - and the dictionary keys must match named parameters of the function. It’s documented search for ** in the Python 3 documentation. Commented Nov 7, 2020 at 0:20
  • 1
    A cleaner way to do the if l is None: thing is a single line l=l or self.foo_list Commented Nov 7, 2020 at 0:23

1 Answer 1

5

By default, the first argument passed to the function will be assigned to the first parameter. If you want to assign the first argument to the second (or n:th) parameter, you must give it as keyword argument. See, for example

In [19]: def myfunc(x='X', y=5):
    ...:     print(x,y)
    ...:
    ...:

# No arguments -> Using default parameters
In [20]: myfunc()
X 5

# Only one positional argument -> Assigned to the first parameter, which is x
In [21]: myfunc(100)
100 5

# One keyword argument -> Assigned by name to parameter y
In [22]: myfunc(y=100)
X 100

The type of the arguments do not matter, but the order you used in the function definition.

Notes on terminology

  • By parameter, I mean the variable in the function definition
  • By argument, I mean the actual value passed to the function.
Sign up to request clarification or add additional context in comments.

9 Comments

Thanks, apart from naming the argument when calling, is there any other way rather than using None in the fun signature for this situations?
Is there any other way to do what?
To call a function with multiple optional arguments of different types?
No you’ll have to name them. It’s nothing to do with types.
I'm not sure if I understand you correctly, but you can always call function with multiple optional arguments of different types, even if the default value would not be None. As you see, in my example, the myfunc has default values x='X' and y=5. Also, the type of the default arguments really does not matter at all: I can still call myfunc(x=100), even if the default argument is a string.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.