02. Колекции

02. Колекции

02. Колекции

10 март 2014

Въпрос

def my_func(a, b='66'):
    print('{}'.format(a) + b*a)

Какво ще видим, ако изпълним следното:

>> print(my_func(6))
6666666666666
None

Още един:

my_string = '1234567890'
>>my_string[10]

IndexError: string index out of range

И още един..

my_data = set(range(10))

for x in my_data:
    print(x)
    break

Ще изпринти един от елементите, без гаранция кой

Последен..

{}
set()
1
None
True
[1, 2, 3]
(1, 2, 3)
12.0
'абвг'
lambda x: x**0
print, 5, 6, 7, 8

Кои от тези са валидни ключове за dict?

1, None, True, (1, 2, 3), 12.0, 'абвг', lambda-та и (print, 5, 6, 7 ,8)

Излъгах :)

my_dict = dict('12 34 16'.split() + [(False, False)])
print(len(my_dict), my_dict[0])

3 False

Написахте ли си домашното?

░░░░░░░░░▄░░░░░░░░░░░░░░▄░░░░
░░░░░░░░▌▒█░░░░░░░░░░░▄▀▒▌░░░
░░░░░░░░▌▒▒█░░░░░░░░▄▀▒▒▒▐░░░
░░░░░░░▐▄▀▒▒▀▀▀▀▄▄▄▀▒▒▒▒▒▐░░░
░░░░░▄▄▀▒░▒▒▒▒▒▒▒▒▒█▒▒▄█▒▐░░░
░░░▄▀▒▒▒░░░▒▒▒░░░▒▒▒▀██▀▒▌░░░
░░▐▒▒▒▄▄▒▒▒▒░░░▒▒▒▒▒▒▒▀▄▒▒▌░░
░░▌░░▌█▀▒▒▒▒▒▄▀█▄▒▒▒▒▒▒▒█▒▐░░
░▐░░░▒▒▒▒▒▒▒▒▌██▀▒▒░░░▒▒▒▀▄▌░
░▌░▒▄██▄▒▒▒▒▒▒▒▒▒░░░░░░▒▒▒▒▌░
▀▒▀▐▄█▄█▌▄░▀▒▒░░░░░░░░░░▒▒▒▐░
▐▒▒▐▀▐▀▒░▄▄▒▄▒▒▒▒▒▒░▒░▒░▒▒▒▒▌
▐▒▒▒▀▀▄▄▒▒▒▄▒▒▒▒▒▒▒▒░▒░▒░▒▒▐░
░▌▒▒▒▒▒▒▀▀▀▒▒▒▒▒▒░▒░▒░▒░▒▒▒▌░
░▐▒▒▒▒▒▒▒▒▒▒▒▒▒▒░▒░▒░▒▒▄▒▒▐░░
░░▀▄▒▒▒▒▒▒▒▒▒▒▒░▒░▒░▒▄▒▒▒▒▌░░
░░░░▀▄▒▒▒▒▒▒▒▒▒▒▄▄▄▀▒▒▒▒▄▀░░░
░░░░░░▀▄▄▄▄▄▄▀▀▀▒▒▒▒▒▄▄▀░░░░░
░░░░░░░░░▒▒▒▒▒▒▒▒▒▒▀▀░░░░░░░░

Решения на предизвикателството

имаме забележки(да ни се ненадява човек)

Решения на предизвикателството

if smth == True:
    return True
else:
    return False

srsly?

защо?

return smth

Решения на предизвикателството

i = 0
while i < n:
    ...
    i += 1

прекрасна конструкция ако пишем на C

for i in range(n):
    ...

Решения на предизвикателството

return bool(count == number and number != 0)

друга възможност

bool(int(float(int(str(int(count == number and number != 0))))))

Решения на предизвикателството

някои много гадни имена:

Решения на предизвикателството

малко ми е гадно за is_prefect

Решения на предизвикателството

perfect=False
...
if(sum == number):
        perfect = True
else: 
        pass

return perfect

8 spaces for added bonus swag!

Решения на предизвикателството

повече от 3(4, ако живота ви зависи от това) нива на влагане са ужасни

