Complex operations with Python (pygame.math.Vector2) - python

I'm learning Python and came across a complex expression that derives from pygame.Vector2:
import pygame
x = pygame.math.Vector2 (1,2)
b = x * 5 - (1, 2)
print (x)
print (b)
Result:
[1,2]
[4,8]
In the above case, the same x * 5 operation is performed both for the 1 and 2 values of Vector2, resulting in (5, 10) respectively; and then both results are subtracted from the tuple (1, 2), resulting in [4,8]
However if I do assign a simple tuple to x: x = (1, 2), instead of Vector2, I get the error:
TypeError: unsupported operand type (s) for -: 'tuple' and 'tuple'
My question is: At what times in Python I can perform these complex operations?

Can do something like (see comments too):
x = (1,2) # create a `tuple`
b = map(lambda x: x * 5,x) # do a `map` object for multiplying 5 to all of them
print(x) # print the `tuple`
t=iter((1,2)) # do an generator object using `iter`, so able to use `next` to access every next element
print(tuple(map(lambda x: x-next(t),b))) # do the `next` and another `map`, to subtract as you wanted
Best thing is still to create a class:
from __future__ import division
class MyClass:
def __init__(self,t):
self.t=t
def __mul__(self,other):
return MyClass(tuple(map(lambda x: x*other,self.t)))
def __truediv__(self,other):
return MyClass(tuple(map(lambda x: x/other,self.t)))
def __sub__(self,other):
gen=iter(other)
return MyClass(tuple(map(lambda x: x-next(gen),self.t)))
def __add__(self,other):
gen=iter(other)
return MyClass(tuple(map(lambda x: x+next(gen),self.t)))
def __repr__(self):
return str(tuple(self.t))
Then now can do anything:
x = MyClass((1,2))
b = x*5
print(b)
print(b-(1,2))
Output:
(5, 10)
(4, 8)
Also can do addition:
x = MyClass((1,2))
b = x*5
print(b)
print(b-(1,2)+(3,4))
Output:
(5, 10)
(7, 12)
Also division:
x = MyClass((1,2))
b = x*5
print(b)
print((b-(1,2)+(3,4))/2)
Output:
(5, 10)
(3.5, 6.0)

Related

What does it mean to pass a function to another function?

I have the following code:
def print_function(values, test):
for x in values:
print('f(', x,')=', test(x), sep='')
def poly(x):
return 2 * x**2 - 4 * x + 2
print_function([x for x in range(-2, 3)], poly)
I understand what the poly function does. What I don't understand is the test(x)? What does this do and where is the connection to the poly function?
In python, functions can be stored in other variables and then called as functions themselves.
Example
def myfunction():
print('hello')
myfunction() #prints hello
alias_myfunction = myfunction # store function object in other variable
alias_myfunction() #prints hello as well
# use id to test if myfunction and alias_myfunction point to same object.
print(id(myfunction) == id(alias_myfunction))
Output
hello
hello
True
Both myfunction and alias_myfunction store the reference to the function object
This can be confirmed using id
In this particular case
# values -> [x for x in range(-2, 3)]
# test -> poly
def print_function(values, test):
for x in values:
print('f(', x,')=', test(x), sep='')
# When test(x) is called, it is essentially calling poly(x)
def poly(x):
return 2 * x**2 - 4 * x + 2
print_function([x for x in range(-2, 3)], poly)

Find number of pairs that add up to a specific number from two different lists?

