Wersje oryginalne i pirackie filmów

UWAGA: Poniżej wyrażone opinie są moimi osobistymi i każdy ma prawo się z nimi nie zgadzać. Jeśli tak właśnie jest i chcesz złożyć skargę – naciśnij krzyżyk zamykający przeglądarkę.

Jakub „Unknow” Mrugalski opublikował ciekawy film, w którym porusza temat legalności oprogramowania przytaczając niezbyt przyjemną sytuację z życia. Źródło: Facebook

Korzystając z tej okazji chciałbym przedstawić inny problem, ale który także dotyczy legalności – filmów.
Jako ofiara konsumpcyjnego stylu życia oraz (nauczony przez mojego dziadka) chomikowania wszystkiego co popadnie kupuję filmy na DVD. Chociażby dlatego, że kiedyś nie mogłem sobie finansowo na to pozwolić. A że były/są filmy do których często z żoną wracamy – znając je (filmy) i tak na pamięć – to miło je mieć. Poza tym, VHSy ciężko już odtwarzać a Internety ktoś może nagle wyłączyć.

Dlaczego jednak uważam, że wersje „kupione” na torrentach są lepsze?

Ponieważ nie są naszpikowane spotami reklamowymi.

Płacąc za oryginalny film na DVD – zanim w ogóle zacznę film oglądać muszę się nasłuchać (i naoglądać), że pobranie filmu z Internetu to kradzież (właśnie dlatego zainwestowałem w legalną wersję). Oczywiście gdyby tego było mało muszą się jeszcze znaleźć reklamy filmów, które za miesiąc pojawią się w kinie. Po co, grzecznie się spytam?!
Ja rozumiem, że kasa się musi zgadzać, ale czemu kosztem zniechęcania klientów do płacenia za rozrywkę?

Jeśli jednak chodzi o problem poruszany przez Jakuba w kwestiach korzystania z oprogramowania bez licencji (oczywiście w niektórych sytuacjach) to podpisuję się nogiema i rencyma pod kilkoma komentarzami do tego filmu – w skrócie –  korzystanie z wersji elektronicznej nie zmniejsza ilości danego produktu u dostawcy, jednak może znacznie zwiększać prawdopodobieństwo kupna tego oprogramowania w przyszłości.

PyCharm – jedna konfiguracja na wielu instancjach

Ponownie chciałbym pochwalić PyCharma – w sumie to wszystkie IDE od JetBrains.

Otóż narzędzie to pozwala nam na współdzielenie naszej ulubionej konfiguracji środowiska pomiędzy różnymi instancjami – jeśli używamy tego IDE w pracy i w domu to warto z tego skorzystać.
Oczywiście ma to też ten plus, że w przypadku kradzieży/zniszczenia możemy w całkiem prosty sposób odzyskać poprzednią konfigurację.

A sprawa jest całkiem prosta:

  1. Zakładamy nowe repozytorium, np. w serwisie GitHub (tak, może być też GitLab albo jakiekolwiek inne – ja lubię GitHub)
  2. W PyCharm wybieramy kolejno File > Settings Repository i ustawiamy konkretny Upstream URL na adres repozytorium
  3. Nadpisujemy zdalne (Overwrite Remote)
  4. To samo robimy na pozostałych instancjach nadpisując ustawienia lokalne (Overwrite Local)

Gdy już mamy zsynchronizowane, każda zmiana powinna być automatycznie pobierana z i wysyłana do repozytorium – jednak opcja Merge też w niektórych sytuacjach może się przydać 🙂

Wąż w stringach

Jednym z pierwszych typów danych o których uczymy się w ramach najróżniejszych kursów programowania jest typ łańcuchowy – często określany jako string. Nie bez powodu jest to jeden z najczęściej używanych w programowaniu typów. A dlaczego? Ponieważ jako ludzie głównie działamy na tekście: czytamy książki, piszemy listy, ostrzegamy o wysokim napięciu, opisujemy substancje chemiczne, gryzmolimy tagi na rozkładach jazdy (kto wracał komunikacją nocną i nie mógł odczytać rozkładu przez głupie tagi wie, że tego typu teksty są najmniej lubiane) – w dużym skrócie – tekstu używamy wszędzie.

Oczywiście ma to swoje konsekwencje -w programowaniu wykorzystujemy tekst aby wyświetlić cokolwiek na ekranie, do logowania aktualnego stanu aplikacji, gdy prosimy użytkownika o podanie informacji, przesyłamy informacje przez sieć.

