-1

I've been trying to follow a video tutorial on Python and cannot understand one operation the developer performs.

class Polynomial():

    def __init__(self, *coeffs):
        self.coeffs = coeffs # (3,4,3)

    def __repr__(self):
        return 'Polynomial(*{!r})'.format(self.coeffs)

    def __add__(self, other):
        print(self.coeffs)
        print(other.coeffs)
        z = (x + y for x, y in zip(self.coeffs, other.coeffs))
        print(z)
        return Polynomial(*(x + y for x, y in zip(self.coeffs, other.coeffs)))

p1 = Polynomial(1, 2, 3) # x^2 + 2x + 3
p2 = Polynomial(3, 4, 3) # 3x^2 + 4x + 3
#print(p2) # Polynomial(*(3, 4, 3))
print(p1 + p2) # Polynomial(*(4, 6, 6))

The above example will print

<generator object Polynomial.__add__.<locals>.<genexpr> at 0x030D0390>

as the return value of z, I cannot understand why because I am performing a zip operation of two tuples?

Alongside that problem, I do not understand why removing the * during the return of __add__ causes a problem i.e return Polynomial(*(x + y for x, y in zip(self.coeffs, other.coeffs))) to return Polynomial((x + y for x, y in zip(self.coeffs, other.coeffs)))

What is the * operator doing, and why is z an object of Polynomial?

The _add__ method does not contain a parameter containing a * or ** and is therefore a different situation.

J.doe
  • 43
  • 3
  • 2
    Possible duplicate of [What does \*\* (double star/asterisk) and \* (star/asterisk) do for parameters?](https://stackoverflow.com/questions/36901/what-does-double-star-asterisk-and-star-asterisk-do-for-parameters) – Norrius Nov 15 '18 at 09:19

3 Answers3

1

So first.

Your print is ok. You defined a generator using () parentheses. You can change this to [] and then you should see the elements in list.

Or you can use your generator, so print:

print([el for el in z])

Second, the *.

It will simply pass iterable as separated args, so:

SomeClass(*args)

Will do:

SomeClass(args[0], args[1], args[2], ...)

You can read about this in official docs (single asterisk), here: https://docs.python.org/3/reference/expressions.html#expression-lists And here (double asterisk): https://docs.python.org/3/reference/expressions.html#dictionary-displays

opalczynski
  • 1,599
  • 12
  • 14
  • 1
    or just print(list(z)). As to second question - you print the result of p1+p2 - i.e. print(p1 + p2). The __add__ method returns Polynominal object, so when you print it and because you don't have __str__ method, it calls the __repr__ method of Polynominal class – buran Nov 15 '18 at 09:22
0

When in a function declaration, * is list of args send.

For exemple:

def my_function(a, *b, **c):
    print(a)
    print(b)
    print(c)

my_function("1st arg", "other arg", "other arg again", 2, arg_type="kwargs")

output :

1st args
["other arg", "other arg again", 2]
{"arg_type": "kwargs"}


And when is not in function declaration, it's for unpack the list.

For exemple:

list_of_arguments = ['a', 'b', 'z']
my_str = "the first letter of alphabet is {}, the second is {} and the last is {}"
print(my_str.format(*list_of_arguments))


or other exemple

 def my_second_func(a, b, c):
     print(a)
     print(b)

 my_list = [1, 2, 3]
 my_second_func(a, b, c)

will output:

 1
 2
iElden
  • 1,272
  • 1
  • 13
  • 26
0

Consider this easy example:

a = [1, 2, 3]
b = [4, 5, 6]

gen = (x + y for x, y in zip(a, b))

print(gen) ## this will print <generator object <genexpr> at 0x...>

In this case, the asterisk evaluates the generator expression. So when doing

print(*gen) ## this will print 5 7 9

you evaluate the generator expression.

DocDriven
  • 3,726
  • 6
  • 24
  • 53