Home > Enterprise >  What python syntax is this?
What python syntax is this?

Time:03-03

I understand that I created a np.poly1d object. But what does it mean by putting it back inside np.poly1d() again?

import numpy as np
f = np.poly1d([1, 1, 1])
print(np.poly1d(f))

FYI running this script, I got

   2
1 x   1 x   1

CodePudding user response:

It's call syntax.

Reference: https://docs.python.org/3/reference/expressions.html#calls

np.poly1d being the callable and f the argument.

np.poly1d is a class, which can be used like a callable to create an instance of the class (What is a "callable"?).


In this particular case, f will be interpreted as an array-like of polynomial coefficients, resulting in a new polynomial which is equivalent to f, since treating a np.poly1d instance as an array results in an array of its coefficients.

>>> np.array(f)
array([1, 1, 1])
>>> g = np.poly1d(f)
>>> g == f
True

So without knowing more context, using np.poly1d(f) instead of f seems pointless. It could be useful if the intention was to create a copy of a polynomial in order to modify one but not the other, since f and g are different objects:

>>> g is f
False

CodePudding user response:

You have np.poly1d, which is a class.

Doing this:

f = np.poly1d([1, 1, 1])

you are initializing an instance of that class, in other words you are calling its __new__ and its __init__ methods.


When you use () after something, is because that something is a callable, that may be defined as @chepner did in the comments:

In Python any type that defines a __call__ method is callable

For example, a function is callable, a method is callable, and also something like this:

class MyClass:
    def __call__(self):
        ...

is callable.

In Python you can check if something is callable with the built-in function callable.

CodePudding user response:

np.poly1d appears to be an old, and somewhat non-standard class definition. There's a note at the start

This forms part of the old polynomial API.

It is also compiled, so there's no Python class definition to read. It also does not start with a capital letter, as is normal Python class practice.

You appear to be working from the first example:

>>> p = np.poly1d([1, 2, 3])
>>> print(np.poly1d(p))
   2
1 x   2 x   3

Why they use that print instead of print(p) is a mystery. May be it's just some sloppiness that no one bothered to fix.

np.poly1d([1,2,3]) makes a poly1d class object.

In [63]: f = np.poly1d([1, 1, 1])
In [64]: type(f)
Out[64]: numpy.poly1d
In [65]: f
Out[65]: poly1d([1, 1, 1])
In [66]: print(f)
   2
1 x   1 x   1

Out[65] is the repr display of this object; Out[66] is the str display.

In [67]: f1 = np.poly1d(f)
In [68]: type(f1)
Out[68]: numpy.poly1d
In [69]: id(f)
Out[69]: 139789855504368
In [70]: id(f1)
Out[70]: 139789855360240

Passing a np.poly1d object to the class creator appears to make a new poly1d object, but with the same attributes. I don't see that documented.

So in terms of Python syntax, both lines are function calls. The details of what happens, or not, are internal to the np.poly1d.

edit

Normal class definition:

In [75]: class Foo:
    ...:     def __init__(self, x):
    ...:         self.x = x
    ...: 
    ...:     def __repr__(self):
    ...:         return "A Foo <%s>" % self.x
In [76]: g = Foo("xxx")
In [77]: g
Out[77]: A Foo <xxx>
In [81]: type(g)
Out[81]: __main__.Foo

[76] uses the class name to actually call Foo.__init__ method, returning a Foo instance. print(g) or in this (ipython) case g displays the instance's repr.

With reference to your comments in another answer, I did not define a __call__ method for the Foo class, so its instances are not callable.

In [94]: g()
Traceback (most recent call last):
  Input In [94] in <module>
    g()
TypeError: 'Foo' object is not callable

Nor is it iterable

In [96]: for x in g:
    ...:     print(x)
Traceback (most recent call last):
  Input In [96] in <module>
    for x in g:
TypeError: 'Foo' object is not iterable

In contrast f, the np.poly1d instance is both callable and iterable:

In [97]: f()
Traceback (most recent call last):
  Input In [97] in <module>
    f()
TypeError: __call__() missing 1 required positional argument: 'val'

In [98]: f(3)
Out[98]: 13
In [99]: for x in f:
    ...:     print(x)
1
1
1
In [100]: f.coeffs
Out[100]: array([1, 1, 1])

That functionality was defined in the compiled code for that class.

dbl edit

np.poly1d docs says the first arg is:

c_or_r : array_like

Usually that mean the argument is first passed through np.asarray.

In [147]: np.asarray(f)
Out[147]: array([1, 1, 1])
In [148]: id(_)
Out[148]: 139789855355984
In [149]: id(f.coeffs)
Out[149]: 139789855355984
In [150]: id(f1.coeffs)
Out[150]: 139789855355984

The f1 instance created in [67] has the coeffs array as f. np.poly1d(f) works it is effectively

np.poly1d(np.asarray(f))  
np.poly1d(f.coeffs)
  • Related