3. . . . . . .
Po co tekst i I/O
Większość programów komunikują się ze światem za pomocą
czytelnego tekstu.
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 3 / 91
4. . . . . . .
Po co tekst i I/O
Większość programów komunikują się ze światem za pomocą
czytelnego tekstu.
odczytują i zapisują tekst z pliku
odczytują i zapisują tekst do bazy danych
odbierają i wysyłają po tekst po sieci.
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 3 / 91
5. . . . . . .
Po co tekst i I/O
Większość programów komunikują się ze światem za pomocą
czytelnego tekstu.
odczytują i zapisują tekst z pliku
odczytują i zapisują tekst do bazy danych
odbierają i wysyłają po tekst po sieci.
I/O jest “corem” tego do czego używamy Pythona (skrypty,
przetwarzanie danych, sklejanie programów ...)
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 3 / 91
6. . . . . . .
Po co tekst i I/O
Większość programów komunikują się ze światem za pomocą
czytelnego tekstu.
odczytują i zapisują tekst z pliku
odczytują i zapisują tekst do bazy danych
odbierają i wysyłają po tekst po sieci.
I/O jest “corem” tego do czego używamy Pythona (skrypty,
przetwarzanie danych, sklejanie programów ...)
Co się pojawiło? Python 3
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 3 / 91
7. . . . . . .
Python 3
W Python 3 na nowo zaimplementowano biblioteki powiązane z I/O.
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 4 / 91
8. . . . . . .
Python 3
W Python 3 na nowo zaimplementowano biblioteki powiązane z I/O.
Mamy nowe typy danych
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 4 / 91
9. . . . . . .
Python 3
W Python 3 na nowo zaimplementowano biblioteki powiązane z I/O.
Mamy nowe typy danych
Python 3 dostarcza wprowadza w ogóle dużo zmian (nowe biblioteki,
część starych bibliotek pod nowymi nazwami - eg urllib …)
Większość starego kodu (z Pythona 2) da się przenieść do Pythona 3 za
pomocą narzędzia 2to3
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 4 / 91
10. . . . . . .
Python 3
W Python 3 na nowo zaimplementowano biblioteki powiązane z I/O.
Mamy nowe typy danych
Python 3 dostarcza wprowadza w ogóle dużo zmian (nowe biblioteki,
część starych bibliotek pod nowymi nazwami - eg urllib …)
Większość starego kodu (z Pythona 2) da się przenieść do Pythona 3 za
pomocą narzędzia 2to3
Ale nie operacje I/O
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 4 / 91
18. . . . . . .
Python 3
built-ins
zmieniono wiele wbudowanych operatorów
range tworzą teraz generator, a nie listy
wiele kolekcji zwracają iteratory zamiast list
ogólnie Python 3 preferuje iteratory / generatory
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 8 / 91
19. . . . . . .
Python 3
Porządek w bibliotece
Python2:
urllib, urllib2 - dwie biblioteki? gdzie co jest i po co?
from urllib2 import urlopen
u = urlopen("http://www.example.com")
Queue, SocketServer
anydbm, dbhash, dbm, dumbdbm, gdbm ...
Python3
urllib - jedna biblioteka z poukładaną funkcjonalnością
from urllib.request import urlopen
u = urlopen("http://www.example.com")
queue, socketserver
dbm.{anydbm, dbhash, dbm, dumbdbm, gdbm ...}
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 9 / 91
20. . . . . . .
Python 3
2to3
Przykładowy kod dla Python2.7
# printlinks.py
import urllib
import sys
from HTMLParser import HTMLParser
class LinkPrinter(HTMLParser):
def handle_starttag(self,tag,attrs):
if tag == 'a':
for name,value in attrs:
if name == 'href': print value
data = urllib.urlopen(sys.argv[1]).read()
LinkPrinter().feed(data)
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 10 / 91
21. . . . . . .
Python 3
2to3
użycie narzędzia 2to3.
Pokazuje co i jak zamienić
bash % 2to3 printlinks.py
...
--- printlinks.py (original)
+++ printlinks.py (refactored)
@@ -1,12 +1,12 @@
-import urllib
+import urllib.request, urllib.parse, urllib.error
-from HTMLParser import HTMLParser
+from html.parser import HTMLParser
-if name == 'href': print value
+if name == 'href': print(value)
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 11 / 91
22. . . . . . .
Python 3
2to3
użycie narzędzia 2to3.
Pokazuje co i jak zamienić
bash % 2to3 printlinks.py
...
--- printlinks.py (original)
+++ printlinks.py (refactored)
@@ -1,12 +1,12 @@
-import urllib
+import urllib.request, urllib.parse, urllib.error
-from HTMLParser import HTMLParser
+from html.parser import HTMLParser
-if name == 'href': print value
+if name == 'href': print(value)
Ale dalej nie działa, czemu?
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 11 / 91
23. . . . . . .
Python 3
2to3
bash % python3 printlinks.py http://www.python.org
Traceback (most recent call last):
File "printlinks.py", line 12, in <module>
LinkPrinter().feed(data)
File "/Users/beazley/Software/lib/python3.1/html/parser.py",
line 107, in feed
self.rawdata = self.rawdata + data
TypeError: Can't␣convert␣'bytes'␣object␣to␣str␣implicitly
Jak widzimy błąd jest w obsłudze napisów.
2to3 nie może zgadnąć o jakie napisy nam chodzi
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 12 / 91
24. . . . . . .
Python 3
2to3
bash % python3 printlinks.py http://www.python.org
Traceback (most recent call last):
File "printlinks.py", line 12, in <module>
LinkPrinter().feed(data)
File "/Users/beazley/Software/lib/python3.1/html/parser.py",
line 107, in feed
self.rawdata = self.rawdata + data
TypeError: Can't␣convert␣'bytes'␣object␣to␣str␣implicitly
Jak widzimy błąd jest w obsłudze napisów.
2to3 nie może zgadnąć o jakie napisy nam chodzi
Fix:
LinkPrinter().feed(data.decode(′
utf − 8′
))
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 12 / 91
25. . . . . . .
Python 3
I/O
Po co to wszytko?
Wiele “prawdziwych” programów polegają na I/O
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 13 / 91
27. . . . . . .
Tekst
Problemy
kodowanie - koszmar
Zależności między bibliotekami
biblioteki operują na stringach
trzeba konfigurować klasy aby wiedziały jak stringi są kodowane
znak → ile bajtów go koduje?
tłumaczenie tekstów
niektóre biblioteki nie obsługują wielu kodowań automatycznie
trzeba samemu przekodowywać tekst
wczytywanie plików.
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 15 / 91
28. . . . . . .
Tekst
Problemy
kodowanie - koszmar
Zależności między bibliotekami
biblioteki operują na stringach
trzeba konfigurować klasy aby wiedziały jak stringi są kodowane
znak → ile bajtów go koduje?
tłumaczenie tekstów
niektóre biblioteki nie obsługują wielu kodowań automatycznie
trzeba samemu przekodowywać tekst
wczytywanie plików.
Python ma być w prosty i intuicyjny
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 15 / 91
29. . . . . . .
Tekst
co poukładano
W Python 3 tekst jest unicode
przetwarzanie tekstu także odbywa się na podstawie unicode
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 16 / 91
30. . . . . . .
Tekst
Unicode
każdy znak ma swój unikalny kod (w lokalne kodowania są
przystosowane do lokalnych alfabetów)
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 17 / 91
31. . . . . . .
Tekst
Unicode
każdy znak ma swój unikalny kod (w lokalne kodowania są
przystosowane do lokalnych alfabetów)
większa “pojemność znaku”
tekst więcej zajmuje :(
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 17 / 91
32. . . . . . .
Tekst
Unicode
każdy znak ma swój unikalny kod (w lokalne kodowania są
przystosowane do lokalnych alfabetów)
większa “pojemność znaku”
tekst więcej zajmuje :( )
największy numer znaku: U+10FFF
http://www.unicode.org/charts
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 17 / 91
33. . . . . . .
Tekst
Unicode
każdy znak ma swój unikalny kod (w lokalne kodowania są
przystosowane do lokalnych alfabetów)
większa “pojemność znaku”
tekst więcej zajmuje :( )
największy numer znaku: U+10FFF
http://www.unicode.org/charts
unicode literals:
"xf1" # standard ascii 'ñ'
"u2191": # ↑
"U0001d122"
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 17 / 91
34. . . . . . .
Tekst
testy z konsolą
testowanie znaków w python2 i python3
methody repr, ascii, chr
ascii('ś') # nowa metoda w python3
repr('ś')
chr(0x15b)
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 18 / 91
35. . . . . . .
Tekst
Unicode
Unicod jest przechowywany jako “C” int
sprawdzenie:
>>> sys.maxunicode
65535
# 16-bits
>>> sys.maxunicode
1114111
# 32-bits
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 19 / 91
36. . . . . . .
Tekst
Unicode
Tekst w Python3 zajmuje 2 lub 4 razy więcej niż w Python2
z tego powodu operacje na tekście wykonują się dłużej:
praca z konsolą
timeit("text[:-1]","text='x'*100000")
timeit("text.upper()","text='x'*1000")
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 20 / 91
37. . . . . . .
Tekst
Unicode - zalety
Bez względu na kodowanie tekstu w pliku, w pythonie dany tekst jest
zawsze tak samo reprezentowany (jako unicode)
Biblioteki nie muszą martwić się o kodowanie
użytkownik nie musi martwić się komunikację z bibliotekami i
wyświetlanie
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 21 / 91
38. . . . . . .
Tekst
Unicode - zalety
Bez względu na kodowanie tekstu w pliku, w pythonie dany tekst jest
zawsze tak samo reprezentowany (jako unicode)
Biblioteki nie muszą martwić się o kodowanie
użytkownik nie musi martwić się komunikację z bibliotekami i
wyświetlanie
przy czytaniu strumienia od razu musimy zadeklarować kodowanie →
mniej błędów
Wbudowana funkcja open() przyjmuje teraz argument encoding z
domyślną wartością "utf-8"
w pythonie 2 wszystko to było ukryte, co mogło powodować błędy w
przyszłości
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 21 / 91
39. . . . . . .
Tekst
Unicode - konsekwencje
unicode to wewnętrzna struktura pythona
inne programy mogą jej nie rozumieć
Aby przesyłać unicode trzeba używać metod encode, decode
>>> s = "Jalapeño"
>>> data = s.encode('utf-8')
>>> data
b'Jalapexc3xb1o'
>>> data.decode('utf-8')
'Jalapeño'
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 22 / 91
40. . . . . . .
Tekst
Unicode - Python3, podsumowanie
Python3 używa unicode do reprezentacji “stringów”
unicode to inty
Jeśli nie zaznaczysz inaczej, każdy unicode będzie zakładał kodowanie
UTF-8
strumienie bajtów to (bytes)
bytes nie “zna” kodowań
bytes to ciągi bajtów
byets wspiera operacje na ciągach (teracja, slices...)
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 23 / 91
41. . . . . . .
Tekst
Unicode - błędy na jakie można się natrafić
Błąd używania złego kodowania
>>> f = open('foo',encoding='ascii')
>>> data = f.read()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/python3.2/encodings/
ascii.py", line 26, in decode
return codecs.ascii_decode(input, self.errors)
[0]
UnicodeDecodeError: 'ascii' codec can't␣decode␣byte
0xc3␣in␣position␣6:␣ordinal␣not␣in␣range(128)
>>>
>>>␣f␣=␣open('foo',encoding='utf-8')
>>>␣data␣=␣f.read()
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 24 / 91
42. . . . . . .
Tekst
Uwagi
unicode to potężny standard. Niektóre znaki są prezentowane jako
różne kody
>>> s = "Jalapexf1o"
>>> t = "Jalapenu0303o" # 'n' + ' '
>>> s
'Jalapeño'
>>> t
'Jalapeño'
>>> s == t
False
>>> len(s), len(t)
(8, 9)
mimo to tekst powinien być jednoznaczny - jako że kody klawiatury
są ustandaryzowane.
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 25 / 91
44. . . . . . .
Print
nowe użycie
definiowanie separatora
>>> print(1,2,3,sep=':')
1:2:3
# python2
>>> print("Hello","World",sep='')
HelloWorld
definiowanie końca linii
>>> print("What?",end="!?!n")
What?!?!
Pytanie: jak w python2 wydrukować coś na ekran bez znaku nowej
linii na końcu
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 27 / 91
45. . . . . . .
Print
nowe użycie
definiowanie separatora
>>> print(1,2,3,sep=':')
1:2:3
# python2
>>> print("Hello","World",sep='')
HelloWorld
definiowanie końca linii
>>> print("What?",end="!?!n")
What?!?!
Pytanie: jak w python2 wydrukować coś na ekran bez znaku nowej
linii na końcu
>>> sys.stdout.write()
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 27 / 91
46. . . . . . .
Formatowanie tekstu
python2
s = "%10.2f" % price
python3
s = format(price,"10.2f")
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 28 / 91
47. . . . . . .
Formatowanie tekstu
funkcje str, repr, format
funkcje str, repr, format wywołują odpowiednio metody obiektu:
__str__, __repr__, __format__
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 29 / 91
48. . . . . . .
Formatowanie tekstu
funkcje str, repr, format
funkcje str, repr, format wywołują odpowiednio metody obiektu:
__str__, __repr__, __format__
format bierze dodatkowy argument - “code formaters”, analogiczny
do % z python2
>>> x = 1/3
>>> format(x,"0.4f")
'0.3333'
>>> format(x,"20.2f")
'␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣0.33'
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 29 / 91
53. . . . . . .
Formatowanie tekstu
code formaters
metodę __format__(self, fmt) można nadpisać.
Wtedy sami możemy interpretować “code formaters” oraz dodawać swoje
kody.
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 33 / 91
54. . . . . . .
Formatowanie tekstu
string format
Metoda format dla napisów pozwala na tworzenie “koszyków” w tekście.
Koszyki później są zastępowane odpowiednimi wartościami.
Koszyki te mogą zawiertać formatery i argumenty:
pozycyjne
"{0}␣has␣{1}␣messages".format("Dave",37)
pozycyjne
"{name}␣has␣{n}␣messages".format(name="Dave",n=37)
pozycyjne
"{}␣has␣{}␣messages".format("Dave",37)
indeksowe
record = {'name' : 'Dave', 'n' : 37}
'{r[name]}␣has␣{r[n]}␣messages'.format(r=record)
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 34 / 91
55. . . . . . .
Formatowanie tekstu
string format
Jak tworzona jest wartość obiektu który “wkładamy” do koszyka
formatera?
{item} # Replaced by str(item)
{item!r} # Replaced by repr(item)
{item:fmt} # Replaced by format(item, fmt)
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 35 / 91
56. . . . . . .
Formatowanie tekstu
string format
Jak tworzona jest wartość obiektu który “wkładamy” do koszyka
formatera?
{item} # Replaced by str(item)
{item!r} # Replaced by repr(item)
{item:fmt} # Replaced by format(item, fmt)
foramt pozwala na pojedyncze zagnieżdżenie {}
>>> s = ('ACME',50,91.10)
>>> "{0:{width}s}␣{2:{width}.2f}".format(*s,width=12)
'ACME␣␣␣␣␣␣␣␣91.10'
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 35 / 91
57. . . . . . .
Formatowanie tekstu
string format
Jak stworzyć znak ’{’ w formaterze?
Trzeba użyć ’{{’
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 36 / 91
58. . . . . . .
Formatowanie tekstu
format_map
Metoda format może korzystać z nazwanych argumentów podczas
formatowania tekstu. Jeśli już mamy słownik i nie chcemy nadmiernie
tworzyć ekspansji słownika, możemy skorzystać z metody format_map,
która oczekuje słownika, a nie listy argumentów.
"{name}␣has␣{n}␣messages".format_map({
'name': 'Robert'
'n': 'Hello'
})
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 37 / 91
59. . . . . . .
Szablony tekstu
string.Templates
Podobną funkcjonalność do formatowania napisów daje klasa
string.Template:
from string import Template
msg = Template("namehasn messages")
print(msg.substitute(name="Dave",n=37)
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 38 / 91
61. . . . . . .
Bytes
definiowanie
Definiowanie “bytes”
a = b"ACME␣50␣91.10" # Byte string literal
b = bytes([1,2,3,4,5]) # From a list of integers
c = bytes(10) # An array of 10 zero-bytes
d = bytes("Jalapeño","utf-8") # Encoded from string
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 40 / 91
62. . . . . . .
Bytes
definiowanie
Definiowanie “bytes”
a = b"ACME␣50␣91.10" # Byte string literal
b = bytes([1,2,3,4,5]) # From a list of integers
c = bytes(10) # An array of 10 zero-bytes
d = bytes("Jalapeño","utf-8") # Encoded from string
Tworzenie z stringu zawierającego liczbę hexadecimal
e = bytes.fromhex("48656c6c6f")
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 40 / 91
63. . . . . . .
Bytes
właściwości
Bytes posiada standardowe metody napisów
>>> s = b"ACME␣50␣91.10"
>>> s.split()
[b'ACME', b'50', b'91.10']
>>> s.lower()
b'acme␣50␣91.10'
>>> s[5:7]
b'50'
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 41 / 91
64. . . . . . .
Bytes
właściwości
Bytes posiada standardowe metody napisów
>>> s = b"ACME␣50␣91.10"
>>> s.split()
[b'ACME', b'50', b'91.10']
>>> s.lower()
b'acme␣50␣91.10'
>>> s[5:7]
b'50'
Bytes tak samo jak napisy są niemutowalne
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 41 / 91
65. . . . . . .
Bytes
właściwości
bytes to tablica int-ów
>>> s = b"ACME␣50␣91.10"
>>> s[0]
65
>>> s[1]
67
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 42 / 91
66. . . . . . .
Bytes
właściwości
bytes to tablica int-ów
>>> s = b"ACME␣50␣91.10"
>>> s[0]
65
>>> s[1]
67
bytes to standardowa struktura operacji I/O
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 42 / 91
67. . . . . . .
Bytes
Problemy
Portowanie kodu z Python2 do Python3
data = s.recv(1024)
if data[0] == b'+': # ERROR!
...
# fix
data = s.recv(1024)
if data[0] == 0x2b: # CORRECT
...
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 43 / 91
68. . . . . . .
Bytes
Portowanie
Nie potrzeba używać metody ord
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 44 / 91
69. . . . . . .
Bytes
Portowanie
Nie potrzeba używać metody ord
konwersja obiektów do “bytes” - postać binarna obiektów:
>>> x = 7
>>> bytes(x)
b'x00x00x00x00x00x00x00'
>>> str(x).encode('ascii')
b'7'
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 44 / 91
70. . . . . . .
bytearray
bytearray to mutowalne “bytes”
>>> s = bytearray(b"ACME␣50␣91.10")
>>> s[:4] = b"PYTHON"
>>> s
bytearray(b"PYTHON␣50␣91.10")
>>> s[0] = 0x70 # Must assign integers
>>> s
bytearray(b'pYTHON␣50␣91.10")
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 45 / 91
71. . . . . . .
bytearray
bytearray to mutowalne “bytes”
>>> s = bytearray(b"ACME␣50␣91.10")
>>> s[:4] = b"PYTHON"
>>> s
bytearray(b"PYTHON␣50␣91.10")
>>> s[0] = 0x70 # Must assign integers
>>> s
bytearray(b'pYTHON␣50␣91.10")
zawiera wiele operacji “listowych”
>>> s.append(23)
>>> s.append(45)
>>> s.extend([1,2,3,4])
>>> s
bytearray(b'ACME␣50␣91.10x17-x01x02x03x04')
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 45 / 91
72. . . . . . .
Bytes a Unicode
bytes nie służy do przetwarzania tekstu
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 46 / 91
73. . . . . . .
Bytes a Unicode
bytes nie służy do przetwarzania tekstu
można użyć ich do tekstu - grozi to strasznym problemom (s[1] to nie
litera, a część kodu litery)
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 46 / 91
74. . . . . . .
Bytes a Unicode
bytes nie służy do przetwarzania tekstu
można użyć ich do tekstu - grozi to strasznym problemom (s[1] to nie
litera, a część kodu litery)
Python3 jasno oddziela tekst od ciągu bajtów (unicode vs bytes)
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 46 / 91
75. . . . . . .
Bytes a Unicode
bytes nie służy do przetwarzania tekstu
można użyć ich do tekstu - grozi to strasznym problemom (s[1] to nie
litera, a część kodu litery)
Python3 jasno oddziela tekst od ciągu bajtów (unicode vs bytes)
>>> s = b"ACME␣50␣91.10"
>>> 'ACME' in s
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Type str doesn't␣support␣the␣buffer␣API
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 46 / 91
76. . . . . . .
Bytes a Unicode
bytes nie służy do przetwarzania tekstu
można użyć ich do tekstu - grozi to strasznym problemom (s[1] to nie
litera, a część kodu litery)
Python3 jasno oddziela tekst od ciągu bajtów (unicode vs bytes)
>>> s = b"ACME␣50␣91.10"
>>> 'ACME' in s
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Type str doesn't␣support␣the␣buffer␣API
print() powiniena być tylko używana z tekstem (unicode)
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 46 / 91
77. . . . . . .
Bytes a Unicode
bytes nie służy do przetwarzania tekstu
można użyć ich do tekstu - grozi to strasznym problemom (s[1] to nie
litera, a część kodu litery)
Python3 jasno oddziela tekst od ciągu bajtów (unicode vs bytes)
>>> s = b"ACME␣50␣91.10"
>>> 'ACME' in s
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Type str doesn't␣support␣the␣buffer␣API
print() powiniena być tylko używana z tekstem (unicode)
Bytes nie wspierają metody format
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 46 / 91
78. . . . . . .
Bytes a Unicode
bytes nie służy do przetwarzania tekstu
można użyć ich do tekstu - grozi to strasznym problemom (s[1] to nie
litera, a część kodu litery)
Python3 jasno oddziela tekst od ciągu bajtów (unicode vs bytes)
>>> s = b"ACME␣50␣91.10"
>>> 'ACME' in s
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Type str doesn't␣support␣the␣buffer␣API
print() powiniena być tylko używana z tekstem (unicode)
Bytes nie wspierają metody format
Wiele funkcji operujących na tekście nie akcepują bytes (np:
time.strptime)
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 46 / 91
79. . . . . . .
Gdzie używać bytes
bytes nadają się do niskopoziomowych operacji I/O. (przekazywanie
wiadomości, systemy wbudowane, obliczenia rozproszone …)
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 47 / 91
80. . . . . . .
Użycie bytes
konkatenacja ciągu w Python2
chunks = []
while True:
chunk = s.recv(BUFSIZE)
if not chunk:
break
chunks.append(chunk)
msg = b"".join(chunks)
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 48 / 91
81. . . . . . .
Użycie bytes
konkatenacja ciągu w Python2
chunks = []
while True:
chunk = s.recv(BUFSIZE)
if not chunk:
break
chunks.append(chunk)
msg = b"".join(chunks)
konkatenacja ciągu w Python3
msg = bytearray()
while True:
chunk = s.recv(BUFSIZE)
if not chunk:
break
msg.extend(chunk)
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 48 / 91
82. . . . . . .
Użycie bytes
konkatenacja ciągu w Python2
chunks = []
while True:
chunk = s.recv(BUFSIZE)
if not chunk:
break
chunks.append(chunk)
msg = b"".join(chunks)
konkatenacja ciągu w Python3
msg = bytearray()
while True:
chunk = s.recv(BUFSIZE)
if not chunk:
break
msg.extend(chunk)
wielka wydajność operacji na bytes i bytearray
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 48 / 91
83. . . . . . .
Użycie bytes
przekazywanie wiadomości
Przekazywanie wiadomości.
objs = [ ... ] # List of tuples to pack
msg = bytearray() # Empty message
# First pack the number of objects
msg.extend(struct.pack("<I",len(objs)))
for x in objs: # Incrementally pack each object
msg.extend(struct.pack(fmt, *x))
f.write(msg) # Do something with the message
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 49 / 91
84. . . . . . .
Użycie bytes
XOR - cipher
kodowanie XOR
>>> s = b"Hello␣World"
>>> t = bytes(x^42 for x in s)
>>> t
b'bOFFEn}EXFN'
>>> bytes(x^42 for x in t)
b'Hello␣World'
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 50 / 91
85. . . . . . .
Użycie bytes
suma kontrolna
dołączanie sumy kontrolnej
chk = 0
for n in msg:
chk ^= n
msg.append(chk)
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 51 / 91
86. . . . . . .
Bufory
podobieństwa bytearray buffers
bufor to ciągły obszar pamięci
bufferarray() jest przykładem buforu
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 52 / 91
87. . . . . . .
Bufory
podobieństwa bytearray buffers
bufor to ciągły obszar pamięci
bufferarray() jest przykładem buforu
przykład:
array.array("i", [1,2,3,4,5])
numpy.array([1,2,3,4,5])
ctypes.ARRAY(ctypes.c_int,5)(1,2,3,4,5)
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 52 / 91
88. . . . . . .
Bufory
podobieństwa bytearray buffers
bufor to ciągły obszar pamięci
bufferarray() jest przykładem buforu
przykład:
array.array("i", [1,2,3,4,5])
numpy.array([1,2,3,4,5])
ctypes.ARRAY(ctypes.c_int,5)(1,2,3,4,5)
można powiedzieć że powyższe struktury są zamienne z typem bytes
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 52 / 91
89. . . . . . .
Memory View
memoryview to “nakładka na bufor” - patrz help()
>>> a = bytearray(b'Hello␣World')
>>> b = memoryview(a)
>>> b
<memory at 0x1007014d0>
>>> b[-5:] = b'There'
>>> a
bytearray(b'Hello␣There')
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 53 / 91
90. . . . . . .
Memory View
memoryview to “nakładka na bufor” - patrz help()
>>> a = bytearray(b'Hello␣World')
>>> b = memoryview(a)
>>> b
<memory at 0x1007014d0>
>>> b[-5:] = b'There'
>>> a
bytearray(b'Hello␣There')
jest bardzo niskopoziomową strukturą
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 53 / 91
92. . . . . . .
implementacja I/O
w Pytonie2 I/O jest oparte o c I/O
python “file” to tylko cienka nakładka na C “FILE”
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 55 / 91
93. . . . . . .
implementacja I/O
w Pytonie2 I/O jest oparte o c I/O
python “file” to tylko cienka nakładka na C “FILE”
Python3 wprowadza swoją strukturę
jak było już powiedziane Python3 przeimplementował system I/O
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 55 / 91
94. . . . . . .
funkcja open()
użycie podobnie jak wcześniej
obiekt zwracany przez open różni się w zależności o ustawionego
argumentu file mode
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 56 / 91
95. . . . . . .
funkcja open()
użycie podobnie jak wcześniej
obiekt zwracany przez open różni się w zależności o ustawionego
argumentu file mode
przykład poniżej
>>> open("foo.txt","rt")
<_io.TextIOWrapper name='foo.txt' encoding='UTF-8'>
>>> open("foo.txt","rb")
<_io.BufferedReader name='foo.txt'>
>>> open("foo.txt","rb",buffering=0)
<_io.FileIO name='foo.txt' mode='rb'>
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 56 / 91
96. . . . . . .
funkcja open()
użycie podobnie jak wcześniej
obiekt zwracany przez open różni się w zależności o ustawionego
argumentu file mode
przykład poniżej
>>> open("foo.txt","rt")
<_io.TextIOWrapper name='foo.txt' encoding='UTF-8'>
>>> open("foo.txt","rb")
<_io.BufferedReader name='foo.txt'>
>>> open("foo.txt","rb",buffering=0)
<_io.FileIO name='foo.txt' mode='rb'>
task: uruchomienie tego w python2
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 56 / 91
97. . . . . . .
Moduł I/O
moduł io składa się z różny klas:
FileIO
BufferedReader
BufferedWriter
BufferedRWPair
BufferedRandom
TextIOWrapper
BytesIO
StringIO
każda klasa implementuje inny rodzaj I/O
każda klasa dodaje pewien zbiór właściwości
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 57 / 91
98. . . . . . .
Moduł I/O
warstwy I/O
otwarcie pliku powoduje kolejno tworzenie obiektów
open("foo.txt", "rt")
(TextIOWrapper → BufferedReader → FileIO
w Javie jest podobnie
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 58 / 91
99. . . . . . .
Moduł I/O
FileIO
obiekt reprezentujący surowy niebuforowany obiekt binary
(FileIO(name [, mode [, closefd]])
name nazwa pliku lub numer fd
mode ’r’, ’w’, ’a’, ’r+’, …
closefd flaga kontrolująca czy metoda close() była wywołana.
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 59 / 91
100. . . . . . .
Moduł I/O
FileIO
obiekt reprezentujący surowy niebuforowany obiekt binary
(FileIO(name [, mode [, closefd]])
name nazwa pliku lub numer fd
mode ’r’, ’w’, ’a’, ’r+’, …
closefd flaga kontrolująca czy metoda close() była wywołana.
FileIO jest bezpośrednio zaimplemenowany na podstawie
systemowych funkcji read(), write()
bezpośrednio daje dostęp do niskopoziomowych wywołań
systemowych na deskryptorze pliku
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 59 / 91
101. . . . . . .
Moduł I/O
FileIO
obiekt reprezentujący surowy niebuforowany obiekt binary
(FileIO(name [, mode [, closefd]])
name nazwa pliku lub numer fd
mode ’r’, ’w’, ’a’, ’r+’, …
closefd flaga kontrolująca czy metoda close() była wywołana.
FileIO jest bezpośrednio zaimplemenowany na podstawie
systemowych funkcji read(), write()
bezpośrednio daje dostęp do niskopoziomowych wywołań
systemowych na deskryptorze pliku
w tym: częściowy odczyt / zapis, zwracanie systemowych kodów
błędów, dostęp blokowany, nieblokowany (asynchroniczny)
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 59 / 91
102. . . . . . .
FileIO
używanie
Python2 - moduł os
fd = os.open("somefile",os.O_RDONLY)
data = os.read(fd,4096)
os.lseek(fd,16384,os.SEEK_SET)
Python3 - obiekt FileIO
f = io.FileIO("somefile","r")
data = f.read(4096)
f.seek(16384,os.SEEK_SET)
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 60 / 91
104. . . . . . .
BufferedIO
klasy implementujące buforowany I/O
BufferedReader(f [, buffer_size])
BufferedWriter(f [, buffer_size [, max_buffer_size]])
BufferedRWPair(f_read, f_write
[, buffer_size [, max_buffer_size]])
BufferedRandom(f [, buffer_size [, max_buffer_size]])
każda z poniższych klas jest implementacją opartą o FileIO
f = io.FileIO("foo.txt") # Open the file (raw I/O)
g = io.BufferedReader(f) # Put buffering around it
f = io.BufferedReader(io.FileIO("foo.txt")) # Alternative
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 61 / 91
105. . . . . . .
Bufory
Bufory są kontrolowane przez dwa parametry:
buffer_size, max_buffer_size
buffer_size - ilość danych jaką bufor może przechować zanim “opróżni
się” do I/O
max_buffer_size - pojemność jaką posiada bufor zanim się zablokuje
(domyślnie 2x buffer_size)
Aby bufor zaakceptował więcej danych, należy wcześniej go opróżnić.
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 62 / 91
106. . . . . . .
Bufory
operacje na buforach
buffer readers:
f.peek([n]) # Return up to n bytes of data without
# advancing the file pointer
f.read([n]) # Return n bytes of data as bytes
f.read1([n]) # Read up to n bytes using a single
# read() system call
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 63 / 91
107. . . . . . .
Bufory
operacje na buforach
buffer readers:
f.peek([n]) # Return up to n bytes of data without
# advancing the file pointer
f.read([n]) # Return n bytes of data as bytes
f.read1([n]) # Read up to n bytes using a single
# read() system call
buffer writers
f.write(bytes) # Write bytes
f.flush() # Flush output buffers
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 63 / 91
108. . . . . . .
Bufory
operacje na buforach
buffer readers:
f.peek([n]) # Return up to n bytes of data without
# advancing the file pointer
f.read([n]) # Return n bytes of data as bytes
f.read1([n]) # Read up to n bytes using a single
# read() system call
buffer writers
f.write(bytes) # Write bytes
f.flush() # Flush output buffers
inne operacje:
seek, tell, close
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 63 / 91
109. . . . . . .
UWAGA
dla obiektów “pliko podobnych”
Jeśli używamy obiektów “pliko podobnych” powinniśmy używać
metody
readl()
jeśli pominiemy tą uwagę nasz program może się rozpaść jeśli inny
wątek / program będzie chciał się odwołać do tego samego pliku
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 64 / 91
110. . . . . . .
TextIOWrapper
obiekt implementujący text-based I/O
TextIOWrapper(buffered [, encoding [, errors
[, newline [, line_buffering]]]])
buffered - A buffered file object
encoding - Text encoding (e.g., 'utf-8')
errors - Error handling policy (e.g. 'strict')
newline - '', 'n', 'r', 'rn', or None
line_buffering - Flush output after each line (False)
jest jedną z warstw buforowanych strumieni I/O
f = io.FileIO("foo.txt") # Open the file (raw I/O)
g = io.BufferedReader(f) # Put buffering around it
h = io.TextIOWrapper(g,"utf-8") # Text I/O wrapper
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 65 / 91
111. . . . . . .
Text
obsługa znaku nowej linii
Domyślnie pliki są otwierane w trybie ”‘universal newline”’ - znaki
nowej linii są mapowane do znaku n
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 66 / 91
112. . . . . . .
Text
obsługa znaku nowej linii
Domyślnie pliki są otwierane w trybie ”‘universal newline”’ - znaki
nowej linii są mapowane do znaku n
aby pozostawić oryginalny znak nowej linii, należy użyć funkcji open z
dodatkowym argumentem newline=''
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 66 / 91
113. . . . . . .
Text
obsługa znaku nowej linii
Domyślnie pliki są otwierane w trybie ”‘universal newline”’ - znaki
nowej linii są mapowane do znaku n
aby pozostawić oryginalny znak nowej linii, należy użyć funkcji open z
dodatkowym argumentem newline=''
jeśli nie wymusimy formatu znaku nowej linii (poprzez użycie
argumentu newline w funkcji open), wtedy podczas zapisu używany
jest os.linesep jako znak nowej linii.
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 66 / 91
114. . . . . . .
Text
obsługa kodowań
w Python2 aby automatycznie zdekodować zawartość pliku podczas
czytania używany jest moduł codecs
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 67 / 91
115. . . . . . .
Text
obsługa kodowań
w Python2 aby automatycznie zdekodować zawartość pliku podczas
czytania używany jest moduł codecs
w Python3 nie ma potrzeby używania codecs.
W pełni zastępuje go TextIOWrapper
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 67 / 91
116. . . . . . .
Text
obsługa kodowań
w Python2 aby automatycznie zdekodować zawartość pliku podczas
czytania używany jest moduł codecs
w Python3 nie ma potrzeby używania codecs.
W pełni zastępuje go TextIOWrapper
TextIOWrapper jest znacznie szybszy niż codecs
for line in open("biglog.txt",encoding="utf-8"): # 3.8 sec
pass
f = codecs.open("biglog.txt",encoding="utf-8")
for line in f: # 53.3 sec
pass
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 67 / 91
117. . . . . . .
open()
Porównanie
typ obiektu zwracanego przez funkcję open zależy od parametrów.
mode buffering Result
any binary 0 FileIO
”rb” != 0 BufferedReader
”wb”, ”ab” != 0 BufferedWriter
”rb”, ”wb+”, ”ab+” != 0 BufferedRandom
any text != 0 TextIOWrapper
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 68 / 91
118. . . . . . .
open()
Porównanie
typ obiektu zwracanego przez funkcję open zależy od parametrów.
mode buffering Result
any binary 0 FileIO
”rb” != 0 BufferedReader
”wb”, ”ab” != 0 BufferedWriter
”rb”, ”wb+”, ”ab+” != 0 BufferedRandom
any text != 0 TextIOWrapper
Uwaga: niektóre kombinacje są nielegalne, a ich użycie spowoduje
rzucenie wyjątku (np: unbuffered text)
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 68 / 91
119. . . . . . .
I/O Stack
przechodzenie po stosie I/O
Scenariusz: mamy plik otwarty w text-mode, ale chcemy go czytać w
binary-mode.
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 69 / 91
120. . . . . . .
I/O Stack
przechodzenie po stosie I/O
Scenariusz: mamy plik otwarty w text-mode, ale chcemy go czytać w
binary-mode.
warstwy wyższe zawierają warstwy niższe. Czyli do bardziej natywnych
obiektów i/o możemy się dostać przez pola obiektów wyższych:
?
?
TextIOWrapper
BufferedReader
FileIO
.buffer
.raw
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 69 / 91
121. . . . . . .
I/O Stack
przechodzenie po stosie I/O - przykład
Pisanie danych binarnych do sys.stdout.
Pomysły?
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 70 / 91
122. . . . . . .
I/O Stack
przechodzenie po stosie I/O - przykład
Pisanie danych binarnych do sys.stdout.
Pomysły?
>>> import sys
>>> sys.stdout.write(b"Hello␣Worldn")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: must be str, not bytes
>>> sys.stdout.buffer.write(b"Hello␣Worldn")
Hello World
12
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 70 / 91
123. . . . . . .
I/O Stack
UWAGA - warstwy!
Przechodzenie po warstwach może powodować błędy gdy pracujemy z
objektami typu pliki.
>>> import io
>>> from urllib.request import urlopen
>>> u = io.TextIOWrapper(
urlopen("http://www.python.org"),
encoding='latin1')
>>> text = u.read()
>>> u = io.TextIOWrapper(
urlopen("http://www.python.org"),
encoding='latin1')
>>> line = u.readline()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'HTTPResponse' object has no
attribute 'read1'
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 71 / 91
126. . . . . . .
I/O Performance
zapis
zapis 100 Mb tekstu do pliku open("foo.txt","wt").write(text)
Python 2.7.1 : 1.73s
Python 3.2 (UTF-8) : 1.85s
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 73 / 91
127. . . . . . .
I/O Performance
zapis
zapis 100 Mb tekstu do pliku open("foo.txt","wt").write(text)
Python 2.7.1 : 1.73s
Python 3.2 (UTF-8) : 1.85s
zapis 100 Mb danych binarnych
data = open("big.bin","wb").write(data)
Python 2.7.1 : 1.79s
Python 3.2 (binary) : 1.80s
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 73 / 91
128. . . . . . .
I/O Performance
iteracja
zapis 100 Mb tekstu do pliku
for line in open("biglog.txt"): pass
Python 2.7.1 : 0.25s
Python 3.2 (UCS-2, UTF-8) : 0.57s
Python 3.2 (UCS-4, UTF-8) : 0.82s
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 74 / 91
129. . . . . . .
I/O Performance
iteracja
zapis 100 Mb tekstu do pliku
for line in open("biglog.txt"): pass
Python 2.7.1 : 0.25s
Python 3.2 (UCS-2, UTF-8) : 0.57s
Python 3.2 (UCS-4, UTF-8) : 0.82s
zapis 100 Mb danych binarnych
for line in open("biglog.txt","rb"): pass
Python 2.7.1 : 0.25s
Python 3.2 (binary) : 0.29s
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 74 / 91
130. . . . . . .
I/O - komentarze
odczyt zapis tak czy siak sprowadza się do zapisu bajtów
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 75 / 91
131. . . . . . .
I/O - komentarze
odczyt zapis tak czy siak sprowadza się do zapisu bajtów
aby odczytać tekst, każdy znak musi zostać skopiowany do ”‘intów”’
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 75 / 91
132. . . . . . .
I/O - komentarze
odczyt zapis tak czy siak sprowadza się do zapisu bajtów
aby odczytać tekst, każdy znak musi zostać skopiowany do ”‘intów”’
aby uniknąć tych kopiowań należy nie korzystać z trybu tekstowego
(nie konwertować bytes do unicode).
Jednak nie zawsze oznacza to praktycznie rozwiązanie.
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 75 / 91
133. . . . . . .
I/O - komentarze
odczyt zapis tak czy siak sprowadza się do zapisu bajtów
aby odczytać tekst, każdy znak musi zostać skopiowany do ”‘intów”’
aby uniknąć tych kopiowań należy nie korzystać z trybu tekstowego
(nie konwertować bytes do unicode).
Jednak nie zawsze oznacza to praktycznie rozwiązanie.
TEKST ZAWSZE POWINIEN BYĆ PRZETWARZANY ZA
POMOCĄ UNICODE
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 75 / 91
134. . . . . . .
I/O, optymalizacja pracy z unicode
Jeśli mamy do czynienia z olbrzymią ilością TEKSTU jednobajtowego
(ASCII, Latin-x, ...), a mammy małą ilość dostępnej pamięci można użyć
paru optymalizacji
Odłożyć konwersje do Unicode jak najpóźniej się da
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 76 / 91
135. . . . . . .
I/O, optymalizacja pracy z unicode
Jeśli mamy do czynienia z olbrzymią ilością TEKSTU jednobajtowego
(ASCII, Latin-x, ...), a mammy małą ilość dostępnej pamięci można użyć
paru optymalizacji
Odłożyć konwersje do Unicode jak najpóźniej się da
parsowanie tekstu jednobajtowego można dokonać na poziomie bytes.
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 76 / 91
136. . . . . . .
I/O, optymalizacja pracy z unicode
Jeśli mamy do czynienia z olbrzymią ilością TEKSTU jednobajtowego
(ASCII, Latin-x, ...), a mammy małą ilość dostępnej pamięci można użyć
paru optymalizacji
Odłożyć konwersje do Unicode jak najpóźniej się da
parsowanie tekstu jednobajtowego można dokonać na poziomie bytes.
Przykład: parsowanie logów
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 76 / 91
137. . . . . . .
I/O, optymalizacja pracy z unicode
Przykład
Znaleźć wszystkie URL, które spowodowały status 404 w logach Apache.
Pomysły?
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 77 / 91
138. . . . . . .
I/O, optymalizacja pracy z unicode
Przykład
Znaleźć wszystkie URL, które spowodowały status 404 w logach Apache.
Pomysły?
error_404_urls = set()
for line in open("biglog.txt","rb"):
fields = line.split()
if fields[-2] == b'404':
error_404_urls.add(fields[-4])
error_404_urls = {n.decode('latin-1')
for n in error_404_urls }
for name in error_404_urls:
print(name)
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 77 / 91
140. . . . . . .
operacje systemowe
Do obsługi operacji systemowych Python wykorzystuje zapytania
systemowe z biblioteki C
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 79 / 91
141. . . . . . .
operacje systemowe
Do obsługi operacji systemowych Python wykorzystuje zapytania
systemowe z biblioteki C
Przykład wywołania zapytania systemowe w POSIX na Unixie:
int fd = open(filename, O_RDONLY);
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 79 / 91
142. . . . . . .
operacje systemowe
Do obsługi operacji systemowych Python wykorzystuje zapytania
systemowe z biblioteki C
Przykład wywołania zapytania systemowe w POSIX na Unixie:
int fd = open(filename, O_RDONLY);
atrybuty są przekazywane do zapytań systemowych (nazwy plików,
programów, …) jako ciągi znaków (w C - char*, Python - bytes)
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 79 / 91
143. . . . . . .
operacje systemowe
Do obsługi operacji systemowych Python wykorzystuje zapytania
systemowe z biblioteki C
Przykład wywołania zapytania systemowe w POSIX na Unixie:
int fd = open(filename, O_RDONLY);
atrybuty są przekazywane do zapytań systemowych (nazwy plików,
programów, …) jako ciągi znaków (w C - char*, Python - bytes)
Bytes są używane w zmiennych środowiskowych, argumentach
wywołania (command line arguments)
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 79 / 91
144. . . . . . .
operacje systemowe
Do obsługi operacji systemowych Python wykorzystuje zapytania
systemowe z biblioteki C
Przykład wywołania zapytania systemowe w POSIX na Unixie:
int fd = open(filename, O_RDONLY);
atrybuty są przekazywane do zapytań systemowych (nazwy plików,
programów, …) jako ciągi znaków (w C - char*, Python - bytes)
Bytes są używane w zmiennych środowiskowych, argumentach
wywołania (command line arguments)
Jak Python integruje swoje stringi (Unicode) z byte-oriented
interfejsem systemowym?
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 79 / 91
146. . . . . . .
operacje systemowe
kodowanie argumentów
Standardowo python3 koduje wszystkie parametry ”‘tekstowe”’ w
UTF-8
ogólnie jest to bezpieczne założenie.
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 80 / 91
147. . . . . . .
operacje systemowe
kodowanie argumentów
Standardowo python3 koduje wszystkie parametry ”‘tekstowe”’ w
UTF-8
ogólnie jest to bezpieczne założenie.
podobnie z argumentami wywołania i zmiennymi środowiskowymi -
Python3 dekoduje je za pomocą UTF-8.
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 80 / 91
148. . . . . . .
operacje systemowe
kodowanie argumentów
Standardowo python3 koduje wszystkie parametry ”‘tekstowe”’ w
UTF-8
ogólnie jest to bezpieczne założenie.
podobnie z argumentami wywołania i zmiennymi środowiskowymi -
Python3 dekoduje je za pomocą UTF-8.
Jest to dość subtelne zachowanie - gdyż zakłada że wszystkie opcje
parametry systemowe są kodowane w UTF-8
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 80 / 91
149. . . . . . .
operacje systemowe
kodowanie argumentów
Standardowo python3 koduje wszystkie parametry ”‘tekstowe”’ w
UTF-8
ogólnie jest to bezpieczne założenie.
podobnie z argumentami wywołania i zmiennymi środowiskowymi -
Python3 dekoduje je za pomocą UTF-8.
Jest to dość subtelne zachowanie - gdyż zakłada że wszystkie opcje
parametry systemowe są kodowane w UTF-8
ale niekoniecznie tak musi być
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 80 / 91
150. . . . . . .
operacje systemowe - kodowanie nazw
Przykład - błąd w nazwie pliku
Za pomocą Python2 stworzymy plik w systemie Linux, którego nazwa
będzie zawierać jeden znak spoza ASCII:
>>> f = open("jalapexf1o.txt","w")
>>> f.write("Bwahahahaha!n")
>>> f.close()
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 81 / 91
151. . . . . . .
operacje systemowe - kodowanie nazw
Przykład - błąd w nazwie pliku
Za pomocą Python2 stworzymy plik w systemie Linux, którego nazwa
będzie zawierać jeden znak spoza ASCII:
>>> f = open("jalapexf1o.txt","w")
>>> f.write("Bwahahahaha!n")
>>> f.close()
Python3 nie będzie w stanie otworzyć tego pliku.
>>> f = open("jalapexf1o.txt")
Traceback (most recent call last):
...
IOError: [Errno 2] No such file or directory: 'jalapeño.txt'
Powód: nazwa pliku po zakodowaniu w UTF-8 nie odpowiada nazwie
pliku w systemie:
”jalapexf1o.txt” → UTF-8 coder → b”jalapec3xb1o.txt”
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 81 / 91
152. . . . . . .
operacje systemowe - kodowanie nazw
Przykład - błąd w nazwie pliku
Za pomocą Python2 stworzymy plik w systemie Linux, którego nazwa
będzie zawierać jeden znak spoza ASCII:
>>> f = open("jalapexf1o.txt","w")
>>> f.write("Bwahahahaha!n")
>>> f.close()
Python3 nie będzie w stanie otworzyć tego pliku.
>>> f = open("jalapexf1o.txt")
Traceback (most recent call last):
...
IOError: [Errno 2] No such file or directory: 'jalapeño.txt'
Powód: nazwa pliku po zakodowaniu w UTF-8 nie odpowiada nazwie
pliku w systemie:
”jalapexf1o.txt” → UTF-8 coder → b”jalapec3xb1o.txt”
Co się stanie gdy w directory listing będzie nazwa pliku nie
UTF-8?
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 81 / 91
153. . . . . . .
operacje systemowe - kodowanie nazw
argumenty jako Bytes
Można użyć bytes zamiast unicode jako argumenty do wywołań
systemowych.
>>> f = open(b"jalapexf1o.txt")
>>> files = glob.glob(b"*.txt")
>>> files
[b'jalapexf1o.txt', b'spam.txt']
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 82 / 91
154. . . . . . .
operacje systemowe - kodowanie nazw
argumenty jako Bytes
Można użyć bytes zamiast unicode jako argumenty do wywołań
systemowych.
>>> f = open(b"jalapexf1o.txt")
>>> files = glob.glob(b"*.txt")
>>> files
[b'jalapexf1o.txt', b'spam.txt']
Jeśli użyjemy bytes do wywołania systemowego, wtedy ciąg ten nie
będzie w ogóle kodowany, oraz zwracane wyniki będą podawane jako
bytes.
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 82 / 91
155. . . . . . .
Surrogate Encoding
W Pythonie3.1 każdy nie dekodowalny (nie ASCII) znak w nazwie
pliku lub parametrze interfejsu systemowego jest tłumaczony przez
Surrogate Encoding
Jest to specyficzny dla Pythona trik, który zapobiega błędom podczas
wywołań systemowych przy obsłudze argumentów które nie są
poprawnymi ciągami UTF-8.
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 83 / 91
156. . . . . . .
Surrogate Encoding
definicja
Każdy bajt ∈ [0x80; 0xff] zamieniany jest na znak unicode
∈ [U + DC80; U + DCFF]
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 84 / 91
157. . . . . . .
Surrogate Encoding
definicja
Każdy bajt ∈ [0x80; 0xff] zamieniany jest na znak unicode
∈ [U + DC80; U + DCFF]
Przykład:
”jalapexf1o.txt” → b”jalapeudcf1o.txt”
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 84 / 91
158. . . . . . .
Surrogate Encoding
definicja
Każdy bajt ∈ [0x80; 0xff] zamieniany jest na znak unicode
∈ [U + DC80; U + DCFF]
Przykład:
”jalapexf1o.txt” → b”jalapeudcf1o.txt”
Podobnie znaki unicode ∈ [U + DC80; U + DCFF] są zamieniane na
bajty ∈ [0x80; 0xff] kiedy występuję w argumentach funkcji interfejsu
systemowego
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 84 / 91
159. . . . . . .
Surrogate Encoding
Przykład
Jeśli w wywołaniu systemowy widać znak rodzaju udcxx znaczy to że
znak nie ASCII został przesłany do interfejsu systemowego
>>> glob.glob("*.txt")
[ 'jalapeudcf1o.txt', 'spam.txt']
>>> f = open("jalapeudcf1o.txt")
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 85 / 91
160. . . . . . .
Surrogate Encoding
integracja z Unicode
Czy Surrogate Encoding jest kompatybilne z Unicode?
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 86 / 91
161. . . . . . .
Surrogate Encoding
integracja z Unicode
Czy Surrogate Encoding jest kompatybilne z Unicode?
Nie do końca
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 86 / 91
162. . . . . . .
Surrogate Encoding
integracja z Unicode
Czy Surrogate Encoding jest kompatybilne z Unicode?
Nie do końca
Poprawny unicode nie zawiera znaków ∈ [U + DC80; U + DCFF]
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 86 / 91
163. . . . . . .
Surrogate Encoding
integracja z Unicode
Czy Surrogate Encoding jest kompatybilne z Unicode?
Nie do końca
Poprawny unicode nie zawiera znaków ∈ [U + DC80; U + DCFF]
na przykład używanie napisów z surrogate encoding powoduje wyjątki
w funkcji print()
>>> files = glob.glob("*.txt")
>>> files
[ 'jalapeudcf1o.txt', 'spam.txt']
>>> for name in files:
print(name)
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'utf-8' codec can't␣encode␣character
'udcf1'␣in␣position␣6:␣surrogates␣not␣allowed
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 86 / 91
164. . . . . . .
Surrogate Encoding
Implementacja
Surrogate encoding zaimplementowane jest jako error handler dla
metod encode(), decode() - patrz help(encode)
>>> s = b"jalapexf1o.txt"
>>> t = s.decode('utf-8','surrogateescape')
>>> t
'jalapeudcf1o.txt'
>>> t.encode('utf-8','surrogateescape')
b'jalapexf1o.txt'
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 87 / 91
165. . . . . . .
Surrogate Encoding
Implementacja
Surrogate encoding zaimplementowane jest jako error handler dla
metod encode(), decode() - patrz help(encode)
>>> s = b"jalapexf1o.txt"
>>> t = s.decode('utf-8','surrogateescape')
>>> t
'jalapeudcf1o.txt'
>>> t.encode('utf-8','surrogateescape')
b'jalapexf1o.txt'
Jeśli rozważamy pisanie kodu, który ma do czynienia z interfejsem
systemowy, i chcemy żeby kod był przenośny, wtedy będziemy
potrzebować powyższych rozwiązań.
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 87 / 91
167. . . . . . .
Unicode i Bytes a biblioteki
W Pyhon2 mogliśmy pomijać różnice między tekstem a ciągiem
bajtów. Wiele bibliotek pomijało tą sprawę (moduły sieciowe, moduły
przetwarzania danych …)
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 89 / 91
168. . . . . . .
Unicode i Bytes a biblioteki
W Pyhon2 mogliśmy pomijać różnice między tekstem a ciągiem
bajtów. Wiele bibliotek pomijało tą sprawę (moduły sieciowe, moduły
przetwarzania danych …)
Python3 traktuje tą sprawę poważnie i musimy być precyzyjni w
obsłudze I/O
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 89 / 91
169. . . . . . .
Unicode i Bytes a biblioteki
Przykład
Niepoprawna funkcja:
def send_response(s,code,msg):
s.sendall("HTTP/1.0␣%s␣%srn" % (code,msg))
send_response(s,"200","OK")
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 90 / 91
170. . . . . . .
Unicode i Bytes a biblioteki
Przykład
Niepoprawna funkcja:
def send_response(s,code,msg):
s.sendall("HTTP/1.0␣%s␣%srn" % (code,msg))
send_response(s,"200","OK")
Funkcja jest niepoprawna ponieważ socket operuje tylko na danych
binarnych (bytes, bytearray).
Czyli nie możemy wysyłać tekstu (np: ”‘Hello!”’)
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 90 / 91
171. . . . . . .
Unicode i Bytes a biblioteki
Przykład
W Python3 trzeba podać dokładnie kodowanie tekstu:
def send_response(s,code,msg):
resp = "HTTP/1.0␣%s␣%srn" % (code,msg)
s.sendall(resp.encode('ascii'))
send_response(s,"200","OK")
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 91 / 91
172. . . . . . .
Unicode i Bytes a biblioteki
Przykład
W Python3 trzeba podać dokładnie kodowanie tekstu:
def send_response(s,code,msg):
resp = "HTTP/1.0␣%s␣%srn" % (code,msg)
s.sendall(resp.encode('ascii'))
send_response(s,"200","OK")
Zasady wysyłania danych:
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 91 / 91
173. . . . . . .
Unicode i Bytes a biblioteki
Przykład
W Python3 trzeba podać dokładnie kodowanie tekstu:
def send_response(s,code,msg):
resp = "HTTP/1.0␣%s␣%srn" % (code,msg)
s.sendall(resp.encode('ascii'))
send_response(s,"200","OK")
Zasady wysyłania danych:
Każdy tekst wysyłany musi być najpierw kodowany do bytes
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 91 / 91
174. . . . . . .
Unicode i Bytes a biblioteki
Przykład
W Python3 trzeba podać dokładnie kodowanie tekstu:
def send_response(s,code,msg):
resp = "HTTP/1.0␣%s␣%srn" % (code,msg)
s.sendall(resp.encode('ascii'))
send_response(s,"200","OK")
Zasady wysyłania danych:
Każdy tekst wysyłany musi być najpierw kodowany do bytes
Każdy tekst odbierany musi być najpierw dekodowany do unicode (jeśli
chcemy nim operować jako tekst)
Robert Zaremba (Scale it) Python Zaawansowane IO Wrocław 2011 listopad 10 91 / 91