Решения на предизвикателството

value.__ne__(n)

инвестирано е време, за да се потърси как се сравняват числа в python?

инвестицията е на загуба

Решения на предизвикателството

import math
def is_perfect( chislo ):
        if not isinstance(chislo,int):
                return print(False)
        sum=0 
        for x in range(1, math.floor(chislo / 2)+1):
                if chislo % x == 0:
                        sum+=x
        return print(sum == chislo)

ако сме тръгнали, python няма проблем с unicode, дайте да е като хората

import math
def is_perfect( число ):
        if not isinstance(число,int):
                return print(False)
        sum=0 
        for x in range(1, math.floor(число / 2)+1):
                if число % x == 0:
                        sum+=x
        return print(sum == число)

8 spaces for added bonus swag!

Решения на предизвикателството

while(something):
    ...

if(something):
    ...

малкия проблем е, че пред скобите трябва да има space

по-сериозния проблем е, че в python не се пишат скоби на такива места

Обобщение

Малко стил

PEP8! Това е конвенцията за стил на Python. Задължително спазване!

And now for something completely different

По същество за колекции

Да си подредим данните

Когато имаме данни, най-логично е да ги слагаме в колекции.

Какво е колекция?

списъци

nice_things = ['coffee', 'cheese', 'crackers', 'tea']
for thing in nice_things:
    print('I tend to like ' + thing)

можем и просто да ги индексираме

print(nice_things[1]) # cheese
print(nice_things[-1]) # tea
print(nice_things[-3]) # cheese

списъци

Списъците съдържат "указатели" към елементи

coffee, cheese, crackers, tea = 'coffee', 'cheese', 'crackers', 'tea' # unpacking
things_i_like = [coffee, cheese, crackers]
things_you_like = [crackers, coffee, tea]

things_i_like[0] == things_i_like[1] # True
things_i_like[0] is things_i_like[1] # True

списъци

Това позволява някои интересни неща

cheeses = ['brie', 'bergkäse', 'kashkaval', 'leipäjuusto']
cheeses.append(cheeses)

cheeses[-1] is cheeses # True
print(cheeses) # ['brie', 'bergkäse', 'kashkaval', 'leipäjuusto', [...]]

списъци(-ception)

cheeses = ['brie', 'bergkäse', 'kashkaval', 'leipäjuusto']
teas = ['chai', 'earl grey', 'jasmine', 'oolong']

breakfast = [cheeses, teas]
print(breakfast[0][1]) # bergkäse

breakfast[1][2] = ['шкембе', 'люби чушки', 'оцет с чесън']
print(teas) # ?

['chai', 'earl grey', ['шкембе', 'люби чушки', 'оцет с чесън'], 'oolong']

range

range връща итерируемо за интервал от числа

numbers = range(3)

for number in numbers:
    print('We can count to ' + numbers)

range

range интервалът може да не започва от нула

numbers = range(10, 13)

for number in numbers:
    print('We can count to ' + numbers)

tuple

последователност, n-торка(n-орка), тюпъл

като списък, но с постоянен състав

people = ('Niki', 'Kiro', 'Stefan')
people[2] # Stefan
people[1] # Kiro
people[0] # Niki

people[1] = 'бобър'

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment

кортеж

tuple

последователността от елементи в кортежа не може да се променя, самите елементи може да изменят вътрешната си структура

change_me = ([1, 2, 3], [4, 5, 6], [7, 8, 9])
change_me[1][1] = 0
change_me[2][0] = 'c'

print(change_me) # ([1, 2, 3], [4, 0, 6], ['c', 8, 9])

tuple

алтернативен синтаксис за кортежи

people = 'Niki', 'Kiro', 'Stefan'
people = 'Niki',

people = ('Niki') # най-вероятно не е каквото очаквате

Популярни структури от данни

Опашка (queue, FIFO buffer) - можете да ползвате списък.

adjectives = []

def add_adjective(items):
    adjectives.append(items)

def get_adjective():
    return adjectives.pop(0)

add_adjective('Magic')
add_adjective('Woody Allen')
add_adjective('Zombie')
add_adjective('Superhero')

