Complex operations with Python (pygame.math.Vector2)

1

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 executed 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?

    
asked by anonymous 29.09.2018 / 03:13

1 answer

1

The Vector2 and Vector3 types of Pygame are specialized classes that, among other things, redefine the behavior of arithmetic operators to do "vector" operations - that is, in the case of scalar multiplication, multiply both components, and case sum with another object that is a sequence of the same length, add the elements one by one, and generate a new object.

In Python it is very easy to create a class with one or more of these characteristics. Although they are desirable in most gaming programs or others to manipulate images on the screen, it is something considered "if anyone wants, goes there and does", Pygame has not implemented this for more than 15 years, and these two are a recent addition to the code.

Standard Behavior for Sequences

The tuples, lists, arrays, the text strings themselves, bytes and bytearrays, and possibly other objects defined in the standard Python language or library are what we call "sequence" (Sequence) - in vain to respect the protocol defined by methods listed in the MutableSequence linah (or Sequence, if they are immutable) here: link

In addition, for arithmetic operators, these sequences will work like this:

  • + Addition: concatenates two sequences. if the two sequences are of the same type, a new sequence is created which is formed by the elements of the first, followed by elements of the second.
  • * Multplication: is only defined for an integer - it concatenates the sequence with itself N times, where "N" is the second operator. In this sense, the multiplication of sequences in Python works the same as the mathematical definition, where "A * N" is equivalent to "A + A + ..." with N repetitions of the sum.

Other operators (mainly - and / , but also % , ** , and others) are not set to sequence.

Vectors

Now, in a 2-dimensional or 3-dimensional drawing, if I have a distance represented by vector (1, 1), and I want to double that distance, I do not want (1, 1, 1, 1) - and yes (2, 2).

(I tried to find a quick introductory article on vector algebra in Portuguese here, but I think mathematicians are all sadists (with the license for the pinpoint) - all the first search links start from an abstract version of a vector with N dimensions and it only gets worse - we will not be formalized then).

The fact is that in Python if I want a class I set can support custom operations with the arithmetic operators, and even with the operator to retrieve item[x] item used in the sequences, all I need to do is create a method as the appropriate "magic" name within the class. These methods, called "magic", or "dunder methods" are distinguished by always starting and ending with two underscore ( __ ). Everyone who has already learned, or even used without understanding, classes in Python has already used the method __init__ - this is the magic method called to initialize the instance. The __add__ , __sub__ , __mul__ , and __div__ methods are called each time their instance is used in conjunction with one of the 4 arithmetic operators - respectively + - * / . __getitem__ allows you to retrieve items like lists, strings, tuples, and dictionaries.

The documentation for all magic methods used internally by the language is in the document called " data model , but simply creating your class to specialize some of these operators is pretty simple.

(Some methods with the same name type, for example __getstate__ , are used by standard Python library components, such as the pickle module. Their behavior is not considered part of the language itself, so they are not cited in the data model)

Pygame's Vector2 has a few more cool things - for example, it "knows" whether to turn if the other operator is another type of sequence. It provides values both as sequence items ( v[0] ) and by component names (x and y, as v.x ), etc ...

But a class that knows how to do addition and vector multiplication can be simply:

class ListaSoma(list):
   def __add__(self, other):
       if len(self) != len(other): 
           raise ValueError("Só pode ser adicionada a sequências do mesmo tamanho")
       result = ListaSoma()
       for ele_self, ele_other in zip(self, other):
             result.append(ele_self + ele_other)
       return result
   def __mul__(self, other):
       result = ListaSoma()
       for element in self:
            result.append(element * other)
       return result

(Here I use zip to get one element at a time from the instance itself and the other list.)

All other features of a Python list are preserved for this class, due to inheritance - only addition and multiplication are changed:

In [53]: a = ListaSoma([10, 20, 30])

In [54]: a + range(3)
Out[54]: [10, 21, 32]

In [55]: a + range(100, 400, 100)
Out[55]: [110, 220, 330]

In [56]: a * 5
Out[56]: [50, 100, 150]
    
29.09.2018 / 19:57