Łańcuch znaków jest po prostu kolekcją… znaków. Mogą to być zarówno znaki drukowalne, jak np. litery alfabetu, cyfry czy znaki interpunkcyjne lub niedrukowalne – znaki o specjalnym znaczeniu – spacje, tabulacje, „dzwonek systemowy”.
Stringi mogą mieć długość od zera do… prawie rozmiaru pamięci zainstalowanej w komputerze. Oczywiście, mają tutaj jeszcze ogromne znaczenie inne czynniki – np. wersja Pythona czy architektura komputera, jednak dla codziennych zastosowań nie powinniśmy się tym aż tak bardzo przejmować. Gdybyśmy jednak chcieli zrobić kopię zapasową Internetu możemy w pewnym momencie zderzyć się z błędem MemoryError.

Długość (między innymi) łańcuchów określa się wbudowaną w Pythona funkcją len jednak należy mieć na uwadze, że ilość znaków, którą widzimy to nie zawsze rzeczywista długość łańcucha trzymana w pamięci. Posiłkując się StackOverflow:


>>> test = u'ë́aúlt' # znaki można policzyć na palcach jednej ręki (dla regionów oddalonych od Czarnobyla)
>>> len(test)
6
>>> # Hmm, chyba jednak jesteśmy blisko uszkodzonego reaktora…
>>> for c in test:
print("{} – {}".format(c, len(c)))
ë 1
1
a 1
ú 1
l 1
t 1
>>> # i wszystko "jasne"…

view raw

strlen_py3.py

hosted with ❤ by GitHub

Dla Pythona 2 wyniki są jeszcze bardziej zaskakujące (w odpowiedzi na StackOverflow został właśnie użyty Python 2).

Stringi w Pythonie możemy zapisywać w kodzie na kilka różnych sposobów:


>>> print("Witaj świecie")
Witaj świecie
>>> print("Witaj 'świecie'")
Witaj 'świecie'
>>> print("Witaj \"świecie\"")
Witaj "świecie"
>>> print('Witaj świecie')
Witaj świecie
>>> print('Witaj "świecie"')
Witaj "świecie"
>>> print("""Witaj 
świecie""")
Witaj
świecie
>>> print('''Witaj 
świecie''')
Witaj
świecie
>>> print("Witaj\t\t\t\n\t\t\t\tświecie")
Witaj
świecie
>>> print('Witaj\t\t\t\n\t\t\t\tświecie')
Witaj
świecie

view raw

pystrings.py

hosted with ❤ by GitHub

Jednak wyświetlanie na ekranie prostych łańcuchów znaków może w pewnym momencie stać się dość nudne – na szczęście wynaleziono interpolację.

Interpolacja to wg Słownika Języka Polskiego: „wstawienie wyrazów, zwrotów, zdań do pierwotnego tekstu; też: takie wstawione wyrazy, zwroty, zdania”.
W naszej sytuacji chodzi o podstawienie wartości ze zmiennych w konkretne miejsca w łańcuchu znaków.
Przykładowo jeśli posiadamy szablon z informacją o uczniu i jego ocenie: "Cześć {imię i nazwisko ucznia}. Uzyskałeś {ilość punktów} punktów z egzaminu." to każde nasze wystąpienie {coś tam} będziemy mogli podmienić konkretnymi wartościami.
Do uzyskania konkretnego łańcucha znaków – z już podmienionymi wartościami możemy podejść (ponownie) na kilka sposobów – lepszych lub gorszych.
I tak na przykład, jednym z nich – niezbyt fajnym ani wygodnym – będzie po prostu łączenie łańcuchów znaków:


uczen = "Alpha Bravo"
punkty = 80
print("Cześć " + uczen + ". Uzyskałeś " + str(punkty) + " punktów z egzaminu.")

Nie da się chyba tego lubić. Przy okazji warto zwrócić uwagę, że pamiętać musimy o rzutowaniu na odpowiedni typ funkcją str albo zderzymy się z błędem TypeError.

Inny ciekawy (dla masochistów) sposób, to zapisanie wszystkiego jako lista i jej połączenie pustym łańcuchem:


uczen = "Alpha Bravo"
punkty = 80
print("".join(["Cześć ", uczen, ". Uzyskałeś ", str(punkty), " punktów z egzaminu."]))

Kod tak wspaniały, że aż oczy bolą… No dobra, są sytuacje, gdzie podobne podejście będzie akceptowalne, całkiem zwięzłe i czytelne… ale to nie jest ten przypadek.

