0

My function is as follows using python:

def PlotCurve(SourceClipName,mode,TestDetails,savepath='../captures/',**args):

    curves=[]
    for a in range(0,len(args)):
        y=[]
        for testrates in TestDetails.BitratesInTest:

            stub = args[a].Directory[testrates]
            y.append(args[a].DataSet[stub][0])
            curves.append(y)

    plt.figure()
    plt.xlabel("Bitrate")
    plt.ylabel(mode)
    plt.title(TestDetails.HDorSD+" "+TestDetails.Codec + " " + SourceClipName[:-4])
    colour=["green","red","brown","orange","purple","grey","black","yellow","white",]
    CurveIDs=[]
    for x in args:
        CurveIDs.append(args.ID)
    p=[]    
    for b in range(0,len(args)-1):
        p[b].plot(TestDetails.BitratesInTest,y[b],c=colour[b])

    plt.legend((p),(CurveIDs),prop={"size":8})
    plt.savefig(os.path.join(savepath,mode+"_"+TestDetails.codec+"_"+SourceClipName[:-4]+".png"))

The error specifically is

TypeEror: PlotCurve() takes at most 4 arguments (5 given)

**args is a list of objects that has been passed into the function

It appears to me that I have defined a function which accepts 5 or more arguments (regardless of whether it works properly or not), but the program disagrees, what is it I am missing which makes the function think it can only have at most 4 parameters?

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
yellowlemming
  • 13
  • 1
  • 2

3 Answers3

3

Use *args, not **kwargs (or **anything), or call the function with parameter names. This will result in a variadic list of the overflow parameters which can then be iterated as done to extract the IDs.

Arguments must be specified by name to apply toward **kwargs and not the parameter count.


See *args and **kwargs?

You would use *args when you're not sure how many arguments might be passed to your function, i.e. it allows you pass an arbitrary number of arguments to your function .. Similarly, **kwargs allows you to handle named arguments that you have not defined in advance.

Community
  • 1
  • 1
user2864740
  • 60,010
  • 15
  • 145
  • 220
  • My problem with trying to use *args as opposed to **args is that it results in the function saying that none of the variables that are within each object in each position of the list exist(which I require).Can you tell me if this is a symptom of *args that means it doesn't allow you to pass a list of objects in or whether there is a more inherent problem with the code? – yellowlemming Jul 24 '14 at 11:14
  • @yellowlemming How is the function be called? Inside the function, `*args` *is* a list. To apply a list to a function call, use the converse `f(*args)` form. But it may be better just to take a list as a separate discrete (named) parameter. – user2864740 Jul 24 '14 at 11:50
  • The function is being called in the form `PlotCurve(filename,"MS_SSIM",TestDetails,"../captures/",CurveList[2:3])` and different calls use different parts of the list CurveList so it would be difficult to name the list explicitly. – yellowlemming Jul 24 '14 at 11:58
  • Simply take an additional parameter then - a list. `def PlotCurve(clipName, mode, testDetails, savepath='../captures/', curve=[])`. The use of \*args is for a *variadic* number of arguments. – user2864740 Jul 24 '14 at 12:03
  • Thankyou, not sure how I didn't think of that – yellowlemming Jul 24 '14 at 12:05
1

When you say, **args is a list of objects that has been passed into the function, then it's with single *

When you define a function with **args as one of the argument it will fail to unpack, while you pass key-value pair

**kwargs to be mapped with dictionary

*args to be mapped with list

or you can have them both, as,

>>> def func(argone, *args, **kwargs):
>>>    # do stuff
>>>
>>> func(1, *[1, 2, 3, 4])
>>> func(1, *[1, 2, 3, 4], **{'a': 1, 'b': 2})
>>>
Siva Cn
  • 929
  • 4
  • 10
0

Most likely you double typed *, as convenience for naming optional positional arguments is *args and optional named arguments is **kwargs.

So your function actually accepts 4 positional arguments and arbitrary number of keyword arguments. If you call it like this:

PlotCurve(1,2,3,4,5) # you should get error
PlotCurve(1,2,3,4,aaa=5) # you should have args = {'aaa': 5}

To fix this, most likely you need to remove second star.

J0HN
  • 26,063
  • 5
  • 54
  • 85