Minus nivo, 1.1-1.21 + str.180-182

Andrija Maric

ПОГЛАВЉЕ 1. ШТА ЈЕ НОВО У  “DIVE INTO PYTHON 3”

"Зар нисмо овде ушли?" — Pink Floyd, The Wall

-1.1. ЗВАНИ „МИНУС НИВО“

Да ли сте већ Pithon програмер? Јесте ли прочитали оригинални "Dive Into Pithon"?

Јесте ли га купили на папиру? (Ако је тако, хвала!)

Да ли сте спремни да се упустите у Pithon 3? … Ако је тако, прочитајте даље.

(Ако ништа од тога није тачно, било би вам боље да почнете од почетка.)

Python 3 долази са скриптом који се зове 2-to-3. Научи то. Нека ти се свиди. Искористи то.

Преношење кода на Питхон 3 са 2-to-3 референца је свих ствари које алатка 2-to-3 може аутоматски да поправи.

Будући да су многе од ових ствари синтакса промене,

добро је полазно место да сазнате о многим променама синтаксе на Pithon-у 3.

(штампање је сада функција, `x` не ради и & c.)

Студија случаја: Преношење chardet-а на Pithon 3 документује мој (веома успешан)

напор да преносим не-тривијалну библиотеку са Pithon 2 на Pithon 3.

Може вам помоћи; можда и неће. Постоји прилично стрма крива учења,

јер прво морате разумети библиотеку, тако да можете разумети зашто се покварила и како сам је поправио.

Много ломова се центрира око жица. Кад смо код тога...

Жице. Увау. Где почети. Pithon 2 је имао "жице" и "низове “Unicode-а".

Pithon 3 има "бајтове" и "жице". То јест, све жице су сада низови Unicode,

и ако желите да се бавите врећом бајтова, користићете нове типове бајтова.

Pithon 3 никада неће имплицитно претварати између стрингова и бајтова,

тако да ако нисте сигурни који имате у датом тренутку, ваш се код ће готово сигурно да се поквари.

Прочитајте поглавље жице за више детаља.

Бајтови наспрам жице појављују се изнова и изнова у цијелој књизи.

• У Датотекама ћете научити разлику између читања датотека у режиму „бинарни“ и „текст“.

Читање (и писање!) Датотека у текстуалном режиму захтева параметар за кодирање.

Неке методе текстуалних датотека броје знакове,

али друге методе броје бајтове. Ако ваш код претпоставља да је један знак == један бајт,

пробиће се на вишебајтне знакове.

У HTTP веб услугама, httplib2 модул узима заглавља и податке преко HTTP-а.

HTTP заглавља се враћају као низови, али HTTP тело враћа се у бајтове.

У сериализацији Pithon објеката научићете зашто модул pickle у Pithon-у 3

дефинише нови формат података који је назадно неспојив са Pithon-ом 2.

(Савет: то је због бајтова и низова.)

Такође, Pithon 3 подржава сериализацију објеката на и из JSON,

који чак нема ни бајтни тип. Показаћу вам како да то решите.

У студији случаја: преношење chardet-а на Pithon 3, то је само крвави неред бајтова и низова свуда.

Чак и ако вам није стало до Unicode-а (ох, али хоће),

мораћете прочитати о форматирању стрингова у Pithon-у 3,

који се у потпуности разликује од Pithon-а 2.

Итератори су свуда на Pithon-у 3 и разумем их пуно боље него пре пет година када сам написао „Зароните у Pithon"

Морате их и разумети, јер ће мноштво функција које су враћале листе у Pithon 2 сада враћати итераторе у Pithon 3.

У најмању руку, требало би да прочитате другу половину поглавља

Итератори и другу половину поглавља Сложени Итератори. .

На популарни захтев, додао сам додатак именима специјалних метода,

који је налик на поглавље „Подаци модела“ Pithon докумената, али са више пукотина.

Кад сам писао „Dive Into Python“, све расположиве XML библиотеке су биле безвезе.

Тада је Фредрик Лундх написао ElementTree, који уопште није лош.

Python богови су мудро уградили ElementTree у стандардну библиотеку и сада представља

основу за моје ново XML поглавље. Стари начини рашчлањивања XML-а још увек постоје,

али треба их избегавати, јер они не ваљају!

Такође новост у Python-у - не на језику, већ у заједници - је појава спремишта кода

попут Python Package Index (PyPI).

Python долази са услужним програмима за паковање вашег кода у стандардним

форматима и дистрибуцију тих пакета на PyPI.

Прочитајте детаље о Паковању библиотека Python.

ПОГЛАВЉЕ 1. ТВОЈ ПРВИ PYTHON ПРОГРАМ

"Не сахраните свој терет у светој тишини. Имате проблем? Сјајно. Радујте се, зароните и истражите."— Ven. Henepola Gunaratana

1.1 ЗАРАЊАЊЕ

Конвенција заповеда да бих требао да вас досађујем са основним елементима програмирања,

тако да полако можемо радити на стварању нечег корисног.

Прескочимо све то. Ево комплетног, делујућег Python програма.

То вам вероватно нема апсолутно никаквог смисла. Не брините због тога,

јер ћете је сецирати линију по ред. Али прво прочитате то и видећете шта,

ако нешто можете направити од тога.

SUFFIXES = {1000: ['KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'],

1024: ['KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB']}

def approximate\_size(size, a\_kilobyte\_is\_1024\_bytes=True):

**Convert a file size to human-readable form.**

Keyword arguments:

size -- file size in bytes

a\_kilobyte\_is\_1024\_bytes -- if True (default), use multiples of 1024

if False, use multiples of 1000

Returns: string

if size < 0:

raise ValueError('number must be non-negative')

multiple = 1024 if a\_kilobyte\_is\_1024\_bytes else 1000

for suffix in SUFFIXES[multiple]:

size /= multiple

if size < multiple:

return '{0:.1f} {1}'.format(size, suffix)

raise ValueError('number too large')

if \_\_name\_\_ == '\_\_main\_\_':

print(approximate\_size(1000000000000, False))

print(approximate\_size(1000000000000))

Now let’s run this program on the command line. On Windows, it will look something like this:

c:\home\diveintopython3\examples> c:\python31\python.exe humansize.py

1.0 TB

931.3 GiB

На Mac OS X или Linux-у изгледало би овако:

you@localhost:~/diveintopython3/examples$ python3 humansize.py

1.0 TB

931.3 GiB

Шта се управо догодило? Покренули сте свој први програм Python.

Позвали сте тумача Python-а из командне линије и пренели сте име скрипте коју сте желели да изврши.

Скрипта дефинише једну функцију, функцију approximate\_size(),

која узима тачну величину датотеке у бајтовима и израчунава „лепу“ (али приближну) величину.

(То сте вероватно видели у Windows Explorer-у, или у Mac OS X претраживачу, или Наутилусу,

Dolphin-у или Thunar-у на Linux-у. Ако прикажете фасциклу докумената као листу са више колона,

приказаће се табела са иконом документа , име документа, величина, врста, датум последње измене итд.

Ако мапа садржи датотеку од 1093 бајта под називом TODO, ваш управитељ датотека неће приказати TODO 1093 бајта;

рећи ће нешто попут TODO 1 КБ уместо тога. То ради функција approximate\_size ().)

Погледајте доњи део скрипте и видећете два позива за штампање (approximate\_size(arguments)).

То су позиви функција - прво позивање функције approximate\_size() и прослеђивање низа аргумената,

затим узимање повратне вредности и прослеђивање равно на функцију print().

Функција print() је уграђена; никада нећете видети експлицитну изјаву о томе.

Можете га користити било када и било где.

(Постоји пуно уграђених функција и пуно више функција које су раздељене на модуле. Стрпљење.)