Zmierzamy powoli w kierunku lepszego jutra – rozwiązanie dość popularne jeszcze do niedawna:


uczen = "Alpha Bravo"
punkty = 80
print("Cześć %s. Uzyskałeś %d punktów z egzaminu." % (uczen, punkty))

Plusem tego sposobu interpolowania łańcucha jest to, że korzysta on z wielu dostępnych specyfikatorów formatowania – co pozwala nam z kolei przyoszczędzić na jawnym konwertowaniu wartości zmiennych na łańcuchowy typ danych – musimy jednak zadbać o odpowiedni specyfikator w stringu.

Pierwszy z zalecanych (moim zdaniem) sposobów interpolowania to wykorzystanie metody format obiektu string:


uczen = "Alpha Bravo"
punkty = 80
print("Cześć {}. Uzyskałeś {} punktów z egzaminu.".format(uczen, punkty))

Sposób ten jest tak fajny, że aż dorobił się własnej strony internetowej z najróżniejszymi przykładami.

Drugim zalecanym (znów, moim zdaniem) sposobem jest użycie tzw f-stringów – dostępnych niestety dopiero od Pythona 3.6:


uczen = "Alpha Bravo"
punkty = 80
print(f"Cześć {uczen}. Uzyskałeś {punkty} punktów z egzaminu.")
print(f"2 + 2 = { 2 + 2 }")

Jeszcze innym sposobem interpolowania o którym warto wspomnieć jest użycie klasy Template z modułu string:


from string import Template
uczen = 'Alpha Bravo'
punkty = 80
tpl = Template("Cześć $uczen. Uzyskałeś $punkty punktów z egzaminu.")
print(tpl.substitute(uczen=uczen, punkty=punkty))

jednak nie spotykałem się z nim zbyt często – warto jednak wiedzieć, że coś takiego jest.

Więcej o samej interpolacji w Pythonie poczytać możemy w oficjalnych dokumentach PEP-0215PEP-0498, PEP-0501 oraz PEP-0502.

Dodatkowo, sam łańcuch znaków jako obiekt ma całkiem sporo metod pozwalających operować na danym łańcuchu, przytaczając kilka takich metod:


# https://pl.wikipedia.org/wiki/Pangram
pangram = "pChNąĆ w Tę łÓdŹ jEżA lUb OśM sKrZyŃ fIg"
print(pangram.capitalize())
print(pangram.casefold())
print(pangram.title())
print(pangram.upper())

UWAGA: Wywołanie takiej metody na stringu nie powoduje jej zmiany w pamięci.

I tym oto sposobem przechodzimy do faktu, że łańcuchy znaków są niezmiennym typem danych (tzw. immutable). Cool. I co to znaczy?
W dużym skrócie chodzi o to, że jeśli zmienimy łańcuch znaków to zmieni się jego lokalizacja w pamięci – zostanie utworzony nowy, zmodyfikowany obiekt. Najlepiej zaobserwujemy to na przykładzie:


>>> my_str_i = "Alpha"
>>> my_str_ii = "Bravo"
>>> my_str_iii = my_str_i
>>> my_str_iv = "Alpha"
>>> hex(id(my_str_i))
'0x7f5fec555960'
>>> hex(id(my_str_ii)) # 2 różne wartości w różnych miejscach pamięci
'0x7f5fe67e71f0'
>>> hex(id(my_str_iii)) # po przypisaniu referencji do obiektu obie zmienne wskazują to samo miejsce w pamięci
'0x7f5fec555960'
>>> hex(id(my_str_iv)) # ta sama wartość może być trzymana w pamięci pod jednym adresem
'0x7f5fec555960'
>>> my_str_i += ' Delta' # zmieniamy referencję ponieważ tworzymy nowy obiekt i wrzucamy go w inne miejsce pamięci
>>> hex(id(my_str_i))
'0x7f5fe684e730'
>>> hex(id(my_str_iii)) # pozostałe referencje nie zostały zmienione
'0x7f5fec555960'
>>> hex(id(my_str_iv))
'0x7f5fec555960'

Dla wygody skorzystałem z wbudowanych funkcji hex i id.

Na koniec warto wspomnieć o dostarczanym ze standardową biblioteką Pythona modułem string, który głównie może okazać się przydatny jeśli będziemy potrzebowali kolekcji znaków: małych lub dużych liter, cyfr (także ósemkowych lub szesnastkowych) czy białych znaków, itp.

Dodatkowe źródła:
[1] A string of unexpected lengths
[2] Moduł string