![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
Entice (
>>> tup = "a", 52, 3.8, [2, 8]
Zápis na pravé straně vyhodnotí interpret jako entici (tuple) a jako takovou ji vrátí v závorkách:
>>> tup ('a', 52, 3.8, [2, 8])
Formát entice má i výraz s jedinou položkou se závěrečnou čárkou:
>>> t1 = 'a', >>> t1; type(t1) ('a',)# závorky si doplnil interpret <class 'tuple'>
Bez čárky by byl výraz
Odhlédneme-li od skladby, jsou operace s enticemi stejné jako operace se seznamy. Indexový operátor vybere položku z entice:
>>> tup = "a", 52, 3.8, [2, 8] >>> tuple[0] 'a'
Úsekový operátor vybere rozsah položek:
>>> tup[1:3] (52, 3.8, [2, 8])
Pokusíme-li se změnit některou z indexem vybraných položek, dostaneme chybové hlášení:
>>> tup[0] = 'A'TypeError: 'tup' object doesn't support item assignment
Neměnitelnost entice znamená, že ji nelze změnit beze změny identity (ID). Pokud nám nevadí změna ID, můžeme entici - jako přiřazenou hodnotu k proměnné, upravit pomocí součtu entic a úsekového operátoru:
>>> tuple = ('A',) + tup[1:] >>> tuple ('A', 52, 3.8, [2, 8]) >>> ruple = ('a', 'b', 'c', 'd', 'e'); id(ruple) 56396448 >>> ruple = ruple[:2] + ("X",) + ruple[3:] >>> ruple; id(ruple) ('a', 'b', 'X', 'd', 'e') 63672720
Entice je neměnitelná kolekce (neměnitelných) prvků. Pokud však entice obsahuje
# metoda copy nemění identitu ani u změněného objektu: >>> import copy >>> lt = ("a", [2.5, "b"])# vložený seznam >>> slt = copy.copy(lt)# závislá kopie >>> id(lt), id(slt)--> # (3027328, 3027328) >>> slt[1][1] = "joj"; slt ('a', [2.5, 'joj'])# změněná entice >>> id(lt), id(slt)--> # (3027328, 3027328) # metoda deep copy mění identitu i u změněného objektu: >>> lt = ("a", [2.5, "b"]) >>> dlt = copy.deepcopy(lt)# nezávislá kopie >>> id(lt), id(dlt)--> # (3027328, 3039104) >>> dlt[1][1] = "hoj"; dlt ('a', [2.5, 'hoj']) >>> id(lt), id(dlt)--> # (3027328, 3039104)
Při úpravě vloženého slovníku musíme zadávat nikoliv index, nýbrž klíč:
>>> import copy >>> dt = ("a", {2: "b"})# vložený slovník # id(dt) --> 54882600 >>> sdt = copy.copy(dt)# závislá kopie >>> sdt[1][2] = "číč"; dt, sdt (('a', {2: 'číč'}), ('a', {2: 'číč'}))# id(dt), id(sdt) --> (54882600 54882600) >>> dt = ("a", {2: "b"})# id(dt) --> 58810760 ) >>> ddt = copy.deepcopy(dt)# nezávislá kopie >>> ddt[1][2] = "rýč"; dt, ddt >>> (('a', {2: 'b'}), ('a', {2: 'rýč'}))# id(dt), id(ddt) --> (58810760 58810920)
Závislou kopclr-ii jak prosté, tak složené entice lze rovněž vytvořit úsekovým operátorem
>>> tup = ('a', 'b', 'c') >>> rup = tup[:]; rup ('a', 'b', 'c') >>> id(tup), id(rup) (46444232, 46444232) dt = ("a", {2: "b"}) >>> sdt = dt[:]; sdt ('a', {2: 'b'}) >>> id(dt), id(sdt) (46497384, 46497384)
Vestavěná metoda
Pojmenovaná entice (named tuple) je entice, opatřená jménem a názvy položek. Prvky entice jsou tedy kromě indexů přístupné také přes jejich slovní označení.
Práce s pojmenovanou enticí připomíná práci s deklarovanou třídou a jejími instancemi - viz Kap.12. Třídou je zde "matriční" entice, vytvořená pomocí importované
Název_typu =namedtuple ('Název_typu', 'výpis polí' [, rename=False] [, defaults=None] [, module=None])
Z takto obecně deklarované entice (třídy) vytvoříme jednotlivé entice (instance) s konkrétními hodnotami příslušných položek. Užitečnost pojmenované entice spočívá v tom, že si nemusíme pamatovat význam jednotlivých polí.
Práci s pojmenovanou enticí si nejlépe ukážeme na konkrétním příkladě, ve kterém si vytvoříme kartotéku se jmény zaměstnanců, jejich obory a platy (převzato ze stránky DaniWeb s laskavým svolením autora):
# ntEmpRec.py from collections import namedtuple # Vytvoření vzorové entice s určením polí (atributů): # název_NT = EmpRec = namedtuple('EmpRec', 'name, department, salary')namedtuple ('název_NT', 'názvy .. polí')# Vytvoření pojmenovaných entic: bob = EmpRec('Bob Zimmer', 'finance', salary = 77123) tim = EmpRec('Tim Bauer', 'shipping', 34231)# Jiný způsob s použitím seznamu a metody _make: fred_list = ['Fred Flint', 'purchasing', 42350] fred = EmpRec._make(fred_list)>>> fred # Jiný způsob s použitím slovníku a dvojhvězdičkového operátoru: fred_dict = {'name': 'Fred Flint', 'department': 'purchasing',
'salary': 42350} fred = EmpRec(**fred_dict)
# Vytvoření entice z existující entice metodou _replace: john = fred._replace(name='John Ward', salary=49200)# Vytvoření implicitní entice pro dělníky s hodinovou mzdou: default = EmpRec('addname', 'manufacturing', 26000)# a její aplikace pro tvorbu konkretních entic: mike = default._replace(name='Mike Holz') gary = default._replace(name='Gary Wood') carl = default._replace(name='Carl Boor')# Převedení entice na slovník metodou _asdict(): >>> print(bob._asdict()) # Výpis polí entice přes název entice či vzorové entice: >>> print(bob._fields) >>> print(EmpRec._fields)
==== RESTART: F:\Codetest\python\ntEmpRec.py ====Invokace >>> fred EmpRec(name='Fred Flint', department='purchasing', salary=42350) >>> print(bob._asdict()) {'name': 'Bob Zimmer', 'department': 'finance', 'salary': 77123} >>> print(bob._fields) ('name', 'department', 'salary') >>> print(EmpRec._fields) ('name', 'department', 'salary')>>> označených řádků:Přístup k polím přes jméno entice a atributu: >>> print(bob.name, bob.salary) Bob Zimmer 77123Přístup k polím přes jméno entice a index atributu: >>> print(tim[0], tim[2]) Tim Bauer 34231
Vytvoření seznamu pojmenovaných entic. Předchozí skript doplníme o následující kód a uložíme jako
# ntEmpRec.py částečně upravené na listEmpRec.py ... print('-'*40) emp_list = [bob, fred, tim, john, mike, gary, carl] for emp in emp_list: print( "%-15s works in %s" % (emp.name, emp.department) ) print('-'*40)
== RESTART: F:/Codetest/HowTo/ch-10/in-text/listEmpRec.py == ---------------------------------------- Bob Zimmer works in finance Fred Flint works in purchasing Tim Bauer works in shipping John Ward works in purchasing Mike Holz works in manufacturing Gary Wood works in manufacturing Carl Boor works in manufacturing ----------------------------------------
Pro
>>> "name department salary".split() ['name', 'department', 'salary']
Objekt EmpRec lze tedy alternativně deklarovat takto:
>>> EmpRec = namedtuple('EmpRec', ['name', 'department', 'salary'])Případně: >>> EmpRec = namedtuple('EmpRec', ('name department salary')) >>> type(EmpRec) <class 'type'># vida, ona je to třída, jak od počátku tvrzeno
Kromě prezentovaných metod
Aktuálně platné parametry funkce namedtuple -
Pěkně je také
Funkce mohou vracet entici jako výstupní hodnotu. Můžeme například napsat funkci, která zamění dva parametry:
def swap (x, y):return y, x
Při používání tété funkce je zapotřebí jisté ostražitosti:
>>> a, b = 10,5 >>> swap(a, b) (5,10)# dostali jsme co jsme chtěli >>> a,b (10,5)# vstupní hodnoty jsme ale nezměnili >>> a,b = swap(a, b)# musíme o to výslovně požádat >>> a,b (5,10)
Enticové přiřazení uvnitř funce
Tato funkce případně neprovede to, co jsme si přáli. To je příklad sémantické (významové) chyby.
Přehlednější ukázkou použití entice pro výstupní hodnoty funkce je tento příklad:
from math import pidef kruh (r): c = 2 * pi * r# obvod kruhu a = pi * r * r# plocha kruhu return (r, c, a)
V kapitole 4.3 jsme si povídali o čistých funkcích a modifikátorech v souvislosti se seznamy.
Zde máme modifikátor, který vloží novou hodnotu
pureTriTools.py def insert_in_middle_lst (val, lst): middle = int(len(lst)/2) lst[middle:middle] = [val]
>>> my_list = ['a', 'b', 'd', 'e'] >>> insert_in_middle_lst('c', my_list) >>> my_list ['a', 'b', 'c', 'd', 'e']
Zkusíme-li to s enticí, dostaneme chybu. Problém je ten, že entice jsou neměnitelné a nepodporují změnu přiřazení. Jednoduchým řešením je udělat z
def insert_in_middle_tup (val, tup): middle = int(len(tup)/2)return tup[:middle] + (val,) + tup[middle:]
Tato verze nyní chodí pro entice, ne však pro seznamy a řetězce.
>>> my_tuple = ('a', 'b', 'd', 'e') >>> insert_in_middle_tup('c', my_tuple) ('a', 'b', 'c', 'd', 'e')
Chceme-li verzi pro všechny sekvenční typy, potřebujeme zapouzdřit naši hodnotu do správného sekvenčního typu. Malá pomocná funkce vykoná div:
def encapsulate (val, seq):if type(seq) == type(""):return str(val)if type(seq) == type([]):return [val]return (val,)
Nyní můžeme napsat
def insert_in_middle (val, seq): middle = int(len(seq)/2)return seq[:middle] + encapsulate(val, seq) + seq[middle:]
Poslední dvě verze
>>> from pureTriTools import * >>> my_string = 'abde' >>> insert_in_middle('c', my_string) 'abcde' >>> my_list = ['a', 'b', 'd', 'e'] >>> insert_in_middle('c', my_list) ['a', 'b', 'c', 'd', 'e'] >>> my_tuple = ('a', 'b', 'd', 'e') >>> insert_in_middle('c', my_tuple) ('a', 'b', 'c', 'd', 'e') >>> my_string 'abde'
Hodnoty
Set (množina) je neuspořádaná
Kolekce
Set vytvoříme buď výčtem jeho prvků nebo pomocí funkce
>>> basket ={ 'apple','orange','apple','pear','orange','banana'} >>> basket {'orange', 'apple', 'banana', 'pear'}# žádné duplikáty! >>> song = set("Okolo Hradce"); song {'o', 'O', 'c', 'd', 'l', 'e', 'a', 'k', ' ', 'r', 'H'} >>> tup = (1,2,3,"alpha",2) >>> st = set(tup); st {1, 2, 3, 'alpha'} >>> fr = frozenset('alcatraz') >>> fr frozenset({'a', 'c', 'l', 'r', 't', 'z'})
Použijeme-li jako argument pro funkce
>>> dic = {"a": 1, "b": 2, "c": 3} >>> set_dic = set(dic) >>> set_dic {'b', 'c', 'a'}
Set i frozenset mají definovanou částečně společnou řadu metod:
set_meth = add, clear, copy, difference, difference_update, discard, intersection, intersection_update, isdisjoint, issubset, issuperset, pop, remove, symmetric_difference, union, update, symmetric_difference_updatefrozenset_meth = copy, difference, intersection, isdisjoint, issubset, issuperset, symmetric_difference, union
Objekt typu set nepodporuje změnu položky. Obsah setu lze nicméně měnit metodami
Ukážeme si některé operace na setech:
>>> a = set('abracadabra') >>> b = set('alacazam') >>> a, b# zápis entice ({'a', 'c', 'b', 'r', 'd'}, {'a', 'c', 'z', 'm', 'l'}) >>> a - b# rozdíl {'r', 'd', 'b'}# b-a --> {'z', 'm', 'l'} >>> a | b# sjednocení {'a', 'c', 'r', 'd', 'b', 'm', 'z', 'l'} >>> a & b# průnik {'a', 'c'} >>> a ^ b# doplněk {'r', 'd', 'b', 'm', 'z', 'l'}
Šikovná je redukce hromady čísel na jedinečnou řadu a posléze přeměna na posloupnost čísel:
>>> e = (1,2,3,2,1,2,3,4,5,6,5,6,4,7,8,3,2,1,3,4,5,6) >>> l = list(set(e)); l [1, 2, 3, 4, 5, 6, 7, 8]
Stejně jako pro seznam lze i pro set definovat
>>> s = {v for v in "ABCDABCD" if v not in "CB"} >>> s >>> {'A', 'D'}
Zápisy
def make_empty (seq): """ >>> make_empty([1, 2, 3, 4]) [] >>> make_empty(('a', 'b', 'c')) () >>> make_empty("No, not me!") '' """def insert_at_end (val, seq): """ >>> insert_at_end(5, [1, 3, 4, 6]) [1, 3, 4, 6, 5] >>> insert_at_end('x', 'abc') 'abcx' >>> insert_at_end(5, (1, 3, 4, 6)) (1, 3, 4, 6, 5) """def insert_in_front (val, seq): """ >>> insert_in_front(5, [1, 3, 4, 6]) [5, 1, 3, 4, 6] >>> insert_in_front(5, (1, 3, 4, 6)) (5, 1, 3, 4, 6) >>> insert_in_front('x', 'abc') 'xabc' """def index_of (val, seq, start=0): """ >>> index_of(9, [1, 7, 11, 9, 10]) 3 >>> index_of(5, (1, 2, 4, 5, 6, 10, 5, 5)) 3 >>> index_of(5, (1, 2, 4, 5, 6, 10, 5, 5), 4) 6 >>> index_of('y', 'happy birthday') 4 >>> index_of('banana', ['apple', 'banana', 'cherry', 'date']) 1 >>> index_of(5, [2, 3, 4]) -1 >>> index_of('b', ['apple', 'banana', 'cherry', 'date']) -1 """def remove_at (index, seq): """ >>> remove_at(3, [1, 7, 11, 9, 10]) [1, 7, 11, 10] >>> remove_at(5, (1, 4, 6, 7, 0, 9, 3, 5)) (1, 4, 6, 7, 0, 3, 5) >>> remove_at(2, "Yomrktown") 'Yorktown' """def remove_val (val, seq): """ >>> remove_val(11, [1, 7, 11, 9, 10]) [1, 7, 9, 10] >>> remove_val(15, (1, 15, 11, 4, 9)) (1, 11, 4, 9) >>> remove_val('what', ('who', 'what', 'when', 'where', 'why', 'how')) ('who', 'when', 'where', 'why', 'how') """def remove_all (val, seq): """ >>> remove_all(11, [1, 7, 11, 9, 11, 10, 2, 11]) [1, 7, 9, 10, 2] >>> remove_all('i', 'Mississippi') 'Msssspp' """def count (val, seq): """ >>> count(5, (1, 5, 3, 7, 5, 8, 5)) 3 >>> count('s', 'Mississippi') 4 >>> count((1, 2), [1, 5, (1, 2), 7, (1, 2), 8, 5]) 2 """def reverse (seq): """ >>> reverse([1, 2, 3, 4, 5]) [5, 4, 3, 2, 1] >>> reverse(('shoe', 'my', 'buckle', 2, 1)) (1, 2, 'buckle', 'my', 'shoe') >>> reverse('Python') 'nohtyP' """def sort_sequence (seq): """ >>> sort_sequence([3, 4, 6, 7, 8, 2]) [2, 3, 4, 6, 7, 8] >>> sort_sequence((3, 4, 6, 7, 8, 2)) (2, 3, 4, 6, 7, 8) >>> sort_sequence("nothappy") 'ahnoppty' """ if __name__ == "__main__": import doctest doctest.testmod()
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |