Can a complex number be unpacked into x and y in python? - python

I want to be able to unpack a complex number into its real and imaginary parts like so:
>>> z = 3 + 5j
>>> x, y = z
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: cannot unpack non-iterable complex object
but I get an error. Of course I can do:
>>> x, y = z.real, z.imag
but this seems repetitive and not very readable, I can improve this by writing a function like this:
def unpack(z: complex) -> tuple[float, float]:
return z.real, z.imag
x, y = unpack(z)
but I feel like there should be a better way.
Do you know a better way to unpack a complex number into its real and imaginary parts?

One thing you can do is subclass complex and implement a custom __iter__ method that returns the unpacked version you seek.
I chose to call it complez in this case, since z is often a symbol for a complex number.
import cmath
class complez(complex):
def __iter__(self):
return iter((self.real, self.imag))
z = complez(3, 5)
x, y = z
print(x, y)
# 3.0 5.0
You can also do the following, if you don't mind overriding the existing complex. Using this approach allows you to continue using the complex class throughout your code without needing to make any changes to naming.
import builtins
import cmath
class complex(builtins.complex):
def __iter__(self):
return iter((self.real, self.imag))
z = complex(3, 5)
x, y = z
print(x, y)
# 3.0 5.0
(Technically, you could also drop the use of the builtins module).
In either case, the standard unpacking operator would also work, e.g.
print(*z)
# 3.0 5.0
NOTE: This solves your immediate problem, but it does have consequences. When you perform operations on these new numbers, e.g. adding 2 complez numbers, you would get a complex number result -- which won't have the convenient __iter__ defined, so you'd have to override other methods to account for this side-effect. For example:
def __add__(self, other):
return complez(super().__add__(other))
Hence, this approach does result in more overhead in producing a fully general solution. But, this is the tradeoff for having the convenience of natural unpacking.

Related

Is there a better way than this to write Python functions that "depend on parameters"?

Consider the Python function line defined as follows:
def line(m, b):
def inner_function(x):
return m * x + b
return inner_function
This function has the property that for any floats m and b, the object line(m, b) is a Python function, and when line(m, b) is called on a float x, it returns a float line(m, b)(x). The float line(m, b)(x) can be interpreted as the value of the line with slope m and y-intercept b at the point x. This is one method for writing a Python function that "depends on parameters" m and b.
Is there a special name for this method of writing a Python function that depends on some parameters?
Is there a more Pythonic and/or computationally efficient way to write a function that does the same thing as line above?
This is called a closure, and it's a perfectly reasonable way to write one, as well as one of the most efficient means of doing so (in the CPython reference interpreter anyway).
The only other common pattern I know of is the equivalent of C++'s functors, where a class has the state as attributes, and the additional parameters are passed to __call__, e.g. to match your case:
class Line:
def __init__(self, m, b):
self.m = m
self.b = b
def __call__(self, x):
return self.m * x + self.b
It's used identically, either creating/storing an instance and reusing it, or as in your example, creating it, using it once, and throwing it away (Line(m, b)(x)). Functors are slower than closures though (as attribute access is more expensive than reading from nested scope, at least in the CPython reference interpreter), and as you can see, they're more verbose as well, so I'd generally recommend the closure unless your needs require the greater flexibility/power of class instances.
I support #ShaddowRanger's answer. But using partial is another nice approach.
import functools
def f(m, b, x):
return m * x + b
line = functools.partial(f, 2, 3)
line(5)
=> 13
One thing which is worth pointing out is that lambda objects, and OP's inner_function aren't pickleable, whereas line here, as well as #ShaddowRanger's Line objects are, which makes them a bit more useful.
This is a little shorter:
def line(m,b):
return lambda x: m*x+b;

SymPy lambdify with dot()

Take an undefined function that happens to be named dot, and make it part of lambdify:
import numpy
import sympy
class dot(sympy.Function):
pass
x = sympy.Symbol('x')
a = sympy.Matrix([1, 0, 0])
f = sympy.lambdify(x, dot(a.T, x))
x = numpy.array([3, 2, 1])
print(f(x))
Surprise: This actually works!
Apparently, the string "dot" is somehow extracted and replaced by an implementation of the dot-product. Does anyone know which?
The result of the above is [3]. I would, however, like to get the scalar 3. (How) can I modify f() to achieve that?
I'm not a sympy user however quoting the documentation for lambdify it says:
If not specified differently by the user, SymPy functions are replaced
as far as possible by either python-math, numpy (if available) or
mpmath functions - exactly in this order. To change this behavior, the
“modules” argument can be used. It accepts:
the strings “math”, “mpmath”, “numpy”, “numexpr”, “sympy”
any modules (e.g. math)
dictionaries that map names of sympy functions to arbitrary functions
lists that contain a mix of the arguments above, with higher priority given to entries appearing first.
So it seems that if you have python-math installed it will use that, if not but you have numpy installed it will use numpy's version, otherwise mpmat and then describes how to modify this behaviour.
In your case just provide a modules value that is a dictionary that maps the name dot to a function that return a scalar as you want.
An example of what I mean:
>>> import numpy as np
>>> import sympy
>>> class dot(sympy.Function): pass
...
>>> x = sympy.Symbol('x')
>>> a = sympy.Matrix([1,0,0])
>>> f = sympy.lambdify(x, dot(a.T, x), modules=[{'dot': lambda x, y: np.dot(x, y)[0]}, 'numpy'])
>>> y = np.array([3,2,1])
>>> print(f(y))
3
>>> print(type(f(y)))
<class 'numpy.int64'>
As you can see by manipulating the modules argument you can achieve what you want. My implementation here is absolutely naive, but you can generalize it like:
>>> def my_dot(x, y):
... res = np.dot(x, y)
... if res.ndim == 1 and res.size == 1:
... return res[0]
... return res
This function checks whether the result of the normal dot is a scalar, and if so returns the plain scalar and otherwise return the same result as np.dot.

Returning intermediate results from function in Python

