Browse Source

Merge branch 'master' of github.com:jbiason/presentations

master
Julio Biason 10 years ago
parent
commit
6db587880c
  1. 2
      README.md
  2. 1
      _external/highlight-default.min.css
  3. 1
      _external/highlight.min.js
  4. 154
      _external/obsidian.css
  5. BIN
      _images/ajax-sosp-cors-csrf.png
  6. BIN
      _images/boring.gif
  7. BIN
      _images/gtg-plugins.png
  8. BIN
      _images/gtg.png
  9. BIN
      _images/hamster-extension.png
  10. BIN
      _images/hamster-totals.png
  11. BIN
      _images/hamster.png
  12. BIN
      _images/intermission_3696.jpg
  13. BIN
      _images/neat.jpg
  14. BIN
      _images/pylint.png
  15. BIN
      _images/tumblr_n6qbpoBDVX1rbyj0do1_500.jpg
  16. 374
      ajax-sosp-cors-csrf.html
  17. 7
      gitsvn.html
  18. 143
      gtg-hamster.html
  19. 15
      index.html
  20. 407
      pylint.html
  21. 610
      python.html

2
README.md

@ -1,3 +1,5 @@
# README #
A bunch of my presentions, in [Reveal.js](http://lab.hakim.se/reveal-js/) format, most (if not all) in Portuguese.
The canonical place for these presentations is [in my website](http://juliobiason.net/presentations/).

1
_external/highlight-default.min.css vendored

@ -0,0 +1 @@
.hljs{display:block;padding:.5em;background:#f0f0f0}.hljs,.hljs-subst,.hljs-tag .hljs-title,.lisp .hljs-title,.clojure .hljs-built_in,.nginx .hljs-title{color:black}.hljs-string,.hljs-title,.hljs-constant,.hljs-parent,.hljs-tag .hljs-value,.hljs-rules .hljs-value,.hljs-rules .hljs-value .hljs-number,.hljs-preprocessor,.hljs-pragma,.haml .hljs-symbol,.ruby .hljs-symbol,.ruby .hljs-symbol .hljs-string,.hljs-aggregate,.hljs-template_tag,.django .hljs-variable,.smalltalk .hljs-class,.hljs-addition,.hljs-flow,.hljs-stream,.bash .hljs-variable,.apache .hljs-tag,.apache .hljs-cbracket,.tex .hljs-command,.tex .hljs-special,.erlang_repl .hljs-function_or_atom,.asciidoc .hljs-header,.markdown .hljs-header,.coffeescript .hljs-attribute{color:#800}.smartquote,.hljs-comment,.hljs-annotation,.hljs-template_comment,.diff .hljs-header,.hljs-chunk,.asciidoc .hljs-blockquote,.markdown .hljs-blockquote{color:#888}.hljs-number,.hljs-date,.hljs-regexp,.hljs-literal,.hljs-hexcolor,.smalltalk .hljs-symbol,.smalltalk .hljs-char,.go .hljs-constant,.hljs-change,.lasso .hljs-variable,.makefile .hljs-variable,.asciidoc .hljs-bullet,.markdown .hljs-bullet,.asciidoc .hljs-link_url,.markdown .hljs-link_url{color:#080}.hljs-label,.hljs-javadoc,.ruby .hljs-string,.hljs-decorator,.hljs-filter .hljs-argument,.hljs-localvars,.hljs-array,.hljs-attr_selector,.hljs-important,.hljs-pseudo,.hljs-pi,.haml .hljs-bullet,.hljs-doctype,.hljs-deletion,.hljs-envvar,.hljs-shebang,.apache .hljs-sqbracket,.nginx .hljs-built_in,.tex .hljs-formula,.erlang_repl .hljs-reserved,.hljs-prompt,.asciidoc .hljs-link_label,.markdown .hljs-link_label,.vhdl .hljs-attribute,.clojure .hljs-attribute,.asciidoc .hljs-attribute,.lasso .hljs-attribute,.coffeescript .hljs-property,.hljs-phony{color:#88F}.hljs-keyword,.hljs-id,.hljs-title,.hljs-built_in,.hljs-aggregate,.css .hljs-tag,.hljs-javadoctag,.hljs-phpdoc,.hljs-yardoctag,.smalltalk .hljs-class,.hljs-winutils,.bash .hljs-variable,.apache .hljs-tag,.go .hljs-typename,.tex .hljs-command,.asciidoc .hljs-strong,.markdown .hljs-strong,.hljs-request,.hljs-status{font-weight:bold}.asciidoc .hljs-emphasis,.markdown .hljs-emphasis{font-style:italic}.nginx .hljs-built_in{font-weight:normal}.coffeescript .javascript,.javascript .xml,.lasso .markup,.tex .hljs-formula,.xml .javascript,.xml .vbscript,.xml .css,.xml .hljs-cdata{opacity:.5}

1
_external/highlight.min.js vendored

File diff suppressed because one or more lines are too long

154
_external/obsidian.css vendored

@ -0,0 +1,154 @@
/**
* Obsidian style
* ported by Alexander Marenin (http://github.com/ioncreature)
*/
.hljs {
display: block; padding: 0.5em;
background: #282B2E;
}
.hljs-keyword,
.hljs-literal,
.hljs-change,
.hljs-winutils,
.hljs-flow,
.lisp .hljs-title,
.clojure .hljs-built_in,
.nginx .hljs-title,
.css .hljs-id,
.tex .hljs-special {
color: #93C763;
}
.hljs-number {
color: #FFCD22;
}
.hljs {
color: #E0E2E4;
}
.css .hljs-tag,
.css .hljs-pseudo {
color: #D0D2B5;
}
.hljs-attribute,
.hljs .hljs-constant {
color: #668BB0;
}
.xml .hljs-attribute {
color: #B3B689;
}
.xml .hljs-tag .hljs-value {
color: #E8E2B7;
}
.hljs-code,
.hljs-class .hljs-title,
.hljs-header {
color: white;
}
.hljs-class,
.hljs-hexcolor {
color: #93C763;
}
.hljs-regexp {
color: #D39745;
}
.hljs-at_rule,
.hljs-at_rule .hljs-keyword {
color: #A082BD;
}
.hljs-doctype {
color: #557182;
}
.hljs-link_url,
.hljs-tag,
.hljs-tag .hljs-title,
.hljs-bullet,
.hljs-subst,
.hljs-emphasis,
.haskell .hljs-type,
.hljs-preprocessor,
.hljs-pragma,
.ruby .hljs-class .hljs-parent,
.hljs-built_in,
.sql .hljs-aggregate,
.django .hljs-template_tag,
.django .hljs-variable,
.smalltalk .hljs-class,
.hljs-javadoc,
.django .hljs-filter .hljs-argument,
.smalltalk .hljs-localvars,
.smalltalk .hljs-array,
.hljs-attr_selector,
.hljs-pseudo,
.hljs-addition,
.hljs-stream,
.hljs-envvar,
.apache .hljs-tag,
.apache .hljs-cbracket,
.tex .hljs-command,
.hljs-prompt {
color: #8CBBAD;
}
.hljs-string {
color: #EC7600;
}
.hljs-comment,
.java .hljs-annotation,
.hljs-blockquote,
.hljs-horizontal_rule,
.python .hljs-decorator,
.hljs-template_comment,
.hljs-pi,
.hljs-deletion,
.hljs-shebang,
.apache .hljs-sqbracket,
.tex .hljs-formula {
color: #818E96;
}
.hljs-keyword,
.hljs-literal,
.css .hljs-id,
.hljs-phpdoc,
.hljs-title,
.hljs-header,
.haskell .hljs-type,
.vbscript .hljs-built_in,
.sql .hljs-aggregate,
.rsl .hljs-built_in,
.smalltalk .hljs-class,
.diff .hljs-header,
.hljs-chunk,
.hljs-winutils,
.bash .hljs-variable,
.apache .hljs-tag,
.tex .hljs-special,
.hljs-request,
.hljs-at_rule .hljs-keyword,
.hljs-status {
font-weight: bold;
}
.coffeescript .javascript,
.javascript .xml,
.tex .hljs-formula,
.xml .javascript,
.xml .vbscript,
.xml .css,
.xml .hljs-cdata {
opacity: 0.5;
}

BIN
_images/ajax-sosp-cors-csrf.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 552 KiB

BIN
_images/boring.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

BIN
_images/gtg-plugins.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

BIN
_images/gtg.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

BIN
_images/hamster-extension.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

BIN
_images/hamster-totals.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

BIN
_images/hamster.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

BIN
_images/intermission_3696.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
_images/neat.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

BIN
_images/pylint.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

BIN
_images/tumblr_n6qbpoBDVX1rbyj0do1_500.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

374
ajax-sosp-cors-csrf.html

@ -0,0 +1,374 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>AJAX/SOSP/CORS/CSRF</title>
<meta name="author" content="Julio Biason">
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<link rel="stylesheet" href="_external/reveal.min.css">
<link rel="stylesheet" href="_external/night.css" id="theme">
<!-- For syntax highlighting -->
<link rel="stylesheet" href="_external/zenburn.css">
<!-- If the query includes 'print-pdf', include the PDF print sheet -->
<script>
if( window.location.search.match( /print-pdf/gi ) ) {
var link = document.createElement( 'link' );
link.rel = 'stylesheet';
link.type = 'text/css';
link.href = '_external/pdf.css';
document.getElementsByTagName( 'head' )[0].appendChild( link );
}
</script>
<!--[if lt IE 9]>
<script src="reveal.js/lib/js/html5shiv.js"></script>
<![endif]-->
<style>
.semi-opaque {
background-color: rgba(0, 0, 0, 0.7);
}
* {
hyphens: none !important;
-moz-hyphens: none !important;
}
</style>
</head>
<body>
<div class="reveal">
<!-- Any section element inside of this container is displayed as a slide -->
<div class="slides">
<section data-background='_images/ajax-sosp-cors-csrf.png' class='semi-opaque'>
<h1>AJAX / SOSP / CORS / CSRF</h1>
<p class='fragment'><small>
(Ou 4 siglas, 16 letras e uma dor de cabeça)
</small></p>
</section>
<section>
<h2>Agenda</h2>
<p>Mostrar como aplicações web ricas se comportam quando
o conteúdo está vindo de uma fonte que não a fonte original.</p>
</section>
<section>
<h2>A Idéia</h2>
<p>Gerar uma view com conteúdo que será inserido em outro site;
o conteúdo deverá abrir um modal para pedir mais dados para o
usuário.</p>
</section>
<section>
<h2>Passo 1: O Conteúdo</h2>
<p>Carregado por AJAX, com jQuery. Fácil.</p>
<p><pre><code data-trim>
$(function() {
$("#div-especial").load("http://outrosite.com/conteudo.html");
});
</code></pre></p>
</section>
<section>
<section>
<h2>Problema 1: SOSP (Same Origin Security Policy)</h2>
</section>
<section>
<p>Same Origin Security Policy é assegurado pelo browser, barrando
requisições vindas de lugares que não são o lugar original.</p>
<p class='fragment'>"Lugar original" = URL requisitada
tem mesmo esquema (http vs https), mesmo domínio
(subdomínios não contam), mesma porta (ou implício
80) da URL que está fazendo a requisição.</p>
</section>
<section>
<p>Página em <code>http://outrosite.com/conteudo.html</code> pede:</p>
<ul>
<li class='fragment'><code>http://outrosite.com/dados.json</code> &#8658; OK</li>
<li class='fragment'><code>http://outrosite.com/<strong>dir</strong>/dados.json</code> &#8658; OK</li>
<li class='fragment'><code>http://<strong>usuário:senha</strong>@outrosite.com/dir/dados.json</code> &#8658; OK</li>
<li class='fragment'><code>http://outrosite.com<strong>:8080</strong>/dados.json</code> &#8658; NOT!</li>
<li class='fragment'><code><strong>https</strong>://outrosite.com/dados.json</code> &#8658; NOT!</li>
<li class='fragment'><code>http://<strong>api.</strong>outrosite.com/dados.json</code> &#8658; NOT!</li>
<li class='fragment'><code>http://outrosite.com<strong>:80</strong>/dados.json</code> &#8658; talvez...</li>
</ul>
</section>
<section>
<p>Apenas lembrando: isso é forçado pelo
<em>browser</em>, não pelo serviço.</p>
<p>Outras aplicações podem passar por cima do Same
Origin se quiserem.</p>
</section>
<section>
<p>Restrições de subdomínios podem ser relaxadas se
scripts forem carregados de subdomínios
diferentes:</p>
<p>Se a página em <code>http://outrosite.com/</code>
carregar um script de
<code>http://api.outrosite.com</code>, a restrição de
subdomínios pode ser removida para funções do
script.</p>
</section>
<section>
<p>Se não tiver como relaxar as restrições, utiliza-se
CORS.</p>
</section>
</section>
<section>
<section>
<h2>Problema 2: CORS (Cross-Origin Resource Sharing)</h2>
</section>
<section>
<p>CORS é implementado no servidor e diz se o serviço
pode ou não utilizar aquele recurso.</p>
</section>
<section>
<p>Browser rodando em <code>http://outrosite.com</code>
requisita serviço em
<code>http://api.outrosite.com/</code>.</p>
<p>Para isso, envia o header <code>Origin</code>.</p>
<p><pre><code data-trim>
Origin: http://outrosite.com
</code></pre></p>
</section>
<section>
<p>Servidor olha o header, verifica se a URL tem permissão
para acessar os recursos, é retornado o header
<code>Access-Control-Allow-Origin</code>.</p>
<p><pre><code data-trim>
Access-Control-Allow-Origin: http://outrosite.com
</code></pre></p>
</section>
<section>
<p>De novo, isso é controlado pelo <em>browser</em>; um
browser que não siga corretamente o controle de acesso ou um
aplicativo qualquer poderiam passar por cima dessa restrição
e continuar lendo o conteúdo.</p>
</section>
<section>
<h3>Django-CORS-Headers</h3>
<p>App para configurar CORS sozinho.</p>
<p><pre><code data-trim>
CORS_ORIGIN_WHITELIST = (
'outrosite.com',
)
</code></pre></p>
<p>ou</p>
<p><pre><code data-trim>
CORS_ORIGIN_REGEX_WHITELIST = (
'^(https?://)?(\w+\.)?outrosite\.com$',
)
</code></pre></p>
</section>
<section>
<p>Agora o site externo consegue carregar o conteúdo das
views.</p>
</section>
</section>
<section>
<section>
<h2>Problema 2.5: URLs reversas</h2>
</section>
<section>
<p>Para resolver URLs, usamos a tag <code>{% url vew_id %}</code>
para retornar a URL da view.</p>
<p>O problema é que é retornada a URL absoluta para a view,
sem considerar o domínio da view.</p>
</section>
<section>
<p><pre><code data-trim>
&lt;a href='/view/'&gt;
</code></pre></p>
<p>em <code>http://outrosite.com</code> vira
<code>http://outrosite.com/view/</code>.</p>
<p>Mas se a view estiver num domínio diferente, o mesmo
não é considerado.</p>
</section>
<section>
<ul>
<li>Se <code>http://outrosite.com</code> carregar o conteúdo
de <code>http://api.outrosite.com</code></li>
<li class='fragment'>... e <code>http://api.outrosite.com</code> tiver uma view
com URL absoluta <code>/view/</code></li>
<li class='fragment'>... o browser irá resolver como
<code>http://outrosite.com/view/</code></li>
<li class='fragment'>... quando deveria ser
<code>http://api.outrosite.com/view/</code>.</li>
</ul>
</section>
<section>
<p>Solução: considerar que <code>SITE_URL</code> (do
<code>settings.py</code>) está correto e usar nas URLs.</p>
<p><pre><code data-trim>
&lt;a href='{{ settings.SITE_URL }}{% url "view_id" %}'&gt;
</code></pre></p>
</section>
</section>
<section>
<section>
<h2>Problema 3: CSRF</h2>
</section>
<section>
<p>Resumo:</p>
<ul>
<li>"csrftoken" é gerado na sessão do usuário.</li>
<li>Campo "csrftoken" é adicionado no form.</li>
<li>Quando o form retorna no POST, é verificado se é o
mesmo indicado na sessão do usuário.</li>
</ul>
</section>
<section>
<p>Problema: Informações do token é passada num cookie.</p>
<p><pre><code>
Set-Cookie: "csrftoken=t5HBi8EbkPk340nnpkdb8qxQsy2n8LwY;
expires=Tue, 04-Aug-2015 16:40:38 GMT; Max-Age=31449600; Path=/"
</code></pre></p>
<p>Cookies não são processados durante requisições AJAX.</p>
</section>
<section>
<p>Solução correta:</p>
<p>Ao receber uma requisição AJAX, processar os headers também,
verificar a existência de "Set-Cookie", verificar se "csrftoken"
está na lista, guardar o valor e usar nas requisições seguintes.</p>
</section>
<section>
<p>Solução utilizada:</p>
<p><pre><code>
from django.views.decorators.csrf import csrf_exempt
@csrf_exempt
def minha_view(request):
....
</code></pre></p>
</section>
</section>
<section>
<section>
<h2>Problema 3.5: CSRF em Class Based Views</h2>
</section>
<section>
<p><pre><code>
class MinhaView(View):
@csrf_exempt
def post(self, request):
....
</code></pre> </p>
<p>... não funciona.</p>
</section>
<section>
<p>É preciso aplicar decorators no dispatch da view:</p>
<p><pre><code>
@csrf_exempt
def dispatch(self, *args, **kwargs):
u"""Altera o dispatch para dispensar CSRF (por cauxa do AJAX)."""
return super(MinhaView, self).dispatch(*args, **kwargs)
</code></pre></p>
</section>
</section>
<section data-background='_images/thats-all-folks.jpg'>
<p></p>
</section>
<section data-background='_images/thats-all-folks.jpg' class='semi-opaque'>
Dica: Evite ter objetos cortantes próximos quando estiver lidando
com AJAX/SOSP/CORS/CSRF.
</section>
</div>
</div>
<script src="_external/head.min.js"></script>
<script src="_external/reveal.min.js"></script>
<script>
// Full list of configuration options available here:
// https://github.com/hakimel/reveal.js#configuration
Reveal.initialize({
controls: true,
progress: true,
history: true,
center: true,
theme: 'night',
transition: 'linear',
// Optional libraries used to extend on reveal.js
dependencies: [
{ src: '_external/classList.js', condition: function() { return !document.body.classList; } },
{ src: '_external/marked.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } },
{ src: '_external/markdown.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } },
{ src: '_external/highlight.js', async: true, callback: function() { hljs.initHighlightingOnLoad(); } },
{ src: '_external/zoom.js', async: true, condition: function() { return !!document.body.classList; } },
{ src: '_external/notes.js', async: true, condition: function() { return !!document.body.classList; } }
]
});
</script>
</body>
</html>

7
gitsvn.html

@ -150,7 +150,12 @@ Stage this hunk [y,n,q,a,d,/,e,?]?
<h3><code>git log</code></h3>
<ul>
<li>Igual ao <code>svn log</code>, mas não precisa de less (e nada de "broken pipe" ao fechar o log).</li>
<li>Igual ao <code>svn log</code>, mas não precisa de less e faz stream do conteúdo.
<ul>
<li>Isso significa que não é preciso esperar o log inteiro
ser gerado para o less apresentar e não ocorrem
mais "broken pipes" ao fechar o less.</li>
</ul></li>
<li>Cores!</li>
<li><code>git log --raw</code>: mostra os arquivos alterados dentro da revisão.</li>
<li><code>git log -p</code>: mostra as alterações dentro da revisão.</li>

143
gtg-hamster.html

@ -0,0 +1,143 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Timetracking com Get Things GNOME + Hamster</title>
<meta name="author" content="Julio Biason">
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<link rel="stylesheet" href="_external/reveal.min.css">
<link rel="stylesheet" href="_external/default.css" id="theme">
<!-- For syntax highlighting -->
<link rel="stylesheet" href="_external/zenburn.css">
<!-- If the query includes 'print-pdf', include the PDF print sheet -->
<script>
if( window.location.search.match( /print-pdf/gi ) ) {
var link = document.createElement( 'link' );
link.rel = 'stylesheet';
link.type = 'text/css';
link.href = '_external/pdf.css';
document.getElementsByTagName( 'head' )[0].appendChild( link );
}
</script>
<!--[if lt IE 9]>
<script src="reveal.js/lib/js/html5shiv.js"></script>
<![endif]-->
<style>
.semi-opaque {
background-color: rgba(0, 0, 0, 0.7);
}
* {
hyphens: none !important;
-moz-hyphens: none !important;
}
img {
height: 400px;
}
</style>
</head>
<body>
<div class="reveal">
<!-- Any section element inside of this container is displayed as a slide -->
<div class="slides">
<section>
<h1>Timetracking com Get Things GNOME + Project Hamster</h1>
</section>
<section>
<h2>O que é o que?</h2>
</section>
<section>
<h3>Get Things GNOME</h3>
<img src='_images/gtg.png'>
<p>Controle de coisas pra fazer (TODO).</p>
</section>
<section>
<h3>Get Things GNOME</h3>
<img src='_images/gtg-plugins.png'>
<p>Plugin para ativar a opção de "Star Task on Hamster".</p>
</section>
<section>
<h3>Project Hamster</h3>
<img src='_images/hamster.png'>
<p>Controle de tempo de tarefas (qualquer tarefa).</p>
</section>
<section>
<h3>Project Hamster</h3>
<img src='_images/hamster-totals.png'>
<p>Tempo total dispendido por tarefa.</p>
</section>
<section>
<h3>Bônus para usuários GNOME 3:</h3>
<img src='_images/hamster-extension.png'>
<p>Extension para GNOME 3 em
<a href="http://extensions.gnome.org">Extensions.GNOME.ORG</a>.</p>
</section>
<section data-background='_images/thats-all-folks.jpg'>
<section></section>
</section>
</div>
</div>
<script src="_external/head.min.js"></script>
<script src="_external/reveal.min.js"></script>
<script>
// Full list of configuration options available here:
// https://github.com/hakimel/reveal.js#configuration
Reveal.initialize({
controls: true,
progress: true,
history: true,
center: true,
theme: 'default',
transition: 'linear',
// Optional libraries used to extend on reveal.js
dependencies: [
{ src: '_external/classList.js', condition: function() { return !document.body.classList; } },
{ src: '_external/marked.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } },
{ src: '_external/markdown.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } },
{ src: '_external/highlight.js', async: true, callback: function() { hljs.initHighlightingOnLoad(); } },
{ src: '_external/zoom.js', async: true, condition: function() { return !!document.body.classList; } },
{ src: '_external/notes.js', async: true, condition: function() { return !!document.body.classList; } }
]
});
</script>
</body>
</html>

15
index.html

@ -69,6 +69,21 @@ ul.inline-list li {
<div class='thumb' style='background-image:url("_images/flask.png")'></div>
Flask
</a></li>
<li><a href='gtg-hamster.html'>
<div class='thumb'></div>
GTG + Hamster
</a></li>
<li><a href='ajax-sosp-cors-csrf.html'>
<div class='thumb' style='background-image:url("_images/ajax-sosp-cors-csrf.png")'></div>
AJAX/SOSP/CORS/CSRF
</a></li>
<li><a href='pylint.html'>
<div class='thumb' style='background-image:url("_images/pylint.png")'></div>
Pylint, Warnings e Correções
</a></li>
</ul>
</div>
</div>

407
pylint.html

@ -0,0 +1,407 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Pylint, Warnings e Correções</title>
<meta name="author" content="Julio Biason">
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<link rel="stylesheet" href="_external/reveal.min.css">
<link rel="stylesheet" href="_external/night.css" id="theme">
<!-- For syntax highlighting -->
<link rel="stylesheet" href="_external/zenburn.css">
<!-- If the query includes 'print-pdf', include the PDF print sheet -->
<script>
if( window.location.search.match( /print-pdf/gi ) ) {
var link = document.createElement( 'link' );
link.rel = 'stylesheet';
link.type = 'text/css';
link.href = '_external/pdf.css';
document.getElementsByTagName( 'head' )[0].appendChild( link );
}
</script>
<!--[if lt IE 9]>
<script src="reveal.js/lib/js/html5shiv.js"></script>
<![endif]-->
<style>
.semi-opaque {
background-color: rgba(0, 0, 0, 0.7);
}
* {
hyphens: none !important;
-moz-hyphens: none !important;
}
div.code {
font-size: 150%
}
</style>
</head>
<body>
<div class="reveal">
<!-- Any section element inside of this container is displayed as a slide -->
<div class="slides">
<section data-background='_images/pylint.png' class='semi-opaque'>
<h1>Pylint, Warnings e Correções</h1>
</section>
<section>
<section>
<h2><code>missing-docstring</code></h2>
</section>
<section>
<h2>O que é o erro</h2>
<div class='code'>
<p><pre><code data-trim class='python'>
def funcao(valor):
return valor * 2
</code></pre></p>
</div>
</section>
<section>
<h2>Solução</h2>
<p>Documente suas funções!</p>
</section>
</section>
<section>
<section>
<h2><code>wildcard-import</code></h2>
</section>
<section>
<h2>O que é o erro</h2>
<div class='code'>
<p><pre><code data-trim class='python'>
from module import *
</code></pre></p>
</div>
</section>
<section>
<h2>Solução</h2>
<p>Importe apenas as funções módulos que são usados.</p>
</section>
<section>
<h2>Por que não usar "import *"</h2>
<ul>
<li>O módulo pode ter código não protegido por
função, classe ou <code>if __name__ == '__main__'</code></li>
<li>Poluíção do namespace.</li>
<li>Módulo pode redefinir uma função presente no
módulo atual.</li>
</ul>
</section>
</section>
<section>
<section>
<h2><code>unused-import</code></h2>
</section>
<section>
<h2>O que é o erro</h2>
<div class='code'>
<p><pre><code data-trim class='python'>
from module import function
</code></pre></p>
</div>
<p>(E <code>function()</code> não é usado em lugar algum.)</p>
</section>
<section>
<h2>Solução</h2>
<p>Remova o import.</p>
</section>
<section>
<h2>Dica!</h2>
<p>Quebrar imports em várias linhas facilita correção desse
tipo de problema.</p>
<div class='code'>
<p><pre><code data-trim class='python'>
from module import func1
from module import func2
</pre></code></p>
</div>
</section>
</section>
<section>
<section>
<h2><code>unused-argument</code></h2>
</section>
<section>
<h2>O que é o erro</h2>
<div class='code'>
<p><pre><code data-trim>
def func(arg1, arg2):
return arg1 * 2
</pre></code></p>
</div>
</section>
<section>
<h2>Solução</h2>
<ul>
<li>Remova o parâmetro desnecessário</li>
<li>Altere o parâmetro para "_"</li>
</ul>
</section>
<section>
<h2>Corner case</h2>
<div class='code'>
<p><pre><code data-trim class='python'>
def addSeven(foo): # "Unused argument 'foo'"
foo += [7]
</code></pre></p>
</div>
<p>O problema é a questão de referência para objetos
mutáveis. O código em si está errado.</p>
</section>
</section>
<section>
<section>
<h2><code>bare-except</code></h2>
</section>
<section>
<h2>O que é o erro</h2>
<div class='code'>
<p><pre><code data-trim class='python'>
try:
func()
except Exception e:
pass
</code></pre></p>
</div>
</section>
<section>
<h2>Solução</h2>
<p>Capture apenas as exceções que você sabe lidar.</p>
</section>
</section>
<section>
<section>
<h2><code>no-self-use</code></h2>
</section>
<section>
<h2>O que é o erro</h2>
<div class='code'>
<p><pre><code data-trim class='python'>
class A(object):
def func(self, a):
return a * 2
</code></pre></p>
</div>
</section>
<section>
<h2>Solução</h2>
<p>A solução mais "correta" é tirar a função da classe e deixar
fora do objeto.</p>
<p class='fragment'>Não sendo possível,
<code># pylint:disable=no-self-use</code> antes da função.
</p>
</section>
</section>
<section>
<section>
<h2><code>old-style-class</code></h2>
</section>
</section>
<section>
<section>
<h2><code>super-on-old-class</code></h2>
</section>
</section>
<section>
<section>
<h2><code>no-init</code></h2>
</section>
</section>
<section>
<section>
<h2><code>super-init-not-called</code></h2>
</section>
</section>
<section>
<section>
<h2><code>attribute-defined-outside-init</code></h2>
</section>
</section>
<section>
<section>
<h2><code>abstract-method</code></h2>
</section>
</section>
<section>
<section>
<h2><code>arguments-differ</code></h2>
</section>
</section>
<section>
<section>
<h2><code>no-member</code> e <code>maybe-no-member</code></h2>
</section>
</section>
<section>
<section>
<h2><code>no-value-for-parameter</code></h2>
</section>
</section>
<section>
<section>
<h2><code>protected-access</code></h2>
</section>
</section>
<section>
<section>
<h2><code>too-few-public-methods</code></h2>
</section>
</section>
<section>
<section>
<h2><code>too-many-ancestors</code></h2>
</section>
</section>
<section>
<section>
<h2><code>too-many-arguments</code></h2>
</section>
</section>
<section>
<section>
<h2><code>too-many-branches</code></h2>
</section>
</section>
<section>
<section>
<h2><code>too-many-instance-attributes</code></h2>
</section>
</section>
<section>
<section>
<h2><code>too-many-lines</code></h2>
</section>
</section>
<section>
<section>
<h2><code>too-many-locals</code></h2>
</section>
</section>
<section>
<section>
<h2><code>too-many-public-methods</code></h2>
</section>
</section>
<section>
<section>
<h2><code>too-many-statements</code></h2>
</section>
</section>
<section>
<section>
<h2><code>invalid-name</code></h2>
</section>
</section>
<section>
<section>
<h2><code>star-args</code></h2>
</section>
</section>
</div>
</div>
<script src="_external/head.min.js"></script>
<script src="_external/reveal.min.js"></script>
<script>
// Full list of configuration options available here:
// https://github.com/hakimel/reveal.js#configuration
Reveal.initialize({
controls: true,
progress: true,
history: true,
center: true,
theme: 'night',
transition: 'linear',
// Optional libraries used to extend on reveal.js
dependencies: [
{ src: '_external/classList.js', condition: function() { return !document.body.classList; } },
{ src: '_external/marked.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } },
{ src: '_external/markdown.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } },
{ src: '_external/highlight.js', async: true, callback: function() { hljs.initHighlightingOnLoad(); } },
{ src: '_external/zoom.js', async: true, condition: function() { return !!document.body.classList; } },
{ src: '_external/notes.js', async: true, condition: function() { return !!document.body.classList; } }
]
});
</script>
</body>
</html>
<!-- vim:set et ts=4 sts=4 st=4: >

610
python.html

@ -15,9 +15,11 @@
<link rel="stylesheet" href="_external/reveal.min.css">
<link rel="stylesheet" href="_external/default.css" id="theme">
<link rel='stylesheet' href='_external/hightlight-default.min.css'>
<!-- For syntax highlighting -->
<link rel="stylesheet" href="_external/zenburn.css">
<!-- <link rel="stylesheet" href="_external/zenburn.css"> -->
<link rel='stylesheet' href='_external/obsidian.css'>
<!-- If the query includes 'print-pdf', include the PDF print sheet -->
<script>
@ -49,7 +51,6 @@
<body>
<div class="reveal">
<!-- Any section element inside of this container is displayed as a slide -->
<div class="slides">
<section data-background='_images/zen-of-python-poster-a3.png' class='semi-opaque'>
<h1>Python</h1>
@ -64,12 +65,27 @@
<ul>
<li>Linguagem interpretada.</li>
<li>Dinamicamente tipada.</li>
<li>Principais usos em pesquisas e web.
<ul>
<li>Assim como o Linux "vazou" dos servidores para os
Desktops, Python parece estar "vazando" do meio acadêmico/pesquisa
para os servidores.</li>
</ul>
</li>
</ul>
</section>
</section>
<section>
<section>
<h2>O Zen de Python</h2>
<p>Começou em uma brincadeira do Tim Peters (um dos desenvolvedores do Python),
mas acabou virando um PEP (PEP 20) e hoje faz parte da filosofia de desenvolvimento
do Python.</p>
</section>
<section>
<ul>
<li>Bonito é melhor que feio.</li>
<li>Explícito é melhor que implícito.</li>
@ -83,20 +99,24 @@
<section>
<ul>
<li>Casos especiais não são especiais o suficiente para quebrar as regras.</li>
<li>Embora praticabilidade ganhe de puridade.</li>
<li>Erros nunca devem passam silenciosamente.</li>
<li>A não ser que sejam explicitamente silenciados.</li>
<li>Casos especiais não são especiais o suficiente para quebrar as regras.
<ul><li>Embora praticabilidade ganhe de puridade.</li></ul>
</li>
<li>Erros nunca devem passam silenciosamente.
<ul><li>A não ser que sejam explicitamente silenciados.</li></ul>
</li>
<li>Em caso de ambiguidade, evite a tentação de adivinhar.</li>
<li>Deve haver um -- e preferencialmente apenas um -- modo óbvio de fazer algo.</li>
<li>Embora talvez não seja tão óbvio de primeira a não ser que você seja Holandês.</li>
<li>Deve haver um -- e preferencialmente apenas um -- modo óbvio de fazer algo.
<ul><li>Embora talvez não seja tão óbvio de primeira a não ser que você seja Holandês.</li></ul>
</li>
</ul>
</section>
<section>
<ul>
<li>Agora é melhor do que nunca.</li>
<li>Embora nunca seja melhor que <i>agora mesmo</i>.</li>
<li>Agora é melhor do que nunca.
<ul><li>Embora nunca seja melhor que <i>agora mesmo</i>.</li></ul>
</li>
<li>Se a implementação é difícil de explicar, é uma péssima idéia.</li>
<li>Se a implementação é fácil de explicar, pode ser uma boa idéia.</li>
<li>Namespaces são uma grande idéia - vamos fazer mais desses!</li>
@ -104,6 +124,126 @@
</section>
</section>
<section>
<section>
<h2>As Esquisitices de Python</h2>
</section>
<section>
<h3>PEP8</h3>
</section>
<section>
<ol>
<li>PEPs (Python Enhancement Proposal) são as RFCs que os desenvolvedores
Python utilizam para comunicar novas funcionalidades.
<ul>
<li>Todos os PEPs podem ser encontados em
<a href='http://legacy.python.org/dev/peps/'>http://legacy.python.org/dev/peps/</a>.</li>
</ul>
<li>Uma funcionalidade não é simplesmente "aceita": É preciso escrever
uma proposta de melhoria explicando o problema encontra e como corrigí-lo.
</li>
<li>PEP8 define a melhor forma de se programar em Python.</li>
<li>PEP8 não é forçado pelo compilador.</li>
<li>PEP8 garante que qualquer programador Python consiga facilmente
encontrar coisas em códigos criados por terceiros.</li>
</ol>
</section>
<section>
<h4>Um pouco do PEP8:</h4>
</section>
<section>
<h5>Variáveis e funções utilizam a notação separado_por_underscores; classes
usam CamelCase.</h5>
<p>Correto:</p>
<p><pre><code data-trim>
MinhaClasse
minha_funcao()
</code></pre></p>
<p>Errado:</p>
<p><pre><code data-trim>
minhaClasse
minhaFuncao()
</code></pre></p>
</section>
<section>
<h5>Blocos são marcados com 4 espaços e não tabulações.</h5>
<p>A maior parte dos editores de código hoje permitem configurar isso facilmente
e fazem com que os 4 espaços no começo sejam tratados como tabulação.</p>
<p>Isso garante que o código irá sempre aparecer da mesma forma em qualquer
editor, não importando a configuração do autor.</p>
</section>
<section>
<h5>Coluna máxima é 80.</h5>
<p>Nenhum código deve passar da coluna 80, não importa o tamanho do seu
monitor.</p>
<p>Facilita a leitura e a movimentação dentro do código.</p>
</section>
<section>
<h5>Duas linhas em branco antes de classes, 1 linha em branco antes de funções.</h5>
</section>
<section>
<h5>Espaços entre operadores (+, -, /, *), nada de espaços antes de parentêses, colchetes ou chaves.</h5>
<p>Correto:</p>
<p><pre><code data-trim>
(1 + 2)
array[1]
</code></pre></p>
<p>Errado:</p>
<p><pre><code data-trim>
(1+2)
( 1 + 2 )
array [ 1 ]
</code></pre></p>
</section>
<section>
<h5>Nada de espaços entre parâmetros nomeados.</h5>
<p>Correto:</p>
<p><pre><code data-trim>
funcao(param=1)
</code></pre></p>
<p>Errado:</p>
<p><pre><code data-trim>
funcao(param = 1)
</code></pre></p>
</section>
<section>
<h3>Blocos</h3>
</section>
<section>
<p>Em Python, uma identação define um bloco.</p>
<p class='fragment'>Não existe <code>{</code> / <code>}</code>, não existe <code>end</code>, nada. Só identação.</p>
<img class='fragment' src='_images/zuul.jpg'></img>
</section>
</section>
<section>
<section>
<h2>O interpretador Python</h2>
@ -111,6 +251,8 @@
<section>
<p><pre><code data-trim>
$ python
Python 2.7.5 (default, Jun 25 2014, 10:19:55)
[GCC 4.8.2 20131212 (Red Hat 4.8.2-7)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
@ -129,7 +271,7 @@ python meuscript.py
<section>
<section>
<h2>Tipos</h2>
<h2>Tipos de Variáveis</h2>
</section>
<section>
@ -160,6 +302,14 @@ python meuscript.py
<p>Outros são tipos simples que não são objetos.</p>
</section>
<section>
<p><code>None</code>: O nada. Tipo simples.</p>
<p><pre><code data-trim>
&gt;&gt;&gt; a = None
</code></pre></p>
</section>
<section>
<p><code>bool</code>: Tipo booleano. Tipo simples.</p>
@ -175,11 +325,6 @@ python meuscript.py
<p><pre><code data-trim>
&gt;&gt;&gt; a = 1
</code></pre></p>
<p><pre><code data-trim>
&gt;&gt;&gt; 1 + 1
2
</code></pre></p>
</section>
<section>
@ -219,7 +364,7 @@ python meuscript.py
</section>
<section>
<p><code>dict</code>: Um dicionário/objeto/mapa. Objeto mutável.</p>
<p><code>dict</code>: Um dicionário/objeto/mapa/documento. Objeto mutável.</p>
<p><pre><code data-trim>
&gt;&gt;&gt; a = {'Python': 'Rocks',
@ -236,13 +381,27 @@ python meuscript.py
</code></pre></p>
</section>
<section>
<p><code>set</code>: Conjunto de elementos não repetíveis. Objeto mutável.</p>
<p><pre><code data-trim>
&gt;&gt;&gt; a = set()
&gt;&gt;&gt; a.add('a')
&gt;&gt;&gt; a
set(['a'])
&gt;&gt;&gt; a.add('a')
&gt;&gt;&gt; a
set(['a'])
</code></pre></p>
</section>
<section>
<p>E ainda (mas menos importantes):</p>
<ul>
<li>None</li>
<li>Long (<code>a = 1L</code>)</li>
<li>Lambdas (<code> a = lambda a: a + 2</code>)</li>
<li>Lambdas (<code>a = lambda a: a + 2</code>)</li>
</ul>
</section>
</section>
@ -260,14 +419,6 @@ python meuscript.py
<h3 class='fragment'>Blocos</h3>
</section>
<section>
<p>Em Python, uma identação define um bloco.</p>
<p class='fragment'>Não tem <code>{</code> / <code>}</code>, não tem <code>end</code>, nada. Só blocos.</p>
<img class='fragment' src='_images/zuul.jpg'></img>
</section>
<section>
<h3><code>if [condição]</code></h3>
@ -290,6 +441,63 @@ python meuscript.py
</code></pre></p>
</section>
<section>
<img src='_images/intermission_3696.jpg'>
</section>
<section>
<h3>[condição]</h3>
<p>Comparação pode ter mais de um elemento:</p>
<p><pre><code data-trim>
&gt;&gt;&gt; a = 1; b = 5; c = 3; d = 1
&gt;&gt;&gt; a == b == c == d
False
&gt;&gt;&gt; a &lt; b &gt; c
True
</code></pre></p>
</section>
<section>
<h3>[condição] (cont.)</h3>
<p>Valores "em branco" são considerados falsos:</p>
<ul>
<li><code>None</code> é falso.</li>
<li><code>""</code>, string vazia, é falso.</li>
<li><code>0</code> é falso em qualquer precisão.</li>
<li><code>[]</code>, lista vazia, é falso.</li>
<li><code>{}</code>, dicionário vazio, é falso.</li>
<li><code>set()</code>, set vazio, é falso.</li>
</ul>
</section>
<section>
<h3>[condição] (cont.)</h3>
<p>Como valores em branco são falsos, para garantir <code>None</code>
usa-se <code>is</code>.</p>
<p><pre><code data-trim>
&gt;&gt;&gt; a = 0
&gt;&gt;&gt; not a
True
&gt;&gt;&gt; a is None
False
&gt;&gt;&gt; a = None
&gt;&gt;&gt; not a
True
&gt;&gt;&gt; a is None
True
</code></pre></p>
</section>
<section>
<img src='_images/tumblr_n6qbpoBDVX1rbyj0do1_500.jpg'>
</section>
<section>
<h3><code>for [iterável]</code></h3>
@ -353,6 +561,8 @@ python meuscript.py
&gt;&gt;&gt; for (key, value) in d.iteritems():
&gt;&gt;&gt; print key, value
</code></pre></p>
<p class='fragment'>Forma considerada "correta" é a anterior.</p>
</section>
</section>
@ -431,6 +641,19 @@ iterável[start:end:step]
<p>Para fazer uma cópia de uma lista com outros
iteráveis internos, existe o módulo <code>deepcopy</code>.</p>
</section>
<section>
<p>Todos os iteráveis podem ser "medidos" com <code>len()</code>:</p>
<ul>
<li><code>len(list)</code> &#8667; Número de elementos na lista.</li>
<li><code>len(tuple)</code> &#8667; Número de elementos na tupla.</li>
<li><code>len(str)</code> &#8667; Número de caracteres na string.</li>
<li><code>len(dict)</code> &#8667; Número de chaves no dicionário.</li>
<li><code>len(set)</code> &#8667; Número de elementos no set.</li>
</ul>
</section>
</section>
<section>
@ -446,6 +669,18 @@ iterável[start:end:step]
&gt;&gt;&gt; return (a + b) / c
</code></pre></p>
</section>
<section>
<p>Parâmetros podem ser nomeados.</p>
<p><pre><code data-trim>
&gt;&gt;&gt; def funcao(a, b, c):
&gt;&gt;&gt; return (a + b) / c
&gt;&gt;&gt;
&gt;&gt;&gt; funcao(b=2, c=3, a=10)
4
</code></pre></p>
</section>
</section>
<section>
@ -536,7 +771,324 @@ iterável[start:end:step]
Julio
</code></pre></p>
</section>
<section>
<p>Herança</p>
<p><pre><code data-trim>
&gt;&gt;&gt; class A(object):
&gt;&gt;&gt; def __init__(self):
&gt;&gt;&gt; self.value = 10
&gt;&gt;&gt; class B(A):
&gt;&gt;&gt; def __init__(self):
&gt;&gt;&gt; super(B, self).__init__()
&gt;&gt;&gt; self.name = 'AAAA'
</code></pre></p>
</section>
<section>
<p>Herança Múltipla</p>
<p><pre><code data-trim>
&gt;&gt;&gt; class A(object):
&gt;&gt;&gt; def __init__(self):
&gt;&gt;&gt; self.value = 10
&gt;&gt;&gt; class B(object):
&gt;&gt;&gt; def __init__(self):
&gt;&gt;&gt; self.name = 'AAAA'
&gt;&gt;&gt; class C(A, B):
&gt;&gt;&gt; def __init__(self):
&gt;&gt;&gt; super(C, self).__init__()
</code></pre></p>
</section>
<section>
<p>No Python 3, basta usar <code>super().__init__()</code>.
</section>
<section>
<p>Propriedades podem ser injetadas a qualquer momento.</p>
&gt;&gt;&gt; class A(object):
&gt;&gt;&gt; def __init__(self):
&gt;&gt;&gt; self.value = 10
&gt;&gt;&gt;
&gt;&gt;&gt; a = A()
&gt;&gt;&gt; a.name = 'Julio'
</section>
</section>
<section>
<h2>As Esquisitices de Python</h2>
</section>
<section>
<section>
<h3>Strings São Imutáveis</h3>
</section>
<section>
<p><pre><code data-trim>
&gt;&gt;&gt; a = 'string 1'
&gt;&gt;&gt; b = 'string 2'
&gt;&gt;&gt; c = a + ' ' + b
</code></pre></p>
<ul>
<li>Cria um objeto que é o conteúdo de "a" com um espaço.</li>
<li>Cria um novo objeto que é o novo objeto mais o conteúdo de "b".</li>
<li>Atribui o novo objeto à "c".</li>
</ul>
</section>
<section>
<p>Forma correta de concatenar strings:</p>
<p><pre><code data-trim>
&gt;&gt;&gt; a = 'string 1'
&gt;&gt;&gt; b = 'string 2'
&gt;&gt;&gt; c = ' '.join([a, b])
</code></pre></p>
</section>
</section>
<section>
<section>
<h3>Listas São Mutáveis</h3>
</section>
<section>
<p><pre><code data-trim>
&gt;&gt;&gt; def a(l=[]):
&gt;&gt;&gt; l.append(1)
&gt;&gt;&gt; print l
&gt;&gt;&gt;
&gt;&gt;&gt; a()
[1]
&gt;&gt;&gt; a()
[1, 1]
</code></pre></p>
</section>
<section>
<p>Forma correta de lidar com parâmetros mutáveis:</p>
<p><pre><code data-trim>
&gt;&gt;&gt; def a(l=None):
&gt;&gt;&gt; if not l:
&gt;&gt;&gt; l = []
&gt;&gt;&gt; l.append(1)
&gt;&gt;&gt;
&gt;&gt;&gt; a()
[1]
&gt;&gt;&gt; a()
[1]
</code></pre></p>
</section>
</section>
<section>
<section>
<h3>Stars</h3>
</section>
<section>
<p>"Stars" servem para empacotar e desempacotar parâmetros indefinidos.</p>
</section>
<section>
<p><pre><code data-trim>
&gt;&gt;&gt; def a(*args):
&gt;&gt;&gt; print args
&gt;&gt;&gt;
&gt;&gt;&gt; a(1)
[1]
&gt;&gt;&gt; a(1, 2, 3, 4, 5)
[1, 2, 3, 4, 5]
</code></pre></p>
<p><code>*</code> pega somente os parâmetros que não tem nome.</p>
</section>
<section>
<p><pre><code data-trim>
&gt;&gt;&gt; def a(**kwargs):
&gt;&gt;&gt; print kwargs
&gt;&gt;&gt;
&gt;&gt;&gt; a(a=1)
{'a': 1}
&gt;&gt;&gt; a(value1=10, a=2)
{'value1': 10, 'a': 2}
</code></pre></p>
<p><code>**</code> pega somente os parâmetros que tem nome.</p>
</section>
<section>
<p><pre><code data-trim>
&gt;&gt;&gt; def a(*args, **kwargs):
&gt;&gt;&gt; print args
&gt;&gt;&gt; print kwargs
&gt;&gt;&gt;
&gt;&gt;&gt; a(a=1)
[]
{'a': 1}
&gt;&gt;&gt; a(1, 2, 3, a=5)
[1, 2, 3]
{'a': 5}
</code></pre></p>
</section>
<section>
<p><pre><code data-trim>
&gt;&gt;&gt; def a(a, b, *args, name=None, **kwargs):
&gt;&gt;&gt; print 'a =', a
&gt;&gt;&gt; print 'b =', b
&gt;&gt;&gt; print 'args =', args
&gt;&gt;&gt; print 'name = ', name
&gt;&gt;&gt; print 'kwargs =', kwargs
</code></pre></p>
<p>Saída de uma chamada desta função fica a cargo do leitor.</p>
</section>
<section>
<img src='_images/boring.gif'>
<p>BORING!</p>
</section>
<section>
<p>A parte legal dos stars não é usar para criar funções que aceitam
qualquer parâmetro (embora isso seja legal em alguns casos).</p>
<p>A parte legal é fazer chamadas de funções com dicionários.</p>
</section>
<section>
<p><pre><code data-trim>
&gt;&gt;&gt; def funcao(a, b, c):
&gt;&gt;&gt; return (a + b) / c
&gt;&gt;&gt;
&gt;&gt;&gt; params = {'b': 2, 'c': 3, 'a':10}
&gt;&gt;&gt; funcao(**params)
</code></pre></p>
</section>
</section>
<section>
<section>
<h3>"Functions are First Class Citizens"</h3>
</section>
<section>
<p><pre><code data-trim>
&gt;&gt;&gt; def funcao(a, b, c):
&gt;&gt;&gt; return (a + b) / c
&gt;&gt;&gt;
&gt;&gt;&gt; def check(a, b, c, condition, function):
&gt;&gt;&gt; if condition:
&gt;&gt;&gt; print function(a, b, c)
&gt;&gt;&gt;
&gt;&gt;&gt; check(1, 2, 3, True, funcao)
1
&gt;&gt;&gt; check(1, 2, 3, False, funcao)
&gt;&gt;&gt;
</code></pre></p>
</section>
<section>
<p>Como funções são cidadãos de primeira classe e classes podem
ter funções injetadas, pode-se extender uma classe em tempo
de execução.</p>
<p><pre><code data-trim>
&gt;&gt;&gt; class A(object):
&gt;&gt;&gt; def __init__(self):
&gt;&gt;&gt; self.value = 10
&gt;&gt;&gt;
&gt;&gt;&gt; def show_name(self):
&gt;&gt;&gt; print 'Julio'
&gt;&gt;&gt;
&gt;&gt;&gt; a = A()
&gt;&gt;&gt; a.show = show_name
&gt;&gt;&gt; a.show()
</code></pre></p>
</section>
</section>
<section>
<section>
<h3>Decorators</h3>
</section>
<section>
<p>A idéia dos decorators é cria uma função que altera a funcionalidade
de uma função.</p>
<p>A forma mais simples de entender decorators é pensar neles como
funções que encapsulam callbacks.</p>
</section>
<section>
<p><pre><code data-trim>
&gt;&gt;&gt; def retrieve(connection):
&gt;&gt;&gt; # faz algo com a conexão para recuperar dados.
</code></pre></p>
<p>Problema: antes de sair executando algo na conexão, tem que ser
verificado se a conexão está ativa.</p>
</section>
<section>
<p>Solução menos óbvia: Criar uma função que verifica a conexão e,
se ela estiver ok, chama a função.</p>
<p><pre><code data-trim>
&gt;&gt;&gt; def retrieve(connection):
&gt;&gt;&gt; # faz algo com a conexão para recuperar dados.
&gt;&gt;&gt;
&gt;&gt;&gt; def update(connection):
&gt;&gt;&gt; # atualiza algo usando a função
&gt;&gt;&gt;
&gt;&gt;&gt; def check(connection, call):
&gt;&gt;&gt; if not connection.is_connected:
&gt;&gt;&gt; connection.retry()
&gt;&gt;&gt; call(connection)
</code></pre></p>
<p>Novo problema: Todo lugar onde antes era chamado <code>retrieve</code>
agora precisa ser alterado para <code>check(connection, retrieve)</code> e
todo lungar onde era chamado <code>update</code> precisa ser alterado para
<code>check(connection, update)</code>.</p>
</section>
<section>
<p>Solução mais simples: decorators.</p>
<p><pre><code data-trim>
&gt;&gt;&gt; from functools import wrap
&gt;&gt;&gt;
&gt;&gt;&gt; def check(func):
&gt;&gt;&gt; def check_conn(*args, **kwargs):
&gt;&gt;&gt; # acha a conexão em args ou kwargs
&gt;&gt;&gt; if not connection.is_connected:
&gt;&gt;&gt; connection.retry()
&gt;&gt;&gt; return func(*args, **kwargs)
&gt;&gt;&gt; return check_conn
&gt;&gt;&gt;
&gt;&gt;&gt; @check
&gt;&gt;&gt; def retrieve(connection):
&gt;&gt;&gt; # faz algo com a conexão para recuperar dados
</code></pre></p>
<p>Não precisa alterar nenhuma chamada de <code>retrieve</code>.</p>
</section>
</section>
<section data-background='_images/thats-all-folks.jpg'>
<section></section>
</section>
</div>
</div>
@ -560,7 +1112,7 @@ Julio
{ src: '_external/classList.js', condition: function() { return !document.body.classList; } },
{ src: '_external/marked.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } },
{ src: '_external/markdown.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } },
{ src: '_external/highlight.js', async: true, callback: function() { hljs.initHighlightingOnLoad(); } },
{ src: '_external/highlight.min.js', async: true, callback: function() { hljs.initHighlightingOnLoad(); } },
{ src: '_external/zoom.js', async: true, condition: function() { return !!document.body.classList; } },
{ src: '_external/notes.js', async: true, condition: function() { return !!document.body.classList; } }
]

Loading…
Cancel
Save