print(' '.join(adjectives) + ' Jesus!') # Magic Woody Allen Zombie Superhero Jesus!

Stack?

Влизат collections

deque

from collections import deque
adjectives = deque()

def add_adjective(items):
    adjectives.append(items)

def get_adjective():
    return adjectives.popleft()

add_adjective('Komodo Dragon')
add_adjective('Telepathic')
add_adjective('Vampire')
add_adjective('Quantum Hovercraft')

print(' '.join(adjectives) + ' Jesus') # Komodo Dragon Telepathic Vampire Quantum Hovercraft Jesus

sets

Множества(за всякакви практически цели неразличими от математическата абстракция със същото име)

favourite_numbers = set()
favourite_numbers.add(13)
favourite_numbers.add(73)
favourite_numbers.add(32)
favourite_numbers.add(73)
favourite_numbers.add(1024)
favourite_numbers.add(73)

print(favourite_numbers) # {32, 73, 666, 13, 1024}

sets

Множествата са итеруеми и НЕподредени

for num in favourite_numbers:
    print('I really like the number ' + str(num))

sets

можем да проверяваме за принадлежност

73 in favourite_numbers # True

sets

Има синтаксис за създаване на множества(както може би сте се досетили)

favourite_numbers = {32, 73, 666, 13, 1024}

{} не е празния set!

dict

Индексите не винаги са достатъчно информативни

artist_names = {
    'Eddie': 'Vedder',
    'Maynard': 'Keenan',
    'Matthew': 'Bellamy',
    'James': 'LaBrie',
}

print('Eddie\'s last names is ' + artist_names['Eddie'])

{}

{} е празен речник, по простата причина, речниците са доста по-често използвана структура от множествата

dict

можем да добавяме нови стойности във вече създаден речник

names['Devin'] = 'Townsend'

print(names) # {'Devin': 'Townsend', 'Matthew': 'Bellamy', 'Eddie': 'Vedder', 'James': 'LaBrie', 'Maynard': 'Keenan'}

речникът също е неподреден

кой какви сирена има

data = [ ('John', 'Tilsit'), ('Eric', 'Cheshire'), ('Michael', 'Camembert'),
         ('Terry', 'Gouda'), ('Terry', 'Port Salut'), ('Michael', 'Edam'),
         ('Eric', 'Ilchester'), ('John', 'Fynbo') ]

def cheeses_by_owner(cheeses_data):
    by_owner = {}
    for owner, cheese in cheeses_data: # <- tuple unpacking
        if owner in by_owner:
            by_owner[owner].append(cheese)
        else:
            by_owner[owner] = [cheese]

    return by_owner

defaultdict

from collections import defaultdict
data = [ ('John', 'Tilsit'), ('Eric', 'Cheshire'), ('Michael', 'Camembert'),
         ('Terry', 'Gouda'), ('Terry', 'Port Salut'), ('Michael', 'Edam'),
         ('Eric', 'Ilchester'), ('John', 'Fynbo') ]

def cheeses_by_owner(cheeses_data):
    by_owner = defaultdict(list)
    for owner, cheese in cheeses_data:
        by_owner[owner].append(cheese)

    return by_owner

map/filter/reduce

за любознателните: map и filter са мързеливи

Comprehensions

List comprehension

[израз for променлива in поредица if условие]

>>> [x * x for x in range(0, 10)]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

>>> [x * x for x in range(0, 10) if x % 2]
[1, 9, 25, 49, 81]

List comprehension

Един list comprehension може да се вложи в друг, защото връща нещо итерируемо

>>> [(x, y) for x in [1,2,3] for y in [3,1,4] if x != y]
[(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]

Generator expression

Set comprehension

>>> import math
>>> {int(math.sqrt(x)) for x in range(1,100)}
{1, 2, 3, 4, 5, 6, 7, 8, 9}

Dict comprehension

>>> {i : chr(65+i) for i in range(10)}
{0: 'A', 1: 'B', 2: 'C', 3: 'D', 4: 'E', 5: 'F', 6: 'G', 7: 'H', 8: 'I', 9: 'J'}

itertools

>>> import itertools
>>> help(itertools)

Въпроси?