Problem z konwersjami

0

Witajcie. Postanowiłem pouczyć się coś pythona i taki 'większy' program z mojej strony, zawsze 5-7 linijek teraz 62 ale nie o to chodzi.

class IllegalConversions:
   [...]
    def TupleToDictionary(self, tup = (), allvalues = False):
        dict = {}
        if len(tup) == 0:
            print 'No-values in tuple!'
            return dict
        if allvalues == True and len(tup) % 2 == 0:
            for i in range(0, len(tup), 2):
                dict[tup[i]] = tup[i+1]
                if len(tup) - (i+1) <= 0:
                    return dict
        elif allvalues == False:
            for i in range(0, len(tup), 2):
                if len(lis) - (i+1) and len(lis) - (i+2) <= 0:
                    dict[tup[i]] = None
                    return dict
                else:
                    dict[tup[i]] = tup[i+1]
            return dict
        else:
            print 'Huh ?',
            return dict

Wszystko pięknie działa, tylko problem mam z TupleToDictionary
Otóż wszystko działa dla tupki = (1,2,3) zamienia to na słownik:
{1:2, 3: None}
Niestety dla jednego argumentu działa źle (traktuje tupke jako inta ...)
tupki = (1) < --- to jest błąd, traktuje jako inta i nie zamienia na słownik;
Cóż, postanowiłem, że pyknę to len(tupki), jeśli będzie 1 'item' w to wypiszę ten item : None
Niestety jako iż uznaje to za int, nie mogę użyć LEN...
Więc jak zbadać czy jest tylko 1 element w tupli bez "łapania errorów" ?

0
```python if type(t)=='tuple': print 'krotka' else: print 'co innego'
</del>
0

@bogdans, bzdura, Python to nie JS!

Dwie opcje:

# bardziej prawidłowa:
if isinstance(obj, tuple):
    print "tuple!"
# mniej prawidłowa bo nie dopuszcza typów pochodnych:
if type(obj) is tuple:
    print "tuple!"

@Resident, jednoelementowa krotka to (1,). Inny zapis kolidowałby z normalnym opcjonalnym nawiasowaniem wyrażeń. Poza tym to nie Pascal, korzystaj z dynamicznego typowania zamiast z nim walczyć. Niech to będzie dowolny obiekt iterowalny, nie wal wszędzie == True, == False, == 0, korzystaj z naturalnych właściwości ifa...

1
bogdans napisał(a)

Dlaczego bzdura?

type zwraca obiekt typu, nie nazwę typu w formie stringa, w końcu Python jest językiem obiektowym...

Kilka przykładowych (nie zawsze optymalnych) implementacji konwersji dowolnej iterowalnej kolekcji na słownik:

import itertools

def iter_to_dict_1(xs, all_values=False):
    """
    Prosta implementacja, dzieli wejscie na listy kluczy i wartosci.
    Dla nieparzystej liczby elementów dodaje None do listy wartosci.
    Jedyna implementacja uzywajaca dodatkowej pamieci.
    """
    keys, vals = [], []
    for i, x in enumerate(xs):
        if i % 2 == 0:
            keys.append(x)
        else:
            vals.append(x)
    if i % 2 == 0 and all_values:
        vals.append(None)
    return dict(zip(keys, vals))

def iter_to_dict_2(xs, all_values=True):
    """
    Modyfikacja wykorzystujaca leniwe generatory.
    `tee` tworzy wiele niezaleznych iteratorow z przekazanego, domyslnie 2.
    `izip_longest` automatycznie dodaje `None` dla niesparowanego elementu.
    """
    data = itertools.tee(enumerate(xs))
    keys = (x for i, x in data[0] if i % 2 == 0) 
    vals = (x for i, x in data[1] if i % 2 == 1)
    izip = itertools.izip_longest if all_values else itertools.izip
    return dict(izip(keys, vals))

def iter_to_dict_3(xs, all_values=False):
    """
    Implementacja z wykorzystaniem closures i generatora.
    `StopIteration` z `next` przerywa jednoczesnie generowanie slownika.
    """
    def make_pairs():
        ys = itertools.chain(xs, [None]) if all_values else iter(xs)
        while True:
            yield next(ys), next(ys)
    return dict(make_pairs())

def iter_to_dict_4(xs, all_values=False):
    """
    Male szalenstwo z itertools...
    """
    data = itertools.chain(xs, [None]) if all_values else iter(xs)
    gens = itertools.tee(data)
    keys = itertools.compress(gens[0], itertools.cycle((True, False)))
    vals = itertools.compress(gens[1], itertools.cycle((False, True)))
    return dict(itertools.izip(keys, vals))

Miłej zabawy w rozczytywanie z dokumentacją, Pytaj jak nie będziesz czegoś mógł zrozumieć.

0

Zawsze można jeszcze sprytnie wykorzystać slicing:

from itertools import izip_longest
tup = (1, 2, 3, 4, 5, 6, 7 )
dic = dict(izip_longest(tup[0::2], tup[1::2]))
0

teraz jestem zbyt zmęczony by to ogarnąć, jutro popatrzę o co chodzi z tym itertools, na necie poradniki są kiepskie, muszę się poradzić jaką książkę do pythona dobrą kupić.
Dobranoc, dzięki za odpowiedzi ;)

0
Zjarek napisał(a):

Zawsze można jeszcze sprytnie wykorzystać slicing

E, nie, nie zawsze :]. Bardzo niewielka część iterowalnych obiektów implementuje ten protokół, nie wykorzystasz niczego, co jest typowym streamem. Dlatego m. in. położyłem nacisk na użycie tee, część kolekcji można przejść tylko jednokrotnie, budowanie z nich dodatkowych kompletnych kolekcji to nadmiarowy koszt. Starałem się napisać jak najbardziej ogólne funkcje, stawiające jak najmniejsze wymagania, można nimi np. zbudować słownik bezpośrednio z obiektu pliku lub streama sieciowego, których nie da się indeksować.
Jeśli sięgamy po itertools to lepiej używać islice, obejdzie się bez alokowania dodatkowej pamięci. Faktycznie jeśli piszemy typowo pod listy i krotki to (i)zip + (i)slice jest najkrótszym rozwiązaniem.

Resident napisał(a):

na necie poradniki są kiepskie, muszę się poradzić jaką książkę do pythona dobrą kupić.

Przeczytaj oficjalną dokumentację, jest tam tutorial, jest bardzo dokładne omówienie wszystkich modułów razem z przykładami użycia i równoważnymi implementacjami. Python jest naprawdę świetnie udokumentowany. Chyba nadal najlepszą książką skupiającą się na samym języku jest Python Essential Reference, ale dokumentacja powinna wystarczyć w zupełności.

0

To z tee wydawało mi się zbyt skomplikowane jak na rozwiązanie Pythonowskie, w dokumentacji jest fajny przykład:

def grouper(n, iterable, fillvalue=None):
    "grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx"
    args = [iter(iterable)] * n
    return izip_longest(fillvalue=fillvalue, *args)

1 użytkowników online, w tym zalogowanych: 0, gości: 1