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)