a = [1,2,3,4,5,6,7]
b = [56,59,62,65,67,69]
def sumOfTwo(a,b,v):
for i in range (len(a)):
val_needed = v - a[i]
for j in range (len(b)):
if b[j] == val_needed:
x = b[j]
y = a[i]
print(x,y)
sumOfTwo(a,b,v=70)
Output: 5 65
What if more pairs are possible from the given lists in the problem, how do I do that?
Help.
What are more ways to achieve this?
If you just want to print matched values, you just have to indent the print statement to be inside theif, as stated below. Also, you should use a more pythonic approach to for loops and also for variable assignments.
a = [1,2,3,4,5,6,7]
b = [56,59,62,65,67,69]
def sumOfTwo(a,b,v):
for i in a:
val_needed = v - i
for j in b:
if j == val_needed:
x, y = j, i
print(x,y)
sumOfTwo(a,b,v=70)
Using a list comprehension:
a = [1,2,3,4,5,6,7]
b = [56,59,62,65,67,69]
c = [(x, y)
for x in a
for y in b
if x + y == 70]
print(c)
This yields
[(1, 69), (3, 67), (5, 65)]

pass multiple parameters to function in multiple tuple sets - python

essentially I have a function which I need to pass to a bunch of values in two different moments (here skipped for practical reasons), hence, I thought need to split all the parameters in two tuple sets after which I'd pass the first set and then the second thinking - mistakenly - that python would allocate all the available n parameters of the function to the values passed with the tuple and then the rest with the second tuple. That is not the case:
def example_F_2(x, y, z, g):
return x * y + z * g
e = (1,2)
r = (3,4)
print(example_F_2(e, r))
in fact:
Traceback (most recent call last):
File "C:/Users/francesco/PycharmProjects/fund-analysis/test_sheet.py", line 7, in <module>
print(example_F_2(e, r))
TypeError: example_F_2() missing 2 required positional arguments: 'z' and 'g'
what can I do? I am guessing something from this page should work (https://docs.python.org/3.5/library/functools.html) but I have been unable to do it myself
A very simple way is to concatenate the tuples and then unpack them as you pass them to your function:
print(example_F_2(*(e+r)))
Perhaps you can use something like this:
def example_F_2(e=None, r=None):
first_term = 0
second_term = 0
if e is not None:
first_term = e[0] * e[1]
if r is not None:
second_term = r[0] * r[1]
return first_term + second_term
e = (1, 2)
r = (3, 4)
print example_F_2(e, r)
> 14
print example_F_2(e=e)
> 2
print example_F_2(r=r)
> 12

Finding percentage of nonempty string

I am trying to write code in Python which finds the percentage of the alphabet in a given string. For example,
percent("ab", "aabccdef") should give [("a", 25), ("b", 13)] since 'a' occurs twice in a string of length 8, so its percentage is round(2 / 8), or 25.
Similarly, 'b' occurs only once. So its percentage is round(1 / 8), or 13.
Here is my code. Can someone help me debug this?
def Percent(alpha, string):
y = [e for e in string if e == alpha]
x = len(y)
return (alpha, round((x / len(string) * 100)))
You were close but the key difference is that you need to compute it for each character c in alpha:
def percent(alpha, string):
results = []
for c in alpha:
y = [e for e in string if e == c]
x = len(y)
results.append((c, round((float(x) / len(string)*100))))
return results
In your code you're comparing e == alpha but alpha is a string ab and e is a single character in the string. This won't give you the results you want.
Furthermore, you need to convert x to a float if you wish to compute the percentage properly. In Python if you write, e.g., 3 / 4 you'll get 0 instead of 0.75. To prevent this you need to convert at least one of the arguments to a float which can be done by calling float(). So you could also write x / float(len(string)*100) to ensure you won't get an integer as result.
Another way to do this, you can use str.count in a list comprehension:
>>> alpha = 'ab'
>>> string = 'aabccdef'
>>> [(x, string.count(x)/len(string)) for x in alpha]
[('a', 0.25), ('b', 0.125)]

Adding Values From Tuples of Same Length

In a graphical program I'm writing using pygame I use a tuple representing a coordinate like this: (50, 50).
Sometimes, I call a function which returns another tuple such as (3, -5), which represents the change in coordinate.
What is the best way to add the change value to the coordinate value. It would be nice if I could do something like coordinate += change, but it appears that would simply concatenate the two tuples to something like (50, 50, 3, -5). Rather than adding the 1st value to the 1st value and the 2nd to the 2nd, and returning a resulting tuple.
Until now I've been using this rather tiresome method:
coord = (coord[0] + change[0], coord[1] + change[1])
What is a better, more concise method to add together the values of two tuples of the same length. It seems especially important to know how to do it if the tuples are of an arbitrary length or a particularly long length that would make the previous method even more tiresome.
Well, one way would be
coord = tuple(sum(x) for x in zip(coord, change))
If you are doing a lot of math, you may want to investigate using NumPy, which has much more powerful array support and better performance.
List comprehension is probably more readable, but here's another way:
>>> a = (1,2)
>>> b = (3,4)
>>> tuple(map(sum,zip(a,b)))
(4,6)
As John Y mentions, this is pretty easy using numpy.
import numpy as np
x1 = (0,3)
x2 = (4,2)
tuple(np.add(x1,x2))
This is a work in progress as I am learning Python myself. Can we use classes here, could simplify some operations later. I propose to use a coord class to store the coordinates. It would override add and sub so you could do addition and subtraction by simply using operators + and -. You could get the tuple representation with a function built into it.
Class
class coord(object):
def __init__(self,x,y):
self.x = x
self.y = y
def __add__(self,c):
return coord(self.x + c.x, self.y + c.y)
def __sub__(self,c):
return coord(self.x - c.x, self.y - c.y)
def __eq__(self,c): #compares two coords
return self.x == c.x and self.y == c.y
def t(self): #return a tuple representation.
return (self.x,self.y)
Usage
c1 = coord(4,3) #init coords
c2 = coord(3,4)
c3 = c1 + c2 #summing two coordinates. calls the overload __add__
print c3.t() #prints (7, 7)
c3 = c3 - c1
print c3.t() #prints (3, 4)
print c3 == c2 #prints True
you could improve coord to extend other operators as well (less than, greater than ..).
In this version after doing your calculations you can call the pygame methods expecting tuples by just saying coord.t(). There might be a better way than have a function to return the tuple form though.
To get your "+" and "+=" behaviour you can define your own class and implement the __add__() method. The following is an incomplete sample:
# T.py
class T(object):
def __init__(self, *args):
self._t = args
def __add__(self, other):
return T(*([sum(x) for x in zip(self._t, other._t)]))
def __str__(self):
return str(self._t)
def __repr__(self):
return repr(self._t)
>>> from T import T
>>> a = T(50, 50)
>>> b = T(3, -5)
>>> a
(50, 50)
>>> b
(3, -5)
>>> a+b
(53, 45)
>>> a+=b
>>> a
(53, 45)
>>> a = T(50, 50, 50)
>>> b = T(10, -10, 10)
>>> a+b
(60, 40, 60)
>>> a+b+b
(70, 30, 70)
EDIT: I've found a better way...
Define class T as a subclass of tuple and override the __new__ and __add__ methods. This provides the same interface as class tuple (but with different behaviour for __add__), so instances of class T can be passed to anything that expects a tuple.
class T(tuple):
def __new__(cls, *args):
return tuple.__new__(cls, args)
def __add__(self, other):
return T(*([sum(x) for x in zip(self, other)]))
def __sub__(self, other):
return self.__add__(-i for i in other)
>>> a = T(50, 50)
>>> b = T(3, -5)
>>> a
(50, 50)
>>> b
(3, -5)
>>> a+b
(53, 45)
>>> a+=b
>>> a
(53, 45)
>>> a = T(50, 50, 50)
>>> b = T(10, -10, 10)
>>> a+b
(60, 40, 60)
>>> a+b+b
(70, 30, 70)
>>>
>>> c = a + b
>>> c[0]
60
>>> c[-1]
60
>>> for x in c:
... print x
...
60
40
60
My two cents, hope this helps
>>> coord = (50, 50)
>>> change = (3, -5)
>>> tuple(sum(item) for item in zip(coord, change))
(53, 45)

Categories

Resources