-1

I'm trying to write the piecewise a simple piece wise function, yet it won't work when you put in a list.

# your code here
def pwfun(*args):
    
    for x in args:
        if x < -1:
            return(-2 * (x + 1))
        elif x > 1:
            return(x**2 - 1)
        else:
            return(0)

I thought that args would help out for any lists that I try, yet I keep getting the following error when I'm trying to run the code with a list of variables. I was wondering if there's an additional step with *args or I'm using *args wrong in the first place

<ipython-input-35-c95bcaddf037> in pwfun(*args)
      3 
      4     for x in args:
----> 5         if x < -1:
      6             return(-2 * (x + 1))
      7         elif x > 1:

TypeError: '<' not supported between instances of 'list' and 'int'
Trenton McKinney
  • 56,955
  • 33
  • 144
  • 158

2 Answers2

0

I think your problem is that calling pwfun(-6, 0, 1) will assign args to (-6, 0, 1) but calling pwfun([-6, 0, 1]) will assign args to ([6, 0, 1]) (notice double brackets).

To fix this (if you still want to use *args), I would do:

pwfun(*x)

The *x means that *args is assigned to (-6, 0, 1) not ([-6, 0, 1]).

If this isn't what you want, there are a few other ways:

  1. Define pwfun like: def pwfun(args): so that args has the value [6, 0, 1].
  2. Just do for x in args[0]. This would mean that you iterate over the first argument of the function.

N.B. As your program returns on the first iteration of the for loop, you don't need the for loop.

sbottingota
  • 533
  • 1
  • 3
  • 18
  • It worked for the test I did, but it's not working for the notebook tests the teacher assigned because there's no *x for her tests. Is there anything you suggest to get the function to work for pwfun(x) – Joseph Silva Apr 26 '23 at 18:30
  • @JosephSilva I edited my answer to include a few other ways. From what I understand, you're aloud to edit inside `pwfun`, but not the code which calls it. – sbottingota Apr 27 '23 at 05:39
0

I see two issues with your solution – one in the way you call your function, one in the implementation of your function:

First, as already pointed out in @sbottingota's answer, you are calling your function with a list, but your function signature and internal logic has been designed as if it should be called with individual values:

  • If you have a list x = [-6, 0, 2] and call pwfun(x), then your args looks as follows: ([1, 2, 3],); in other words, you will have your list of values wrapped inside a one-element tuple. As a consequence, when iterating over the values in args in your loop, you will get the list [-6, 0, 2] as the first and only value for your loop variable x, which ends in a comparison of a list ([-6, 0, 2]) with an integer (-1), which is undefined.
  • If you call pwfun(*x) instead, with the same list x, this will be the same as calling pwfun(-6, 0, 2), i.e. the same as calling your function with the individual elements of the list. Then *args will gather them into a new list (or rather, tuple), which will look as expected: (-6, 0, 2). As a consequence, when iterating over args you will iterate over the individual values, as expected.

However (second issue), in your for-loop, you will return in each if-statement. This means that the loop will never reach any element after the first element in args, as you will have already exited both your loop and your function with returning the result for your first element only.

There are two solutions that I can think of for your problem: (1) gathering the results in a list again, (2) using a generator function. Let's have a look at the individual solutions in the following sections.

Your solution

def pwfun(*args):
    for x in args:
        if x < -1:
            return(-2 * (x + 1))
        elif x > 1:
            return(x**2 - 1)
        else:
            return(0)

x = [-6, 0, 2]
result = pwfun(*x)
print(f"Calling pwfun(*x) with x = {x}:")
print(f"The result is of type {type(result)} and looks as follows: {result}")
# >>> Calling pwfun(*x) with x = [-6, 0, 2]:
# >>> The result is of type <class 'int'> and looks as follows: 10

As you can see, the function only returns a result for the first value in args.

Side note: In python, return is a keyword, not a function or anything that is called; so while writing return(0) etc. works, you would normally write return 0 without the brackets.

Solution with result list

def pwfun_list(*args):
    result = []
    for x in args:
        if x < -1:
            result.append(-2 * (x + 1))
        elif x > 1:
            result.append(x ** 2 - 1)
        else:
            result.append(0)
    return result

x = [-6, 0, 2]
result = pwfun_list(*x)
print(f"Calling pwfun_list(*x) with x = {x}:")
print(f"The result is of type {type(result)} and looks as follows: {result}.")
print("The individual values are:")
for value in result:
    print(value)
# >>> Calling pwfun_list(*x) with x = [-6, 0, 2]:
# >>> The result is of type <class 'list'> and looks as follows: [10, 0, 3].
# >>> The individual values are:
# >>> 10
# >>> 0
# >>> 3

Here, we iterate over the values in args, but rather than returning results immediately, we append them to a new list result, which we return once, at the very end. As a result, we have evaluated the function for all values rather than only for the first one.

Solution with generator

def pwfun_gen(*args):
    for x in args:
        if x < -1:
            yield -2 * (x + 1)
        elif x > 1:
            yield x ** 2 - 1
        else:
            yield 0

x = [-6, 0, 2]  
result = pwfun_gen(*x)
print(f"Calling pwfun_gen(*x) with x = {x}:")
print(f"The result is of type {type(result)} and looks as follows: {result}.")
print("The individual values are:")
for value in result:
    print(value)
# >>> Calling pwfun_gen(*x) with x = [-6, 0, 2]:
# >>> The result is of type <class 'generator'> and looks as follows: <generator object pwfun_gen at 0x000001E8AE3787B0>.
# >>> The individual values are:
# >>> 10
# >>> 0
# >>> 3

This solution looks more similar to your original solution. However, as we replaced return with yield, we will get a generator in return when calling pwfun_gen(*x).

The generator will then provide the result for each individual element in args (and not only for the first one), once we iterate over it with for value in result. In contrast to a list, however, this last step will work only once, and then the generator will be "exhausted".

The concept of generators is maybe a bit less intuitive than a regular Python function (at least that's what I think). You can find a good introduction here, if you are interested.

simon
  • 1,503
  • 8
  • 16