Па зашто вам покретање скрипте у командној линији даје исти излаз сваки пут? Доћи ћемо до тога.

Прво, погледајмо ону функцију approximate\_size().

1.2. ДОДЕЉИВАЊЕ ФУНКЦИЈА

Python има функције као и већина других језика, али нема засебне датотеке

заглавља попут C ++ или секције интерфејса / имплементације као што је Pascal.

Када вам је потребна функција, само је изјавите овако:

def approximate\_size(size, a\_kilobyte\_is\_1024\_bytes=True):

Кључна реч daf покреће декларацију функције, а затим име функције,

а затим аргументе у заградама. Више аргумената је одвојено зарезима.

Такође имајте на уму да функција не дефинише повратни тип података.

Python функције не одређују тип података њихове повратне вредности;

чак не одређују да ли враћају вредност или не.

(У ствари, свака функција Python-а враћа вредност; ако функција икада изврши изјаву о враћању,

вратиће ту вредност, у супротном ће вратити None, Python-обу нулту вредност.

У неким језицима, функције (које враћају вредност) почињу function,

а подпрограми (који не враћају вредност) почињу са sub.

У Python-у нема подпрограма. Све је функција,

све функције враћају вредност (чак и ако је нула), а све функције почињу са def.

Функција approximate\_size() узима два аргумента - size и

a\_kilobyte\_is\_1024\_bytes - али ниједан аргумент не одређује врсту података.

У Python-у се променљиве никада експлицитно не куцају.

Python открива која је врста променљиве и интерно је прати.

У Јави и другим статички типканим језицима морате навести врсту података

повратне вредности функције и сваки аргумент функције.

У Python-у никада не одредите изричито врсту података било чега.

На основу вредности коју доделите, Python интерно прати врсту података.

1.2.1. ОПЦИОНИ И ИМЕНИ АРГУМЕНТИ

Python омогућава аргументима функција да имају задате вредности;

ако се функција позива без аргумента, аргумент добија своју задату вредност.

Надаље, аргументи се могу специфицирати било којим редослиједом кориштењем именованих аргумената.

Погледајмо још једну декларацију функције approximate\_size() :

def approximate\_size(size, a\_kilobyte\_is\_1024\_bytes=True):

Други аргумент,  a\_kilobyte\_is\_1024\_bytes, одређује уобичајну вредност True.

То значи да је аргумент необавезан; можете позвати функцију без њега,

а Python ће се понашати као да сте је позвали са Тrue као другим параметром.

print(approximate\_size(1000000000000, False)) ①

print(approximate\_size(1000000000000)) ②

1. Ово позива функцију approximate\_size() са два аргумента.

Унутар функције approximate\_size(), a\_kilobyte\_is\_1024\_bytes ће бити False,

јер сте изричито пренели False као други аргумент.

2. Ово позива функцију approximate\_size() са само једним аргументом.

Али то је у реду, јер други аргумент је опционалан!

Будући да позивалац не одређује, други аргумент се поставља на True,

што је дефинисано декларацијом функције.

Такође можете да пренесете вредности у функцију по имену.

>>> from humansize import approximate\_size

>>> approximate\_size(4000, a\_kilobyte\_is\_1024\_bytes=False) ① '4.0 KB'

>>> approximate\_size(size=4000, a\_kilobyte\_is\_1024\_bytes=False) ② '4.0 KB'

>>> approximate\_size(a\_kilobyte\_is\_1024\_bytes=False, size=4000) ③ '4.0 KB'

>>> approximate\_size(a\_kilobyte\_is\_1024\_bytes=False, 4000) ④ File "<stdin>", line 1

SyntaxError: non-keyword arg after keyword arg

>>> approximate\_size(size=4000, False) ⑤ File "<stdin>", line 1

SyntaxError: non-keyword arg after keyword arg

1. Овим се позива функција approximate\_size() са 4000 за први аргумент (величина) и False

за аргумент под називом a\_kilobyte\_is\_1024\_bytes. (То се дешава као други аргумент, али није важно,

као што ћете видети за минуту.)

2. Ово позива функцију approximate\_size() са 4000 за аргумент величине и False

за аргумент назван a\_kilobyte\_is\_1024\_bytes.

(Чини се да су наведени именовани аргументи истим редоследом као и аргументи наведени у декларацији функција,

али ни то није важно.)

3. Ово позива функцију approximate\_size() са False за аргумент под називом a\_kilobyte\_is\_1024\_bytes и 4000

за аргумент именовану величину. (Видите? Рекао сам вам да наруџба није битна.)

4. Овај позив није успео, јер имате аргумент са именом,

а иза њега следи неименовани (позиционирани) аргумент и то никада не ради.

Читајући листе аргумената са леве на десно, када имате један именовани аргумент,

морају се именовати и остали аргументи.

5. Овај позив такође није успео, из истог разлога као и претходни. Да ли је то изненађујуће?

На крају, прешли сте 4000 за аргумент именован size,

а затим "очигледно" да је False вредност била смишљена за аргумент a\_kilobyte\_is\_1024\_bytes.

Али Python не функционише на тај начин. Чим имате именовани аргумент,

сви аргументи почевши од њега морају бити именовани аргументима такође.

Stranca 180-183

Узмимо класу бит по бит .

Класа LazyRules:

rules\_filename = 'plural6-rules.txt'

def \_\_init\_\_(self):

self.pattern\_file = open(self.rules\_filename, encoding='utf-8') ①

self.cache = [] ②

Кад инстанцирамо класу LazyRules, отворите датотеку са узорцима, али из ње ништа не читамо. (То долази касније.)

2. Након отварања датотеке обрасца, иницирате кеш меморију. Касније ћете користити ову кеш меморију (у методи  \_\_next\_\_()) када читате редове из датотеке обрасца.

Пре него што наставимо, погледајмо поближе назив rules\_filename. Није дефинисано унутар \_\_iter\_\_() методи.

У ствари, није дефинисано ни у једној методи. Дефинисано је на нивоу класе. То је варијабла класе и иако му можете приступити баш као и променљива инстанце (self.rules\_filename), она се дели на све примерке класе ЛазиРулес.

>>> import plural6

>>> r1 = plural6.LazyRules()

>>> r2 = plural6.LazyRules()

>>> r1.rules\_filename ①

'plural6-rules.txt'

>>> r2.rules\_filename

'plural6-rules.txt'

>>> r2.rules\_filename = 'r2-override.txt' ②

>>> r2.rules\_filename

'r2-override.txt'

>>> r1.rules\_filename

'plural6-rules.txt'

>>> r2.\_\_class\_\_.rules\_filename ③

'plural6-rules.txt'

>>> r2.\_\_class\_\_.rules\_filename = 'papayawhip.txt' ④

>>> r1.rules\_filename

'papayawhip.txt'

>>> r2.rules\_filename ⑤

'r2-overridetxt'

1. Свака инстанца класе насљеђује атрибут rules\_filename са вриједношћу коју дефиниса класа.

2. Промена вредности атрибута у једној инстанци не утиче на друге инстанце…

3.… нити мења атрибут класе. Можете приступити атрибуту класе (за разлику од појединца

примерка атрибута) помоћу посебног атрибута \_\_class\_\_  за приступ самој класи.

4. Ако промените атрибут класе, утицаће на све инстанце које још увек наслеђују ту вредност (попут r1 овде).

5. На случајеве који су надјачали тај атрибут (попут r2 овде) неће утицати.

А сада се вратимо нашој емисији.

def \_\_iter\_\_(self): ①

self.cache\_index = 0

return self ②

1. Метода \_\_iter\_\_() позиваће се сваки пут када неко - рецимо, за петљу - позове iter(rules).