Skip to content

Commit 51a6cad

Browse files
committed
Merge remote-tracking branch 'upstream/pelican' into copilot/update-workflows-ubuntu-20-04
2 parents b71baea + 15290b4 commit 51a6cad

197 files changed

Lines changed: 17103 additions & 75 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/build-test.yml

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
name: Build Test
2+
3+
on:
4+
push:
5+
branches:
6+
- '*'
7+
- '!pelican'
8+
9+
permissions:
10+
contents: read
11+
12+
jobs:
13+
build:
14+
name: Build
15+
runs-on: ubuntu-latest
16+
steps:
17+
- name: Checkout do repositório
18+
uses: actions/checkout@v5
19+
with:
20+
submodules: recursive
21+
22+
- name: Configura python
23+
uses: actions/setup-python@v6
24+
with:
25+
python-version: "3.5"
26+
cache: pip
27+
28+
- name: Instala dependências
29+
run: pip install -r requirements.txt
30+
31+
- name: Build do site
32+
run: make publish
33+

.github/workflows/github-pages.yml

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
name: GitHub Pages
2+
3+
on:
4+
push:
5+
branches:
6+
- pelican
7+
8+
permissions:
9+
contents: read
10+
11+
concurrency:
12+
group: pages
13+
cancel-in-progress: true
14+
15+
jobs:
16+
build:
17+
name: Build
18+
runs-on: ubuntu-latest
19+
steps:
20+
- name: Checkout do repositório
21+
uses: actions/checkout@v5
22+
with:
23+
submodules: recursive
24+
25+
- name: Configura python
26+
uses: actions/setup-python@v6
27+
with:
28+
python-version: "3.5"
29+
cache: pip
30+
31+
- name: Instala dependências
32+
run: pip install -r requirements.txt
33+
34+
- name: Build do site
35+
run: make publish
36+
37+
- name: Upload do site
38+
uses: actions/upload-pages-artifact@v4
39+
with:
40+
path: output/
41+
42+
deploy:
43+
name: Deploy
44+
needs: build
45+
permissions:
46+
pages: write
47+
id-token: write
48+
runs-on: ubuntu-latest
49+
environment:
50+
name: github-pages
51+
url: ${{ steps.deployment.outputs.page_url }}
52+
steps:
53+
- name: Deploy no GitHub Pages
54+
id: deployment
55+
uses: actions/deploy-pages@v4

.gitignore

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,17 @@ Thumbs.db
1414

