Hlavní navigace

Další novinky v jazyce Python 3.0

17. 12. 2008
Doba čtení: 6 minut

Sdílet

Minulý týden jsme rozebírali některé ze zásadních změn Pythonu 3.0 oproti starší řadě. Dnes se podíváme na další a zkusíme, jak dobře či špatně funguje nástroj 2o3 pro převod starších zdrojových kódů do nových. Ukážeme si, jak nástroj použít, jaký má výstup a jak a na co si dát pozor při jeho použití.

Další změny

Změny v syntaxi

Parametry funkce umístěné za args musí být vždy keywords-only (klíč=hodnota). V seznamu lze použít i samotnou hvězdičku. Za hvězdičkou pak stejně jako u argv musíme uvádět už jen keywords-only argumenty. Hvězdička označuje předem neznámý počet argumentů.

Můžeme ji také použít při zápisu podobném tomuto:

>>> a,*b,c=1,2,3,4,5
>>> a
1
>>> b
[2, 3, 4]
>>> c
5 

Byla přidána také jedna z flexibilnějších cest, jak vytvořit slovník, resp. jak ho vytvořit z jiných typů.

>>> values = [("a",1),("b",2)]
>>> {k:v for k,v in values}
{'a': 1, 'b': 2} 

Zápis binárních a ostatních číselných soustav se teď nově provádí přes:

>>> i=0b101010
>>> print(i)
42
>>> i=0o52
>>> print(i)
42 

Cesta zpět vede přes nové funkce bin() a oct():

>>> bin(42)
'0b101010'
>>> oct(42)
'0o52' 

Klíčová slova, která zastupují v pythonu nějakou funkci, nemohou být přepsána. K těmto slovům se v novém pythonu přidala další. Tento zápis již není v 3.0 možný:

>>> True=2
>>> print True
2 

V Pythonu 3.0 hodí chybu:

>>> True = 2
  File "<stdin>", line 1
SyntaxError: assignment to keyword 

K těmto novým slovům patří as, with, True, False a None.

Python 3.0 mění také práci s metatřídami. Už nebude možné dále používat proměnnou metaclass, ale musíme použít parametr třídy metaclass.

>>> class M(type):
...     pass
...
>>> class C(metaclass=M):
...     pass
... 

Cyklus for už není tak benevolentní ke svému vstupu a zápis z Pythonu 2.x:

>>> for x in 1,2,3,4:
...     print x
...
1
2
3
4 

Už nebude možný a budeme muset použít:

>>> for x in (1,2,3,4):
...     print(x)
...
1
2
3
4 

V definici funkce nebudeme moci používat typ tuple, ale musíme ho nahradit jedinou proměnnou. Toto by v řadě 2.x ještě prošlo:

>>> def foo(a,(b,c)):
...     print a,b,c
...
>>> foo(1,(2,3))
1 2 3 

Ale nyní musíme skript upravit:

>>> def foo(a,b):
...     print(a,b)
...
>>> foo(1,(2,3))
1 (2, 3) 

Funkce raw_input() byla přejmenována na input().

>>> var = input("piš:")
piš:Foo
>>> print(var)
Foo 

Operátor <> je nahrazen operátorem !=. Klíčové slovo exec již nadále není klíčové slovo a místo něj byla zavedena funkce exec(). Jako funkce teď již nebere jako argument objekt se souborem, ale pouze text. Již z minulého dílu je jasné, že zápisy u"" nebo 10L končí, protože Python teď již nedělá rozdíl mezi dlouhými a krátkými celými čísly a text je vždy unicode. Klasické třídy byly kompletně z Pythonu odstraněny a byly nahrazeny novým stylem známým již z minulých řad, kde ale tento styl nebyl jako výchozí.

Velké změny se týkají také výjimek. API bylo vyčištěno a nové vlastnosti přidány. Všechny výjimky nově musí být odvozeny přímo či nepřímo od BaseException. Výjimka StandardError byla odstraněna a také se dále nechovají jako sekvence. Jako náhrada se používají argumenty. To znamená, že „raise Exception, args“ už fungovat nebude a musíme použít „raise Exception(args)“.

Nástroj 2to3

Ukázkový zdrojový kód

Ukázkový kód jsem složil z několika problémových částí, které nás budou v příštích měsících potkávat, a na nich si můžeme zkusit, jak se s nimi 2to3 vypořádá. Schválně jsem tedy použil takové konstrukce, které v Pythonu 3.0 nepojedou. Na druhou stranu nejedná se o všechny, takový skript by pak byl nepřiměřeně dlouhý.

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import os

l = long(1000000)
print "%d %s"%(l/2,u"ěščřžý")
print

if 1 < "":
    print type(1/2)
    print 1/2

f = open("testfile","wb")
f.write("ěščř\n")
f.close()