Imagine I've got a Python module with some function in it:
def sumvars(x, y, z):
s = x
s += y
s += z
return s
But sometimes I want to get results of some intermediate calculations (for example, I could have a function which reverses a matrix and would like to know the determinant which has been calculated as an intermediate step as well). Obviously, I wouldn't want to redo those calculations again if they were already done within that function.
My first idea is to return a dict:
def sumvars(x, y, z):
d = {}
s = x
d['first_step'] = s
s += y
d['second_step'] = s
s += z
d['final'] = s
return d
But I don't recall any functions in numpy or scipy which return dicts and so it seems like this might be not a good idea. (Why?) Also routinely I'll always have to type sumvars(x,y,z)['final'] for a default return value...
Another option I see is creating global variables but seems wrong having a bunch of them in my module, I would need to remember their names and in addition not being attached to the function itself looks like a bad design choice.
What would be the proper function design for such situation?
Generally when you have two different ways you want to return data, go ahead and make two different functions. "Flat is better than nested", after all. Just have one call the other so that you Don't Repeat Yourself.
For example, in the standard library, urllib.parse has parse_qs (which returns a dict) and parse_qsl (which returns a list). parse_qs just then calls the other:
def parse_qs(...):
parsed_result = {}
pairs = parse_qsl(qs, keep_blank_values, strict_parsing,
encoding=encoding, errors=errors)
for name, value in pairs:
if name in parsed_result:
parsed_result[name].append(value)
else:
parsed_result[name] = [value]
return parsed_result
Pretty straightforward. So in your example it seems fine to have
def sumvars(x, y, z):
return sumvars_with_intermediates(x, y, z).final
def sumvars_with_intermediates(x, y, z):
...
return my_namedtuple(final, first_step, second_step)
(I favor returning namedtuples instead of dicts from my APIs, it's just prettier)
Another obvious example is in re: re.findall is its own function, not some configuration flag to search.
Now, the standard library is a sprawling thing made by many authors, so you'll find counterexamples to every example. You'll far more often see the above pattern rather than one omnibus function that accepts some configuration flags, though, and I find it far more readable.
Put the common calculation into its own function as Jayanth Koushik recommended if that calculation can be named appropriately. If you want to return many values (an intermediate result and a final result) from a single function then a dict may be an overkill depending on what is your goal but in python it is much more natural to simply return a tuple if your function has many values to return:
def myfunc():
intermediate = 5
result = 6
return intermediate, result
# using the function:
intermediate, result = myfunc()
Not sure if function attributes is a good idea:
In [569]: def sumvars(x, y, z):
...: s = x
...: sumvars.first_step = s
...: s += y
...: sumvars.second_step = s
...: s += z
...: return s
In [570]: res=sumvars(1,2,3)
...: print res, sumvars.first_step, sumvars.second_step
...:
6 1 3
Note: as #BrenBarn mentioned, this idea is just like global variables, your previously calculated "intermediate results" could not be stored when you want to reuse them.
Just came up with this idea which could be a better solution:
def sumvars(x, y, z, mode = 'default'):
d = {}
s = x
d['first_step'] = s
s += y
d['second_step'] = s
s += z
d['final'] = s
if mode == 'default':
return s
else:
return d
I belive the proper solution is to use a class, to have a better grasp of what you are modeling. For example in the case of the Matrix, you could simply store the determinant in the "determinant" attribute.
Here is an example using your matrix example.
class Matrix:
determinant = 0
def calculate_determinant(self):
#calculations
return determinant
def some_method(self, args):
# some calculations here
self.determinant = self.calculate_determinant()
# other calculations
matrix = Matrix()
matrix.some_method(x, y, z)
print matrix.determinant
This also allows you to separate your method into simpler methods, like one for calculating the determinant of your matrix.
Another variation:
def sumvars(x, y, z, d=None):
s = x
if not d is None:
d['first_step'] = s
s += y
if not d is None:
d['second_step'] = s
s += z
return s
The function always returns the desired value without packing it into a tuple or dictionary. The intermediate results are still available, but only if requested. The call
sumvars(1, 2, 3)
just returns 6 without storing intermediate values. But the call
d = {}
sumvars(1, 2, 3, d)
returns the same answer 6 and inserts the intermediate calculations into the supplied dictionary.
Option 1. Make two separate functions.
Option 2. Use a generator:
>>> def my_func():
... yield 1
... yield 2
...
>>> result_gen = my_func()
>>> result_gen
<generator object my_func at 0x7f62a8449370>
>>> next(result_gen)
1
>>> next(result_gen)
2
>>> next(result_gen)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
>>>
Inspired by #zhangxaochen solution, here's my take on your problem using class attributes:
class MyClass():
def __init__(self):
self.i = 4
def f(self):
s = self.i
MyClass.first_step = s
print(MyClass.first_step)
s += self.i
MyClass.second_step = s
print(MyClass.second_step)
s += self.i
return s
def main():
x = MyClass()
print(x.f()) # print final s
print(x.first_step)
print(x.second_step)
print(MyClass.second_step)
Note: I included several prints to make it more explicit how attribute values can be retrieved.
Result:
4
8
12
4
8
8

Python - can't convert value from sympy.core.add.Add class to float

Here's my problem (illustraded with an applicable example):
... some code
### x=0.5*t*(copysign(1, t - 0.5) + 1) + 0.1
### x=string value
X= Matrix(len(x),1,x)
>>>print X[0]
0.5*t*(copysign(1, t - 0.5) + 1) + 0.1
>>>print type(X[0])
<class 'sympy.core.add.Add'>
t1=linspace(0,1,2)
REF=[]
for i in range(len(t1)):
REF.append(M_ref[0].subs(t,t1[i]))
>>>print REF
0.100000000000000, 0.5*copysign(1, 0.5) + 0.6
So REF[0] is from the 'sympy.core.numbers.Float' class, but REF[1] is from the 'sympy.core.add.Add' class (as are the rest of list values when I expand the linspace). Therefore I can't use them in the rest of my code. I tried to use evalf but that didn't solve the problem.
I need the values in the REF list to be all floats (or integers).
Any help would be appreciated.
I think I understand what is happening.
You are converting your input from strings. SymPy doesn't have a function called copysign, and sympify doesn't use the math library, so it just creates Function('copysign'), which is an unevaluated object. If you want to evaluate it as the math copysign from the get-go, you can add {'copysign': math.copysign} as a second argument when you call sympify, like sympify('copysign(1, 2)', {'copysign': math.copysign}). If you want a symbolic version, you will need to create one, as it doesn't exist in SymPy yet. Something like
class copysign(Function):
nargs = 2
#classmethod
def eval(cls, x, y):
if x.is_number and y.is_number:
return math.copysign(x, y)
That will work symbolically, but as soon as both arguments are numeric, it will evaluate using the math copysign.
>>> x, y = symbols('x y')
>>> copysign(x, y)
copysign(x, y)
>>> copysign(1, -2)
-1.0
Really, a better way to do it would be to reimplement the copysign logic symbolically, so that it always returns a SymPy type, but I'll leave that to you as an exercise. You can look at how sign is implemented in SymPy to get an idea.

Problems in summing two polynomials using python

I'm asked to make a program that calculates the addition of two polynomials of n and m degrees. I made two dictionaries (one for the first polynomial and the other is for the other polynomial) since each one has the coefficients as values and degrees as keys so that I can check whether the keys from both dictionaries are identical, then I can sum their values. But I don't know why I always get an error. My code so far is:
class poly:
def __init__(self, L=[], D=[]):
self.coef=L
self.deg=D
def __add__(self,L2):
if len(self.coef)>len(self.deg):
dec=dict(zip(self.deg,self.coef))
dec[0]=self.coef[-1]
else:
dec=dict(zip(self.deg,self.coef))
Dec1=dec
if len(L2.coef)>len(L2.deg):
dec=dict(zip(L2.deg,L2.coef))
dec[0]=L2.coef[-1]
else:
dec=dict(zip(L2.deg,L2.coef))
Dec2=dec
p=[]
if len(Dec2)>len(Dec1):
for i in Dec2:
if i in Dec1:
s=Dec1[i]+Dec2[i]
p=p+[s]
else:
p=p+p[Dec2[i]]
for x in Dec1:
if x in Dec2:
p=p
else:
p=p+[dec1[x]]
return(poly(p))
if len(Dec2)<len(Dec1):
for x in Dec1:
if x in Dec2:
g=Dec1[x]
p=p+[g]
else:
p=p+[Dec1[x]]
for m in Dec2:
if m in Dec1:
p=p
else:
p=p+[Dec2[m]]
return (poly(p))
This code doesn't work for all my examples such as
>>> p=poly([2,4,7,34],[6,4,2])
>>> p1=poly([6,3,7,2,8],[8,4,2,1])
>>> p2=p+p1
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
p2=p+p1
File "poly.py", line 31, in __add__
p=p+p[Dec2[i]]
IndexError: list index out of range
>>> #The numbers in the first list is the coefficients and the second list is for degrees
This doesn't work! But it worked when I've done the addition without using class method. I'm a beginner and I did my best to fix the problem.
Another question is how to write the def str for my code? I really don't have any idea what I should write in the beginning. I'm sorry guys but I'm new in programming and I need an easy code such as mine.
By common convention, class names should be capitalized (ie Poly)
You have __add__ doing a lot of stuff that has nothing to do with adding. This should be a warning sign.
A lot of __add__'s work is mucking about with the data storage format. Maybe you should use a better storage format, one which won't need so much reshuffling?
You have a lot of repetitive chunks of code in __add__; this is usually an indicator that the code should be factored into a subroutine.
You have this object (self) making changes to the internal details of another object (L2) - another bad smell.
If you move the normalization code for self (if len(self.coef) > len(self.deg) ...) from __add__ into __init__, this will solve #2, #3, half of #4, and #5 all in one go (you no longer have to "do to" L2, it will "do to" itself).
If you realize that it's pretty much irrelevant whether len(Dec1) > len(Dec2) or not, you can get rid of another block of redundant code. This fixes the other half of #4. Suddenly __add__ shrinks from 48 lines of code to about 12, and becomes much easier to understand and debug.
For sake of comparison:
from itertools import izip_longest, chain, product
from collections import defaultdict
class Poly(object):
def __init__(self, coeff=None, power=None):
if coeff is None: coeff = []
if power is None: power = []
self.d = defaultdict(int)
for c,p in izip_longest(coeff, power, fillvalue=0):
if c != 0:
self.d[p] += c
#classmethod
def fromDict(cls, d):
return cls(d.itervalues(), d.iterkeys())
#property
def degree(self):
return max(p for p,c in self.d.iteritems() if c != 0)
def __add__(self, poly):
return Poly(
chain(self.d.itervalues(), poly.d.itervalues()),
chain(self.d.iterkeys(), poly.d.iterkeys())
)
def __mul__(self, poly):
return Poly(
(cs*cp for cs,cp in product(self.d.itervalues(), poly.d.itervalues())),
(ps+pp for ps,pp in product(self.d.iterkeys(), poly.d.iterkeys()))
)
def __call__(self, x):
return sum(c*x**p for p,c in self.d.iteritems())
def __str__(self):
clauses = sorted(((p,c) for p,c in self.d.iteritems() if c != 0), reverse=True)
return " + ".join("{}x^{}".format(c,p) for p,c in clauses) or "0"
Note that:
Each method is short and does only things relevant to what it is supposed to accomplish.
I purposefully wrote __init__ to be very fault-tolerant; it will cheerfully accept multiple coefficients of a given power and sum them. This allowed me to greatly simplify __add__ and __mul__, basically just throwing all the resulting clauses at a new Poly and letting it clean them up again.
I have included a minimal implementation of __str__, which will result in moderately ugly output like 5x^2 + -2x^1 + -5x^0. You may wish to add special handling for negative coefficients and powers of 1 or 0, to make it produce 5x^2 - 2x - 5 instead.
This is for the purpose of understanding, not plagiarism; do not submit it to your teacher as is, he will never in a million years believe you actually wrote it ;-)

Categories

Resources