> For the complete documentation index, see [llms.txt](https://carlaprv.gitbook.io/python-fluente/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://carlaprv.gitbook.io/python-fluente/part-1-prologue/chapter-1-the-python-data-model.md).

# Chapter 1 - The Python Data Model

<https://docs.python.org/3/reference/datamodel.html>

* **Dunder methods:** special methods such as `.__getitem__` ou `.__dict__`

### French Deck example

```python
class FrenchDeck:
    ranks = [str(n) for n in range(2, 11)] + list('JQKA') 
    suits = 'spades diamonds clubs hearts'.split()

    def __init__(self):
        self._cards = [Card(rank, suit) for suit in self.suits

    def __len__(self):
        return len(self._cards)

    def __getitem__(self, position): 
        return self._cards[position]
```

* o uso dos atributos `.__getitem__` e `.__len__` torna essa classe uma sequência que pode ser **iterable**. Então, podemos criar laços, sortear um item da instância classe etc.

### Metódo especial `.__getitem__`

In Python’s data model, when you write `foo[i]`, `foo.__getitem__(i)` is called.

```python
list = ['Carla','Leonardo','Carlos']
```

#### Slicing

```python
a[start:stop]  # items start through stop-1
a[start:]      # items start through the rest of the array
a[:stop]       # items from the beginning through stop-1
a[:]           # a copy of the whole array
```

```python
list = ['Carla','Leonardo','Carlos']
```

```python
#input
list[:2]
```

```
['Carla', 'Leonardo']
```

#### Iterable

Just because a method implements `.__getitem__`, it is also iterable

```python
for i in list:
    print(i)
```

```
Carla
Leonardo
Carlos
```

#### `in`

Uses the method `.__contains__`

```python
'Carla' in list
```

```
True
```

#### Sorting

```python
for i in sorted(list):
    print(i)
```

```
Carla
Carlos
Leonardo
```

### Chamada dos métodos especiais

No geral, não precisamos chamar diretamente os métodos especiais - quem faz isso é o interpretador python.

Um dos únicos métodos que usamos diretamente é o `.__init__` - para invocar o inicializador da superclasse - é um **construtor de objetos**.

**Java**

```java
int age
int name

public void abc(int age,int name) {
    this.age = age;
    this.name = xyz;
}
```

**Python**

```python
class Main:
    def __init__(self):
        self._age = None
        self._name = None
    def method(self):
        print self._age, self._name

test = Main()
test.method()
# None None
```

[\* Stackoverflow: Quando devo usar **init** em funções dentro de classes?](https://pt.stackoverflow.com/questions/109013/quando-devo-usar-init-em-fun%C3%A7%C3%B5es-dentro-de-classes)

[\* Java Class Variables & **init** method in Python](https://stackoverflow.com/questions/19303146/java-class-variables-init-method-in-python)

### Managed contexts

<https://book.pythontips.com/en/latest/context_managers.html>

### Operators overloading

> Em java, não é possível fazer isso. Então, temos que criar métodos específicos da classe para realizar essas operações (ex.: `sum`)

<https://pense-python.caravela.club/17-classes-e-metodos/07-sobrecarga-de-operadores.html>

#### Exemplo `Vector`

Nesse caso, implementamos operadores aritméticos para o formato de vetor e mostramos qual deve ser o comportamento se for chamada uma multiplicação ou adição de vetores.

```python
from math import hypot class Vector:

def __init__(self, x=0, y=0): 
    self.x = x
    self.y = y

def __repr__(self):
    return 'Vector(%r, %r)' % (self.x, self.y) 

def __abs__(self):
    return hypot(self.x, self.y) 

def __bool__(self):
    return bool(abs(self))

def __add__(self, other): 
    x = self.x + other.x 
    y = self.y + other.y 
    return Vector(x, y)

def __mul__(self, scalar):
    return Vector(self.x * scalar, self.y * scalar)
```

#### `__string__` x `__repr__`

<https://www.geeksforgeeks.org/str-vs-repr-in-python/>

<https://stackoverflow.com/questions/1436703/difference-between-str-and-repr>

O [`__str__`](https://docs.python.org/2/library/string.html) serve para exibir o objeto para usuário final, usada pelo comando print e pela função str.

O [`__repr__`](https://docs.python.org/2/library/functions.html#repr) serve para exibir o objeto para o programador, usada pelo console do Python e pela funçao repr.

\* Dar preferência à implementação do `__repr__` - fallback

### Method overloading

Diferentes formas de chamar o mesmo método.

![](https://i.imgur.com/pBAPVT4.png)

<https://pythonspot.com/method-overloading/>

#### `__bool__` and `__len__`

O tipo bool em python aceita qualquer tipo de objeto através de `bool(x)` que chama `x.__bool__()`.

* Se o **bool** não estiver implementado:
  * Python invoca `x.__len__()` (se retornar zero, será **false**)

### Why len is not a method

> No method is called for the built-in objects of CPython: the length is simply read from a field in a C struct.