f = os.tmpfile()
f.write("foo")
f.close() 

Správný výstup programu:

cx@ubuntu:~$ python2.5 test.py; cat testfile
500000 ěščřžý

<type 'int'>
0
ěščř 

Co o kódu řekne Python 2.6

Moc nám toho Python 2.6 o ukázkovém kódu neřekl. Prakticky informuje pouze o špatně zvolené podmínce.

500000 ěščřžý

test.py:10: DeprecationWarning: comparing unequal types not supported in 3.x
  if 1 < "":
<type 'int'>
0
ěščř 

Použití nástroje 2to3

Nástroj 2to3 je koncipován tak, aby nám dodal patch, se kterým můžeme dál pracovat, upravovat ho a hlavně aplikovat.

cx@ubuntu:~$ 2to3 test.py
RefactoringTool: Skipping implicit fixer: buffer
RefactoringTool: Skipping implicit fixer: idioms
RefactoringTool: Skipping implicit fixer: set_literal
RefactoringTool: Skipping implicit fixer: ws_comma
--- test.py (original)
+++ test.py (refactored)
@@ -3,13 +3,13 @@

 import os

-l = long(1000000)
-print "%d %s"%(l/2,u"ěščřžý")
-print
+l = int(1000000)
+print("%d %s"%(l/2,"ěščřžý"))
+print()

 if 1 < "":
-       print type(1/2)
-       print 1/2
+       print(type(1/2))
+       print(1/2)

 f = open("testfile","wb")
 f.write("ěščř\n")
RefactoringTool: Files that need to be modified:
RefactoringTool: test.py 

Lze ho aplikovat i na celé adresáře a on bude rekurzivně hledat zdrojové kódy a generovat pro ně patch. Patch samotný se kopíruje na standardní výstup a další informace na standardní chybový výstup. Proto není problém získat samotný patch.

Je-li patch v pořádku, přejdeme k jeho aplikaci:

cx@ubuntu:~$ cat test.patch | patch -p0
patching file test.py 

Co je potřeba doladit

--- testB.py    2008-12-14 22:17:39.000000000 +0100
+++ testA.py    2008-12-14 22:12:19.000000000 +0100
@@ -7,16 +7,17 @@
 print("%d %s"%(l/2,"ěščřžý"))
 print()

-if 1 < "":
+if 1 < 2:
        print(type(1/2))
        print(1/2)

 f = open("testfile","wb")
-f.write("ěščř\n")
+f.write("ěščř\n".encode("utf8"))
 f.close()

-f = os.tmpfile()
-f.write("foo")
+import tempfile
+f = tempfile.TemporaryFile()
+f.write("foo".encode("iso-8859-2"))
 f.close() 

Výstup z nástroje 2to3 sice vyladí jednoduché věci kolem typů a funkce print, ale s těmi složitějšími si neporadí. Stačilo mu předhodit funkci, která s Pythonem 3.0 zmizí, a bylo zapotřebí ručního zásahu, i když má funkce svoji náhradu v jiném modulu.

Další možnosti 2to3

Může se stát, že 2to3 opraví něco špatně. Jedná se o modulární nástroj a my můžeme použít na nás zdrojový kód pouze pár z těchto modulů. Také si můžeme napsat vlastní. Moduly se nacházejí v adresáři /usr/lib/python3­.0/lib2to3/fi­xes/.

List dostupných modulů dostaneme buď vypsáním obsahu zmíněného adresáře nebo v použitelnější formě pomocí:

cx@ubuntu:~$ 2to3 -l
Available transformations for the -f/--fix option:
apply
basestring
buffer
callable
[...] 

Jednotlivé moduly pak můžeme aplikovat pomocí parametru -f.

Závěr

Problémy s Pythonem 3.0 budou a takovýchto ručních zásahů bude potřeba víc. Jak jsem psal již minule, ne všechny projektu používají zasažené části pythonu, takže se klidně může stát, že 2to3 a pár ručních oprav budou dostačující. Množství malých skriptů nebude dělat problémy vůbec. Webové stránky napsané v Pythonu jsou většinou založené na jednom z pythoních frameworků a tam většina práce zůstane na vývojářích daného frameworku. Změny jsou známy již delší dobu, takže se vývojáři podobných projektů většinou vyhýbají postiženým konstrukcím nebo si nechávají cestu, jak z toho ven. Proto by neměl být to neměl být problém ani v tomto směru.

Nezbývá než popřát hodně štěstí.

Odkazy

Byl pro vás článek přínosný?

Autor článku

Adam Štrauch je redaktorem serveru Root.cz a svobodný software nasazuje jak na desktopech tak i na routerech a serverech. Ve svém volném čase se stará o komunitní síť, ve které je již přes 100 členů.