You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
344 lines
24 KiB
344 lines
24 KiB
11 months ago
|
<!DOCTYPE html>
|
||
|
<html lang="en">
|
||
|
<head>
|
||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||
|
<meta http-equiv="content-type" content="text/html; charset=utf-8">
|
||
|
|
||
|
<!-- Enable responsiveness on mobile devices-->
|
||
|
<!-- viewport-fit=cover is to support iPhone X rounded corners and notch in landscape-->
|
||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1, viewport-fit=cover">
|
||
|
|
||
|
<title>Julio Biason .Me 4.3</title>
|
||
|
|
||
|
<!-- CSS -->
|
||
|
<link rel="stylesheet" href="https://blog.juliobiason.me/print.css" media="print">
|
||
|
<link rel="stylesheet" href="https://blog.juliobiason.me/poole.css">
|
||
|
<link rel="stylesheet" href="https://blog.juliobiason.me/hyde.css">
|
||
|
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=PT+Sans:400,400italic,700|Abril+Fatface">
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
</head>
|
||
|
|
||
|
<body class=" ">
|
||
|
|
||
|
<div class="sidebar">
|
||
|
<div class="container sidebar-sticky">
|
||
|
<div class="sidebar-about">
|
||
|
|
||
|
<a href="https://blog.juliobiason.me"><h1>Julio Biason .Me 4.3</h1></a>
|
||
|
|
||
|
<p class="lead">Old school dev living in a 2.0 dev world</p>
|
||
|
|
||
|
|
||
|
</div>
|
||
|
|
||
|
<ul class="sidebar-nav">
|
||
|
|
||
|
|
||
|
<li class="sidebar-nav-item"><a href="/">English</a></li>
|
||
|
|
||
|
<li class="sidebar-nav-item"><a href="/pt">Português</a></li>
|
||
|
|
||
|
<li class="sidebar-nav-item"><a href="/tags">Tags (EN)</a></li>
|
||
|
|
||
|
<li class="sidebar-nav-item"><a href="/pt/tags">Tags (PT)</a></li>
|
||
|
|
||
|
|
||
|
</ul>
|
||
|
</div>
|
||
|
</div>
|
||
|
|
||
|
|
||
|
<div class="content container">
|
||
|
|
||
|
<div class="post">
|
||
|
<h1 class="post-title">Python 2 + 3 = Six</h1>
|
||
|
<span class="post-date">
|
||
|
2016-11-21
|
||
|
|
||
|
<a href="https://blog.juliobiason.me/pt/tags/python/">#python</a>
|
||
|
|
||
|
<a href="https://blog.juliobiason.me/pt/tags/six/">#six</a>
|
||
|
|
||
|
<a href="https://blog.juliobiason.me/pt/tags/python-2/">#python 2</a>
|
||
|
|
||
|
<a href="https://blog.juliobiason.me/pt/tags/python-3/">#python 3</a>
|
||
|
|
||
|
<a href="https://blog.juliobiason.me/pt/tags/tchelinux/">#tchelinux</a>
|
||
|
|
||
|
<a href="https://blog.juliobiason.me/pt/tags/companion-post/">#companion post</a>
|
||
|
|
||
|
</span>
|
||
|
<p>"Six" é uma pequena biblioteca Python que pode ajudar você a passar o seu
|
||
|
código de Python 2 para Python 3.</p>
|
||
|
<span id="continue-reading"></span><div style="border:1px solid grey; margin:7px; padding: 7px">
|
||
|
<p>(Esse post é relacionado com a apresentação que eu fiz no dia 19 de novembro
|
||
|
no TchêLinux. Os slides podem ser encontrados
|
||
|
<a href="http://presentations.juliobiason.net/python23six.html">na área de apresentações</a>.)</p>
|
||
|
|
||
|
</div>
|
||
|
<p>Antes de mais nada, uma coisa que precisamos responder é: Porque alguém usaria
|
||
|
Python 3?</p>
|
||
|
<ul>
|
||
|
<li>Todas as strings são unicode por padrão; isso resolve a pilha de problemas
|
||
|
macabros, chatos, malditos, desgraçádos do <code>UnicodeDecodeError</code>;</li>
|
||
|
<li><code>Mock</code> é uma classe padrão do Python; ainda é possível instalar usando <code>pip</code> e
|
||
|
a sintaxe é exatamente igual, mas é uma dependência a menos;</li>
|
||
|
<li><code>Enum</code> é uma classe padrão do Python; Enum é um dos abusos mais
|
||
|
interessantes de classes em Python e realmente útil;</li>
|
||
|
<li>AsyncIO e toda a parte de lazy-evaluation que o Python 3 trouxe; muita coisa
|
||
|
no Python 3 deixou de ser "gerar uma lista" para ser um retorno de um
|
||
|
iterador ou um generator; com AsyncIO, tem-se um passo a frente nessa idéia
|
||
|
de geração lazy das coisas e, segundo pessoas mais inteligentes que eu, com
|
||
|
PyUV, o Python consegue ser tão ou mais rápido que o Node;</li>
|
||
|
<li>E, principalmente, <strong>o suporte ao Python 2 termina em 2020!</strong></li>
|
||
|
</ul>
|
||
|
<div style="border:1px solid grey; margin:7px; padding: 7px">
|
||
|
<p>Existe ainda a interpolação de strings com o novo identificador <code>f</code>; a
|
||
|
funcionalidade é semelhante à chamada <code>str.format</code> usando <code>locals()</code>, por
|
||
|
exemplo, <code>f'{element} {count}</code> é equivalmente à <code>'{element} {count}'.format(locals())</code> (desde que você tenha <code>element</code> e <code>count</code> como
|
||
|
variáveis locais da sua função).</p>
|
||
|
|
||
|
</div>
|
||
|
<p>O último ponto é o mais importante. Você pode pensar "mas ainda tem três anos
|
||
|
até lá", mas natal está chegando, daqui a pouco é carnaval e, quando menos se
|
||
|
espera, é 2020.</p>
|
||
|
<h2 id="o-caminho-para-python-3">O caminho para Python 3</h2>
|
||
|
<p>Quem quiser já começar a portar seus aplicativos para Python 3, existem duas
|
||
|
formas:</p>
|
||
|
<p>A primeira é executar seus aplicativos com <code>python -3 [script]</code>; isso irá fazer
|
||
|
com que o interpretador Python avise quando qualquer instrução de código que
|
||
|
ele não consiga converter corretamente seja alertado. Eu executei um script
|
||
|
pessoal <a href="https://bitbucket.org/juliobiason/pyttracker">com data de 2003</a> e o
|
||
|
Python não apresentou nada. </p>
|
||
|
<div style="border:1px solid grey; margin:7px; padding: 7px">
|
||
|
<p>Apenas para fins de melhor elucidação: o código que eu estava gerando já estava
|
||
|
mais correto e seguindo os padrões mais pythônicos; em 2014 eu ainda estava
|
||
|
vendo casos em que código rodando em Python 2.6 ainda usava <code>has_keys()</code>, que
|
||
|
foi deprecado no Python 2.3.</p>
|
||
|
|
||
|
</div>
|
||
|
<p>Existem vários motivos pra isso:</p>
|
||
|
<ol>
|
||
|
<li>As pessoas se acostumaram a escrever código "Pythonico"; a linguagem em si
|
||
|
não sofreu grandes alterações.</li>
|
||
|
<li>Apesar da linguagem Python ter algumas coisas removidas, essas foram
|
||
|
lentamente reintroduzidas na linguagem; um exemplo é o operador de
|
||
|
interpolação de strings (<code>%</code>) que havia sido removido em favor do
|
||
|
<code>str.format</code> mas acabou voltando.</li>
|
||
|
</ol>
|
||
|
<p>A segunda forma para portar seu código para Python 3 é usar a ferramenta
|
||
|
<code>2to3</code>. Ela irá verificar as alterações conhecidas para Python 3 (por exemplo,
|
||
|
a transformação de <code>print</code> para função, a alteração de alguns pacotes da STL)
|
||
|
e ira apresentar um patch para ser aplicado depois.</p>
|
||
|
<p>Entre as conversões que o <code>2to3</code> irá fazer, está a troca de chamadas de
|
||
|
<code>iter</code>-alguma-coisa para a versão sem o prefixo (por exemplo,
|
||
|
<code>iteritems()</code> irá se tornar simplesmente <code>items()</code>); <code>print</code> será
|
||
|
convertido para função; serão feitos vários ajustes nas chamadas das
|
||
|
bibliotecas <code>urllib</code> e <code>urlparse</code> (estas duas foram agrupadas no Python 3
|
||
|
e a primeira teve várias reorganizações internas); <code>xrange</code> passa a ser
|
||
|
<code>range</code>; <code>raw_input</code> agora se chama <code>input</code> e tem um novo tratamento de
|
||
|
saída, entre outros.</p>
|
||
|
<p>Existe apenas um pequeno problema nessa conversão de Python 2 para Python 3:
|
||
|
Como pode ser visto na lista acima, alguns comandos existem nas duas versões,
|
||
|
mas com funcionalidades diferentes; por exemplo, <code>iteritems()</code> é convertido
|
||
|
para simplesmente <code>items()</code>, mas os dois métodos existem em Python 2: o
|
||
|
primeiro retorna um iterador e o segundo retorna uma nova lista com as tuplas
|
||
|
de todos os elementos do dicionário (no caso do Python 3, é retornado um
|
||
|
iterador). Assim, apesar do código ser gramaticalmente igual tanto em Python 2
|
||
|
quanto Python 3, semanticamente os dois são diferentes.</p>
|
||
|
<p>Esse problema de "comandos iguais com resultados diferentes" pode ser um
|
||
|
grande problema se o sistema está sendo executado em ambientes que não
|
||
|
permitem modificação fácil -- por exemplo, o mesmo é executando num Centos 4
|
||
|
ou ainda necessita compabilidade com Python 2.6, ambos "problemas" sendo, na
|
||
|
verdade, requisitos do grupo de infraestrutura.</p>
|
||
|
<h2 id="six-e-future-ao-resgate">Six (e <code>__future__</code>) ao Resgate</h2>
|
||
|
<p>Para resolver o problema de termos código que precisa executar nas duas
|
||
|
versões, existe a biblioteca <a href="https://pythonhosted.org/six/">Six</a>; ela faz o
|
||
|
"meio de campo" entre Python 2 e Python 3 e fornece uma interface para que
|
||
|
código Python 2 seja portado para Python 3 mantendo a compatibilidade.</p>
|
||
|
<p>Num exemplo (relativamente idiota):</p>
|
||
|
<pre data-lang="python" style="background-color:#2b303b;color:#c0c5ce;" class="language-python "><code class="language-python" data-lang="python"><span style="color:#b48ead;">import </span><span>collections
|
||
|
</span><span>
|
||
|
</span><span style="color:#b48ead;">class </span><span style="color:#ebcb8b;">Model</span><span style="color:#eff1f5;">(</span><span style="color:#a3be8c;">object</span><span style="color:#eff1f5;">):
|
||
|
</span><span> </span><span style="color:#b48ead;">def </span><span style="color:#96b5b4;">__init__</span><span>(</span><span style="color:#bf616a;">self</span><span>, </span><span style="color:#bf616a;">word</span><span>):
|
||
|
</span><span> </span><span style="color:#bf616a;">self</span><span>._count = </span><span style="color:#d08770;">None
|
||
|
</span><span> </span><span style="color:#bf616a;">self</span><span>.word = word
|
||
|
</span><span> </span><span style="color:#b48ead;">return
|
||
|
</span><span>
|
||
|
</span><span> @</span><span style="color:#96b5b4;">property
|
||
|
</span><span> </span><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">word</span><span>(</span><span style="color:#bf616a;">self</span><span>):
|
||
|
</span><span> </span><span style="color:#b48ead;">return </span><span style="color:#bf616a;">self</span><span>._word
|
||
|
</span><span>
|
||
|
</span><span> @word.</span><span style="color:#bf616a;">setter
|
||
|
</span><span> </span><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">word</span><span>(</span><span style="color:#bf616a;">self</span><span>, </span><span style="color:#bf616a;">word</span><span>):
|
||
|
</span><span> </span><span style="color:#bf616a;">self</span><span>._word = word
|
||
|
</span><span> </span><span style="color:#bf616a;">self</span><span>._count = collections.</span><span style="color:#bf616a;">Counter</span><span>(word)
|
||
|
</span><span>
|
||
|
</span><span> @</span><span style="color:#96b5b4;">property
|
||
|
</span><span> </span><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">letters</span><span>(</span><span style="color:#bf616a;">self</span><span>):
|
||
|
</span><span> </span><span style="color:#b48ead;">return </span><span style="color:#bf616a;">self</span><span>._count
|
||
|
</span><span>
|
||
|
</span><span> </span><span style="color:#b48ead;">def </span><span style="color:#96b5b4;">__getitem__</span><span>(</span><span style="color:#bf616a;">self</span><span>, </span><span style="color:#bf616a;">pos</span><span>):
|
||
|
</span><span> </span><span style="color:#b48ead;">return </span><span style="color:#bf616a;">self</span><span>._count[pos]
|
||
|
</span><span>
|
||
|
</span><span style="color:#b48ead;">if </span><span>__name__ == "</span><span style="color:#a3be8c;">__main__</span><span>":
|
||
|
</span><span> word = </span><span style="color:#bf616a;">Model</span><span>('</span><span style="color:#a3be8c;">This is an ex-parrot</span><span>')
|
||
|
</span><span> </span><span style="color:#b48ead;">for </span><span>letter, count </span><span style="color:#b48ead;">in </span><span>word.letters.</span><span style="color:#bf616a;">iteritems</span><span>():
|
||
|
</span><span> </span><span style="color:#b48ead;">print </span><span>letter, count
|
||
|
</span></code></pre>
|
||
|
<p>Nesse exemplo, temos uma classe que guarda uma frase e a quantidade de vezes
|
||
|
que cada letra aparece, utilizando <code>Counter</code> para fazer isso (já que <code>Counter</code>
|
||
|
conta a quantidade de vezes que um elemento aparece em um iterável e strings
|
||
|
<em>são</em> iteráveis).</p>
|
||
|
<p>Nesse exemplo, temos os seguintes problemas:</p>
|
||
|
<ol>
|
||
|
<li>
|
||
|
<p><code>class Model(object)</code>: em Python 3, todas as classes são "new class" e o
|
||
|
uso do <code>object</code> não é mais necessário (mas não afeta o funcionamento da
|
||
|
classe);</p>
|
||
|
</li>
|
||
|
<li>
|
||
|
<p><code>for letter, count in word.letter.iteritems()</code> Conforme discutido
|
||
|
anteriormente, <code>iteritems()</code> deixou de existir e passou a ser <code>items()</code>;
|
||
|
<code>items()</code> existe no Python 2, mas a funcionalidade é diferente. No nosso
|
||
|
caso aqui, o resultado da operação continua sendo o mesmo, mas o consumo de
|
||
|
memória irá subir cada vez que a chamada for feita.</p>
|
||
|
</li>
|
||
|
<li>
|
||
|
<p><code>print leter, count</code>: <code>print</code> agora é uma função e funciona levemente
|
||
|
diferente da versão com Python 2.</p>
|
||
|
</li>
|
||
|
</ol>
|
||
|
<p>Então, para deixar esse código compatível com Python 2 e Python 3 ao mesmo
|
||
|
tempo, temos que fazer o seguinte:</p>
|
||
|
<blockquote>
|
||
|
<p><code>class Model(object)</code></p>
|
||
|
</blockquote>
|
||
|
<p>Não é preciso fazer nada.</p>
|
||
|
<blockquote>
|
||
|
<p><code>print letter, count</code></p>
|
||
|
</blockquote>
|
||
|
<pre data-lang="python" style="background-color:#2b303b;color:#c0c5ce;" class="language-python "><code class="language-python" data-lang="python"><span style="color:#b48ead;">from </span><span>__future__ </span><span style="color:#b48ead;">import </span><span>print_function
|
||
|
</span><span style="color:#96b5b4;">print</span><span>('</span><span style="color:#d08770;">{} {}</span><span>'.</span><span style="color:#bf616a;">format</span><span>(letter, count))
|
||
|
</span></code></pre>
|
||
|
<p><code>print</code> como função pode ser "trazido do futuro" usando o módulo
|
||
|
<code>__future__</code> (apenas disponível para Python 2.7); como a apresentação de
|
||
|
várias variáveis não é recomenando usando-se vírgulas, usar o
|
||
|
<code>str.format</code> é a forma recomendada.</p>
|
||
|
<p>Uma opção melhor (na minha opinião) é:</p>
|
||
|
<pre data-lang="python" style="background-color:#2b303b;color:#c0c5ce;" class="language-python "><code class="language-python" data-lang="python"><span style="color:#b48ead;">from </span><span>__future__ </span><span style="color:#b48ead;">import </span><span>print_function
|
||
|
</span><span style="color:#96b5b4;">print</span><span>('</span><span style="color:#d08770;">{letter} {count}</span><span>'.</span><span style="color:#bf616a;">format</span><span>(</span><span style="color:#bf616a;">letter</span><span>=letter
|
||
|
</span><span> count=count))
|
||
|
</span></code></pre>
|
||
|
<p>Assim, os parâmetros usados na saída são nomeados e podem ser alterados.
|
||
|
Isto gera um erro estranho quando um nome usado na string de formato não
|
||
|
for passada na lista de parâmetros do format, mas em strings mais
|
||
|
complexas, o resultado é mais fácil de ser entendido (por exemplo, eu acho
|
||
|
mais fácil entender <code>{letters} aparece {count} vezes</code> do que <code>{} aparece {} vezes</code>; ainda, é possível mudar a ordem das variáveis na string de formato
|
||
|
sem precisar alterar a ordem na lista de parâmetros).</p>
|
||
|
<p>Uma opção melhor ainda é:</p>
|
||
|
<pre data-lang="python" style="background-color:#2b303b;color:#c0c5ce;" class="language-python "><code class="language-python" data-lang="python"><span style="color:#b48ead;">import </span><span>six
|
||
|
</span><span>six.</span><span style="color:#bf616a;">print_</span><span>('</span><span style="color:#d08770;">{letter} {count}</span><span>'.</span><span style="color:#bf616a;">format</span><span>(</span><span style="color:#bf616a;">letter</span><span>=letter,
|
||
|
</span><span> </span><span style="color:#bf616a;">count</span><span>=count))
|
||
|
</span></code></pre>
|
||
|
<p>Com Six, remove-se a dependência com <code>__future__</code> e assim pode-se usar o
|
||
|
mesmo código em Python 2.6.</p>
|
||
|
<blockquote>
|
||
|
<p><code>for letter, count in word.letters.iteritems():</code></p>
|
||
|
</blockquote>
|
||
|
<pre data-lang="python" style="background-color:#2b303b;color:#c0c5ce;" class="language-python "><code class="language-python" data-lang="python"><span style="color:#b48ead;">import </span><span>six
|
||
|
</span><span style="color:#b48ead;">for </span><span>letter, count </span><span style="color:#b48ead;">in </span><span>six.</span><span style="color:#bf616a;">iteritems</span><span>(word.letters):
|
||
|
</span></code></pre>
|
||
|
<p>Six provê uma interface unificada para iterador de itens tanto em Python 2
|
||
|
quanto Python 3: <code>six.iteritems()</code> irá chamada <code>iteritems()</code> se estiver
|
||
|
rodando em Python e <code>items()</code> se estiver rodando com Python 3.</p>
|
||
|
<p>E, assim, nosso código relativamente idiota agora é compatível com Python 2 e
|
||
|
Python 3 roda de forma idêntica nos dois.</p>
|
||
|
<p>Mas vamos para um exemplo real:</p>
|
||
|
<pre data-lang="python" style="background-color:#2b303b;color:#c0c5ce;" class="language-python "><code class="language-python" data-lang="python"><span style="color:#b48ead;">import </span><span>urllib
|
||
|
</span><span style="color:#b48ead;">import </span><span>urlparse
|
||
|
</span><span>
|
||
|
</span><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">add_querystring</span><span>(</span><span style="color:#bf616a;">url</span><span>, </span><span style="color:#bf616a;">querystring</span><span>, </span><span style="color:#bf616a;">value</span><span>):
|
||
|
</span><span> frags = </span><span style="color:#bf616a;">list</span><span>(urlparse.</span><span style="color:#bf616a;">urlsplit</span><span>(url))
|
||
|
</span><span> query = frags[</span><span style="color:#d08770;">3</span><span>]
|
||
|
</span><span> query_frags = urlparse.</span><span style="color:#bf616a;">parse_qsl</span><span>(query)
|
||
|
</span><span> query_frags.</span><span style="color:#bf616a;">append</span><span>((querystring, value))
|
||
|
</span><span> frags[</span><span style="color:#d08770;">3</span><span>] = urllib.</span><span style="color:#bf616a;">urlencode</span><span>(query_frags)
|
||
|
</span><span> </span><span style="color:#b48ead;">return </span><span>urlparse.</span><span style="color:#bf616a;">urlunsplit</span><span>(frags)
|
||
|
</span><span>
|
||
|
</span><span style="color:#b48ead;">if </span><span>__name__ == "</span><span style="color:#a3be8c;">__main__</span><span>":
|
||
|
</span><span> </span><span style="color:#b48ead;">print </span><span style="color:#bf616a;">add_querystring</span><span>('</span><span style="color:#a3be8c;">http://python.org</span><span>', '</span><span style="color:#a3be8c;">doc</span><span>', '</span><span style="color:#a3be8c;">urllib</span><span>')
|
||
|
</span><span> </span><span style="color:#b48ead;">print </span><span style="color:#bf616a;">add_querystring</span><span>('</span><span style="color:#a3be8c;">http://python.org?doc=urllib</span><span>',
|
||
|
</span><span> '</span><span style="color:#a3be8c;">page</span><span>', '</span><span style="color:#a3be8c;">2</span><span>')
|
||
|
</span></code></pre>
|
||
|
<div style="border:1px solid grey; margin:7px; padding: 7px">
|
||
|
<p>Sim, sim, o código poderia ser um simples "verificar se tem uma interrogação na
|
||
|
URL; se tiver, adicionar <code>&</code> e a query string; se não tiver, adicionar <code>?</code> e a
|
||
|
query string". A questão é: dessa forma, eu consigo fazer uma solução que vai
|
||
|
aceitar qualquer URL, em qualquer formato, com qualquer coisa no meio porque as
|
||
|
bibliotecas do STL do Python vão me garantir que a mesma vai ser parseada
|
||
|
corretamente.</p>
|
||
|
|
||
|
</div>
|
||
|
<p>Esse é um código de uma função utilizada para adicionar uma query string em
|
||
|
uma URL. O problema com essa função é que tanto <code>urlib</code>
|
||
|
quanto <code>urlparse</code> sofreram grandes modificações, ficando, inclusive, sob o
|
||
|
mesmo módulo (agora é tudo <code>urllib.parse</code>).</p>
|
||
|
<p>Para fazer esse código ficar compatível com Python 2 e 3 ao mesmo tempo, é
|
||
|
preciso usar o módulo <code>six.moves</code>, que contém todas essas mudanças de escopo
|
||
|
das bibliotecas da STL (incluindo, nesse caso, a <code>urllib</code> e <code>urlparse</code>).</p>
|
||
|
<pre data-lang="python" style="background-color:#2b303b;color:#c0c5ce;" class="language-python "><code class="language-python" data-lang="python"><span style="color:#b48ead;">import </span><span>six
|
||
|
</span><span>
|
||
|
</span><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">add_querystring</span><span>(</span><span style="color:#bf616a;">url</span><span>, </span><span style="color:#bf616a;">querystring</span><span>, </span><span style="color:#bf616a;">value</span><span>):
|
||
|
</span><span> frags = </span><span style="color:#bf616a;">list</span><span>(six.moves.urllib.parse.</span><span style="color:#bf616a;">urlsplit</span><span>(url))
|
||
|
</span><span> query = frags[</span><span style="color:#d08770;">3</span><span>]
|
||
|
</span><span> query_frags = six.moves.urllib.parse.</span><span style="color:#bf616a;">parse_qsl</span><span>(query)
|
||
|
</span><span> query_frags.</span><span style="color:#bf616a;">append</span><span>((querystring, value))
|
||
|
</span><span> frags[</span><span style="color:#d08770;">3</span><span>] = six.moves.urllib.parse.</span><span style="color:#bf616a;">urlencode</span><span>(query_frags)
|
||
|
</span><span> </span><span style="color:#b48ead;">return </span><span>six.moves.urllib.parse.</span><span style="color:#bf616a;">urlunsplit</span><span>(frags)
|
||
|
</span><span>
|
||
|
</span><span style="color:#b48ead;">if </span><span>__name__ == "</span><span style="color:#a3be8c;">__main__</span><span>":
|
||
|
</span><span> six.</span><span style="color:#bf616a;">print_</span><span>(</span><span style="color:#bf616a;">add_querystring</span><span>('</span><span style="color:#a3be8c;">http://python.org</span><span>', '</span><span style="color:#a3be8c;">doc</span><span>', '</span><span style="color:#a3be8c;">urllib</span><span>'))
|
||
|
</span><span> six.</span><span style="color:#bf616a;">print_</span><span>(</span><span style="color:#bf616a;">add_querystring</span><span>('</span><span style="color:#a3be8c;">http://python.org?doc=urllib</span><span>',
|
||
|
</span><span> '</span><span style="color:#a3be8c;">page</span><span>', '</span><span style="color:#a3be8c;">2</span><span>'))
|
||
|
</span></code></pre>
|
||
|
<p>O que foi feito, aqui, foi usar <code>six.moves.urllib.parse</code>. Essa estrutura não
|
||
|
vêm por acaso: no Python 3, as funções de <code>urlparse</code> agora se encontram em
|
||
|
<code>urllib.parse</code>; Six assumiu que a localização correta para as funções dentro
|
||
|
"de si mesma" seriam os pacotes utilizados no Python 3. </p>
|
||
|
<p>E, assim, temos dois exemplos de programas que conseguem rodar de forma igual
|
||
|
tanto em Python 3 quanto Python 2.</p>
|
||
|
<p>Ainda, fica a dica: Se houver algum software que você utiliza que não roda
|
||
|
corretamente com Python 3, utilizar o Six pode ajudar a manter o código atual
|
||
|
até que uma escrita resolva o problema.</p>
|
||
|
<h2 id="outras-perguntas">Outras Perguntas</h2>
|
||
|
<h3 id="como-fica-a-questao-de-ficar-sempre-com-o-six">Como fica a questão de ficar sempre com o Six?</h3>
|
||
|
<p>Boa parte das aplicações hoje botaram uma "quebra" do suporte às suas versões
|
||
|
que rodam em Python 2. Por exemplo, Django anunciou que em 2020 vai sair a
|
||
|
versão 2.0 do framework e essa versão vai suportar Python 3 apenas.</p>
|
||
|
<h2 id="quao-dificil-e-portar-para-python-3">Quão difícil é portar para Python 3?</h2>
|
||
|
<p>Não muito difícil -- agora. Muitas das coisas que foram removidas que davam dor
|
||
|
de cabeça na conversão retornaram; o caso mais clássico é o que operador de
|
||
|
interpolação de strings <code>%</code>, que foi removido e teria que ser substituído por
|
||
|
<code>str.format</code>, mas acabou retornando. Outro motivo é que os scripts são mais
|
||
|
"pythônicos" atualmente, muito por causa de gente como <a href="https://rhettinger.wordpress.com/">Raymond
|
||
|
Hettinger</a>, que tem feito vídeos excelentes
|
||
|
de como escrever código em Python com Python (ou seja, código "pythônico"). E,
|
||
|
como anedota pessoal, eu posso comentar que meu código de 2003 rodou com
|
||
|
<code>python -3</code> sem levantar nenhum warning.</p>
|
||
|
|
||
|
</div>
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
</div>
|
||
|
|
||
|
</body>
|
||
|
|
||
|
</html>
|