1515
# Cache files
1616
cache/*
17+
18+
# Pycharm
19+
.idea
20+
21+
# Virtualenv
22+
venv/
23+
24+
MacOS Files
25+
.DS_Store
26+
27+
# alias
28+
src
29+
30+
.env

.travis.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ language: python
55
python:
66
- 2.7
77
install:
8-
- pip install -r requirements.txt --use-mirrors
8+
- pip install -r requirements.txt
99
script:
1010
- make publish
1111
notifications:
@@ -18,3 +18,4 @@ env:
1818
before_install:
1919
- git submodule update --remote --merge
2020
after_success: bash deploy.sh
21+

README.md

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[pythonclub.com.br][0]
22
======================
3-
Duvidas sobre este projeto, deixe sua mensagem em [![Gitter](https://badges.gitter.im/Join Chat.svg)](https://gitter.im/pythonclub/pythonclub.github.io?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
3+
Duvidas sobre este projeto, deixe sua mensagem em [![Gitter](https://badges.gitter.im/pythonclub/pythonclub.github.io.svg)](https://gitter.im/pythonclub/pythonclub.github.io?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
44

55
Blog colaborativo sobre tecnologias que envolvam a linguagem Python
66

@@ -11,7 +11,7 @@ Como Contribuir
1111
* Faça um fork desse repositório, clicando no botão [![Fork][14]][15], na parte superior direita da pagina do Github
1212
* Clone seu fork:
1313

14-
``git clone --recursive https://github.com/SEU_USUARIO_DO_GITHUB/pythonclub.github.io.git``
14+
``git clone --depth 1 --recursive https://github.com/SEU_USUARIO_DO_GITHUB/pythonclub.github.io.git``
1515

1616
* Instale os requirements ``pip install -r requirements.txt`` - se você não tiver o pip instalado, instale-o: https://pip.pypa.io/en/latest/installing.html#install-pip
1717
* Todas as publicações ficam na pasta ``content``, os textos podem ser escritos
@@ -80,16 +80,6 @@ Para finalizar o servidor use:
8080

8181
``./develop_server.sh stop``
8282

83-
Futuras Publicações
84-
-------------------
85-
86-
Alguns dos contribuidores criaram o compromisso de publicar alguns artigos.
87-
88-
Foi estabelecido um prazo maximo para a entrega dos artigos com o intuito de que o contribuidor realmente publique o artigo com o conteudo que ele mesmo definiu.
89-
90-
Você pode ver a lista contendo os nomes dos artigos nesta planilha no [Google Drive][7].
91-
92-
Quando tiver um assunto e uma data de entrega, adicione na planinha, ao finalizar o seu artigo, envie o pull request e atualize a planilha marcando que sua publicação já foi entregue.
9383

9484
[0]: http://pythonclub.com.br/
9585
[1]: https://pages.github.com/
Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
title: A armadilha dos argumentos com valores padrão
2+
Slug: a-armadilha-dos-argumentos-com-valores-padrao
3+
Date: 2015-06-07 11:00
4+
Tags: python,mutable,function,class,anti-pattern
5+
Author: Diego Garcia
6+
Email: drgarcia1986@gmail.com
7+
Github: drgarcia1986
8+
Site: http://www.codeforcloud.info
9+
Twitter: drgarcia1986
10+
Linkedin: drgarcia1986
11+
Category: anti-patterns
12+
13+
14+
<figure style="float:left;">
15+
<img src="/images/drgarcia1986/is_a_trap.png">
16+
</figure>
17+
</br>
18+
Algo muito comum em várias linguagens de programação é a possibilidade de definir _valores default_ (valores padrão) para argumentos de funções e métodos, tornando a utilização desses opcional.
19+
Isso é ótimo, principalmente para manter retrocompatibilidade, porém, o python possui uma pequena armadilha que caso passe despercebida, pode causar sérios problemas, muitas vezes difíceis de serem detectados.
20+
Essa armadilha ocorre quando usamos valores de tipos `mutáveis` como valor default de argumentos.
21+
22+
<!-- MORE -->
23+
24+
### O que são tipos mutáveis e imutáveis?
25+
Segundo a [documentação oficial do python](https://docs.python.org/3.4/reference/datamodel.html), o valor de alguns objetos pode mudar, esses objetos que podem ter seu valor alterado após serem criados são chamados de mutáveis, enquanto que os objetos que não podem ter seus valores alterados após serem criados são chamados de imutáveis (simples assim).
26+
27+
* **Tipos mutáveis**:
28+
29+
Listas, Dicionários e tipos definidos pelo usuário.
30+
31+
* **Tipos imutáveis**:
32+
33+
Numeros, Strings e Tuplas.
34+
35+
> Apesar de serem imutáveis, a utilização de um valor mutável (uma lista por exemplo) dentro de uma tupla, pode causar o efeito _[tuplas mutáveis](http://pythonclub.com.br/tuplas-mutantes-em-python.html)_, onde visualmente o valor da tupla é alterado, mas por trás dos panos o valor da tupla não muda, o que muda é o valor do objeto pelo qual a tupla está se referenciando.
36+
37+
### A armadilha
38+
Como disse no começo desse blogpost, é muito comum a utilização de valores default em agurmentos de funções e métodos, por essa razão, nos sentimos seguros em fazer algo desse tipo:
39+
40+
```python
41+
def my_function(my_list=[]):
42+
my_list.append(1)
43+
print(my_list)
44+
```
45+
46+
Porém, levando esse exemplo em consideração, o que irá acontecer se invocarmos essa função 3 vezes?
47+
48+
```python
49+
>>> my_function()
50+
[1]
51+
>>> my_function()
52+
[1, 1]
53+
>>> my_function()
54+
[1, 1, 1]
55+
```
56+
Sim, o valor do argumento `my_list` mudou em cada vez que executamos a função sem passar algum valor para ele.
57+
58+
### Por que isso acontece?
59+
Isso acontece porque o python processa os valores default de cada argumentos de uma função (ou método) quando essa for definida, após esse processamento o valor é atribuido ao objeto da função.
60+
Ou seja, por questões de optimização, seguindo nosso exemplo, o python não cria uma lista vazia para o argumento `my_list` a cada vez que a função `my_function` for invocada, ele reaproveita uma lista que foi criada no momento em que essa função foi importada.
61+
62+
```python
63+
>>> my_function.func_defaults
64+
([],)
65+
>>> id(my_function.func_defaults[0])
66+
140634243738080
67+
>>> my_function()
68+
[1]
69+
>>> my_function.func_defaults
70+
([1],)
71+
>>> id(my_function.func_defaults[0])
72+
140634243738080
73+
>>> my_function()
74+
[1, 1]
75+
>>> my_function.func_defaults
76+
([1, 1],)
77+
>>> id(my_function.func_defaults[0])
78+
140634243738080
79+
```
80+
> Note que a identificação do argumento (no caso `my_list`) não muda, mesmo executando a função várias vezes.
81+
82+
Outro exemplo seria utilizar o resultado de funções como valores default de argumentos, por exemplo, uma função com um argumento que recebe como default o valor de `datetime.now()`.
83+
84+
```python
85+
def what_time_is_it(dt=datetime.now()):
86+
print(dt.strftime('%d/%m/%Y %H:%M:%S'))
87+
```
88+
O valor do argumento `dt` sempre será o _datetime_ do momento em que o python carregou a função e não o _datetime_ de quando a função foi invocada.
89+
90+
```python
91+
>>> what_time_is_it()
92+
07/06/2015 08:43:55
93+
>>> time.sleep(60)
94+
>>> what_time_is_it()
95+
07/06/2015 08:43:55
96+
```
97+
98+
### Isso também acontece com classes?
99+
Sim e de uma forma ainda mais perigosa.
100+
101+
```python
102+
class ListNumbers():
103+
def __init__(self, numbers=[]):
104+
self.numbers = numbers
105+
106+
def add_number(self, number):
107+
self.numbers.append(number)
108+
109+
def show_numbers(self):
110+
print(numbers)
111+
```
112+
Assim como no caso das funções, no exemplo acima o argumento `numbers` é definido no momento em que o python importa a classe, ou seja, a cada nova instância da classe `ListNumbers`, será aproveitada a mesma lista no argumento `numbers`.
113+
114+
```python
115+
>>> list1 = ListNumbers()
116+
>>> list2 = ListNumbers()
117+
>>> list1.show_numbers()
118+
[]
119+
>>> list2.show_numbers()
120+
[]
121+
>>> list2.add_number(1)
122+
>>> list1.show_numbers()
123+
[1]
124+
>>> list2.show_numbers()
125+
[1]
126+
>>> list1.numbers is list2.numbers
127+
True
128+
```
129+
130+
### Por que isso não acontece com Strings?
131+
Porque strings são `imutáveis`, o que significa que a cada alteração de valor em uma variavel que armazena uma strings, o python cria uma nova instância para essa variável.
132+
133+
```python
134+
>>> a = 'foo'
135+
>>> id(a)
136+
140398402003832
137+
>>> a = 'bar'
138+
>>> id(a)
139+
140398402003872 # o penúltimo número muda :)
140+
```
141+
142+
Em argumentos com valores default, não é diferente.
143+
144+
```
145+
def my_function(my_str='abc'):
146+
my_str += 'd'
147+
print(my_str)
148+
```
149+
No exemplo acima, sempre que for executado o `inplace add` (`+=`) será criada outra váriavel para `my_str` sem alterar o valor default do argumento.
150+
151+
```python
152+
>>> my_function()
153+
abcd
154+
>>> my_function.func_defaults
155+
('abc',)
156+
>>> my_function()
157+
abcd
158+
>>> my_function.func_defaults
159+
('abc',)
160+
```
161+
162+
### Como se proteger?
163+
A maneira mais simples de evitar esse tipo de surpresa é utilizar um [valor sentinela](http://en.wikipedia.org/wiki/Sentinel_value) como por exemplo `None`, nos argumentos opcionais que esperam tipos mutáveis:
164+
165+
```python
166+
def my_function(my_list=None):
167+
if my_list is None:
168+
my_list = []
169+
my_list.append(1)
170+
print(my_list)
171+
```
172+
173+
Ou, para deixar o código ainda mais elegante, podemos simplificar a condicional com um simples `or`:
174+
175+
```python
176+
def my_function(my_list=None):
177+
my_list = my_list or []
178+
my_list.append(1)
179+
print(my_list)
180+
```
181+
> Obrigado [Bruno Rocha](http://pythonclub.com.br/author/bruno-cezar-rocha.html) pela sugestão.
182+
183+
Pronto, sem surpresas e sem armadilhas :).
184+
185+
```python
186+
>>> my_function()
187+
[1]
188+
>>> my_function()
189+
[1]
190+
>>> my_function()
191+
[1]
192+
```
193+
194+
### Referências
195+
196+
* [Fluent Python (Mutable types as parameter defaults: bad idea)](http://shop.oreilly.com/product/0636920032519.do)
197+
* [Python Anti-Patterns (Using a mutable default value as an argument)](http://docs.quantifiedcode.com/python-anti-patterns/correctness/mutable_default_value_as_argument.html)

0 commit comments

Comments
 (0)