Open MarcinCiura opened 4 years ago
# -*- coding: utf-8 -*-
to zaszłość z Pythona 2. W Pythonie 3 nic nie robi. Przydać by się mogło tylko, gdyby używała Pani przedpotopowego edytora, w którym domyślne kodowanie to nie UTF-8.find_shortest_path()
, albo biblioteki networkx
, albo python-igraph
. Dodam tylko, że 14. przykazanie programisty/programistki brzmi: "If it ain't broke, don't fix it".Dzień dobry!
12.Poprawione. Faktycznie, z przyzwyczajenia do biblioteki numpy z labolatoriów nawet na to nie wpadłam! :)
Lambdy robiłam ze względu na to, że Pan Gąciarz pisał, że jeśli chodzi o Buttony to warto je tam stosować. Potem rzeczywiście zaczęłam szukać, czy taką praktykę się stosuje i właśnie w moim programie one zdają egzamin. Właśnie jak próbowałam robić bez lambd to efekty nie spełniały moich oczekiwań - czasami nawet funkcja na buttonie w ogóle nie chciała się bez niej wykonać i tutaj mówię o funkcjach typu " Wyświetl napis helllo World". Zaczęłam szukać w internecie jak ktoś obszedł podobny problem do mojego i właśnie zastosował labdy na buttonie i dopiero wtedy mi to zadziałało, także nie mam pojęcia jak to inaczej obejść. :(
Czyli mam rozumieć, że nie ma być dziedziczenia "hierarchicznego"? Postaram się to zmienić.
15.Stałe stworzyć jako globalne dla wszystkich klas,czy dla przykładowo każdej klasy osobno? Wydaje mi się, że lepiej będzie dla każdej klasy osobno zdefiniować kilka takich wartości (które rzeczywiście się nie zmieniają), dlatego, że u mnie rozmiar czcionki w programie, czy kolory akurat ulegają ciągłym zmianom. Czcionki się zmieniają chociażby dlatego, że jak wywołuję Label'a, który wypisuje przystanki, a tych przystanków jest jakieś 30 to przy czcionce rozmiaru 20 nie ma szans, żeby mi się to zmieściło. A kolorki się zmieniają, żeby nie było smutno, żmudno i monotonnie. :)
Numery liniii wczytane z bazy wyglądają tak: [('469',), ('439',), ('164',), ('608',), ('511',), ('304',), ('139',), ('503',), ('208',), ('179',), ('501',), ('292',), ('192',), ('169',), ('159',)] i właśnie dzięki linijce kodu str(i)[2:-3] wyświetlają się jako '469','439'...(chodziło o obcięcie zarówno nawiasów, jak i apostrofów). Próbowałam to robić int(i), ale nie działało. Teraz spróbowałam split na tej zmiennej i pokazuje mi, że nie ma takiego atrybutu. Ten fragment kodu służy tylko do wyświetlenia liniii użytkownikowi w przypadku dojazdów bezpośrednich, żeby sobie wybrał spośród nich i wpisał do pola, którą linię chce dojechać. 17.Poprawione. Racja! Mój zapis był trochę bez sensu. 18.Poprawione. Ale super! Od razu wzięłam to do przystanków w drugą stronę.
--> Chodziło mi dokładnie o to co Pan napisał, ale nie wiedziałam jak to ubrać dobrze w słowa. Ogólnie jak pisałam tego maila ciężko mi było pozbierać myśli, bo miałam w głowie cały czas " Muszę napisać jeszcze to i to " i przez to mogłam coś poprzekręcać. Proszę wybaczyć czasem chaotyczne wiadomości - wynika to z pewnego rodzaju "nieobycia" jeszcze w tej terminologii programistycznej i czasem też mojego roztrzepania. --> jasne, poprawione. Dużo robiłam zmiennych roboczych, na szybko - póki pomysł nie wyleci z głowy. --> (teraz już values są jako stops) są wczytywane w formie listy, w sensie KAŹDY stop jako OSOBNA lista (trochę mnie to zdzwiło) - ale takie rezultaty otrzymuję z tej części dotyczącej sql-a. Nie do końca wiedziałam na początku jak to obejść, zeby wczytywało jako po prostu listę przystanków, a nie "listę w liście", więc po prostu przekonwertowałam tak, zeby stamtąd brało tylko stringa, czyli samą nazwę przystanku. Także w tym wypadku str(stops[i]) mi się bardzo przydał. --> Tak, to jest usuwanie nawiasów. Ogólnie chciałam tam zastosować strip albo replace, ale z niewiadomych przyczyn (dla mnie) nie chce mi to działać, więc stąd wykorzystanie first.translate(...). Jak dawałam przykładowo "first.replace('[', '').replace(']', '')" to w ogóle mi nie wyszukiwało przystanków. Pamiętam,że tkwiłam w tym punkcie długo, aż w końcu natknęłam się na "translate" i to jako jedyne rozwiązało problem.
Rozumiem i też mi się to strasznie niepodoba, ale proszę mi wierzyć - siedziałam nad tym z 4 h jak nie więcej. Przekazywałam wszystkie inputy użytkownika do klasy 3 okna - sprawdzałam kilkukrotnie, czy na pewno je dobrze przekazuję i czy "są widoczne" i możliwe do użycia w klasie - z tym było w porządku. No to sobie zaimplementowałam te funkcje na 3cim oknie do wyszukiwania drogi i nie było żadnej akcji, nic nie działało. Ogólnie nie znalazłam dużo dobrych informacji na temat wielu okien w bibliotece Tkinter, więc już z bezsilności dałam na 2gie okno. Czy jeśli by tak zostało to jest bardzo dyskwalifikujące?
Jasne, poprawiłam. Mogę wrzucić w postaci funkcji, ale nigdzie niewywołanej? ( z racji tego, że za pomocą graf.py stworzyłam już wcześniej ten plik. Baza nie jest aktualizowana w żaden sposób to uważam, że nie ma potrzeby go ciągle na nowo tworzyć.)
To mnie Pan zaskoczył w sumie, bo ja normalnie czytam te dane właśnie z pliku .json i wyszukuje mi te połączenia.Ze względu na czytelność wybrałam .jsona - jedyne co tam musiałam zmienić to to żeby czytało w utf-8, bo nie czytało mi poprawnie polskich znaków. Ale ten algorytm normalnie działa na tym pliku i generalnie sprawdzałam na stronach typu "Jak dojadę" to często się pokrywają te pośrednie połączenia. Niestety, mam starą bazę, więc sporo z tych połączeń zostało usuniętych albo zmodyfikowanych, więc głównie weryfikowałam poprawność na podstawie podobieństw i analizowania algorytmu.
23.Poprawione. Korzystam ze Spydera, a on z automatu daje tę linijkę kodu :)
Ufff, wyszło całkiem długie wypracowanie. Dziękuję za wszystkie poprawki, dużo mi dają i mam nadzieję,że będę takich błędów popełniać coraz mniej. Pozdrawiam!
Dziękuję za zmiany i za odpowiedź. Już teraz kod wygląda dużo lepiej.
journeyCosts
się przyczepiał nie do obiektu klasy, tylko do klasy, a tak być nie powinno. Ale dobrze, że Pani wspomniała o hermetyzacji. Dodam do Poradnika punkt o niepotrzebności getterów i setterów w Pythonie. Zamiast nich można albo: a) swobodnie czytać i pisać atrybut journey_costs
, przy czym przy czytaniu samej go sobie sumować (zgadzam się, że niezbyt eleganckie), albo: b) zrobić atrybut _journey_costs
z getterem, który je sumuje, i spowodować za pomocą odpowiedniego dekoratora, że odczyt pseudoatrybutu ticket_cost
zostanie do niego przekierowany. Na marginesie: w snake_case
ma nie być żadnych wielkich liter.tk.Button(command=lambda: self.combine_func(fn1, fn2))
. Ponieważ wywołanie self.combine_func()
zwraca tzw. domknięcie (closure), czyli po prostu obiekt, który potem można wywołać, działało to tak samo jak lambda: jakaś_funkcja
, co przy wywołaniu zwraca nieciekawy wynik — obiekt funkcji jakaś_funkcja
. Żeby jakaś_funkcja
się wywoływała przy wykonaniu command
, trzeba napisać albo lambda: jakaś_funkcja()
(czyli u Pani dopisać ()
po self.combine_func(fn1, fn2)
), albo po prostu jakaś_funkcja
, co jest prostsze i o co mi chodziło.Win2
i Win3
nie są udoskonaleniem Win1
, tylko raczej jego równorzędnymi braćmi, prawda?.fetchall()
. Standardowy sposób robienia SELECT-ów jest taki:
line_numbers = []
for row in cursor.execute(
"""
SELECT LineName FROM StopDepartures
WHERE ... ?
AND ?
""",
(a, b)):
line_numbers.append(row[0])
# Prosi Pani SELECT-em o 1 kolumnę, więc
# w każdym wierszu dostaje 1-elementową krotkę.
[["Bronowice"], ["Mistrzejowice"], ["Miśnieńska"], ["Głowackiego"],...
. Więc stops[i]
zwraca np. ["Bronowice"]
i żeby z tego wyciągnąć to, co chcemy, wystarczy stops[i][0]
. ALE: JSON z listą jednoelementowych list napisów zamiast z listą napisów jest dziwny. A jest taki, bo w graph.py
też Pani użyła .fetchall()
. Teraz, kiedy Pani już wie, jak się obchodzić z SELECT-ami, jest świetna okazja do spowodowania, żeby graph.py
robił lepszego JSON-a. Samodzielnym ćwiczeniem niech będzie dostosowanie make_graph_from_dict()
do takiego lepszego JSON-a.find_shortest_path()
leżała poza jakimikolwiek klasami, bo ona jest przydatna w ogóle, a nie tylko w oknie Win2
czy Win3
. To łatwo zrobić. Potem powinna Pani znowu zamienić dziwne operacje na napisach pod koniec tej funkcji na porządne indeksowanie. W razie problemów proszę mi napisać, jak wygląda przykładowe shortest_way
przed przeróbkami.funkcja(argument, argument1,argument2)
Zrobiłam: funkcja(argument, argument1, argument2)
(nie wiem jak to sformatować w kod, bo mi wrzuca do jednej liniii)
Czy o to chodzi?
Zahermetyzowałam journey_costs. Poprawiłam te duże litery na małe.
Jeśli chodzi o decodery to na bazie przykładów znalezionych w internecie wiem o co z nimi chodzi, ale nie do końca rozumiem jaką u mnie by miało funkcję spełnić. Mogłabym zrobić @ticket_costs
na funkcji get_ticket_costs
,tylko , że jest taka sprawa, że ja właśnie nie chcę za każdym razem wywoływać funkcji ticket_costs , a zastosowanie tego dekoratora tutaj chyba z tym by się wiązało. Nie chcę dlatego, że ja w konkretnych miejscach programu, zeby obliczyć wartość biletu po prostu wywołuję tę funkcję w każdym nowym połączeniu i ona dolicza np 4.60 zł za każdym razem (przejazd z punktu A do B - 1 bilet, z B do C - drugi bilet). Za to get_ticket_costs
mi po prostu zwraca łączną sumę do labela - ta funkcja w zasadzie jest mi potrzebna tylko do wyświetlania. W momencie kiedy dam @ticket_costs
to to sprawi, ze jeden bilet będzie doliczony "nadmiarowo" - będzie o jeden bilet za dużo. Czy to błędne myślenie i jednak nie do końca rozumiem o co chodzi?
Poprawione. Tak, zorientowałam się dopiero jak Panu napisałam maila, że w zasadzie to combine_func
nic nie robi i tak jak Pan napisał, można po prostu wywołać jedną funkcję - pamiętam, że wtedy nie do końca wiedziałam jak działa przełączanie się między oknami i chciałam dołożyć tam dodatkową akcję, ale teraz widzę jakie to myślenie było bez sensu. Wyrzuciłam całkowicie tę funkcję :)
Tak, dokładnie. Z tym, że niektóre metody nadpisuję w innych klasach, bo chcę, zeby trochę inne rzeczy czasem robiły, ale generalnie one są zbliżone do siebie.
Poprawione.
W trakcie - czyli tak jakby ten fetchall w graf.py traktuje 'Bronowice' jako kolumnę i dlatego wsadza ją jako listę? Czyli to, ze tak zapisuje mi się do tablicy to jest wina fetchalla, a nie źle sformułowanego SELECTu?
Z find_shortest_path
poprawione. Indeksowanie w trakcie.
W trakcie
PS Dostałam kiedyś podobnie brzmiącą radę od pewnego muzyka, że własnie " Nie należy naprawiać tego co nie jest zepsute" i "Lepsze jest wrogiem dobrego" Dobrze brzmi po angielsku: "The Best Is The Enemy Of The Good"
```python
def f(g):
return g
cost
jest zbędne (a i tak przypisuje się do niego None
). To, że dwie metody mają podobne nazwy, rodzi zamieszanie. Ja bym get_ticket_costs()
przemianował np. na total_cost()
i oznaczył jako @property
, po czym tutaj napisał tak:
if choice in ("yes", "no"):
return self.total_cost
else:
return 0.0
W clear_costs_of_journey()
wyrzucić wyraz return
, co i tak zwracał None
. Wracam jeszcze do sprawy __journey_costs
, które nie powinny być inicjalizowane tak, jak teraz (wyrzucić), tylko przez
def __init__(self):
self.__journey_costs = []
Po zmienieniu ich inicjalizacji proszę jeszcze raz przeczytać w 3. rozdziale punkt o atrybutach klas i atrybutach instancji klas — może tym razem "zaskoczy".
.fetchall()
najlepiej zapomnieć.Swoje poprzednie wpisy w Issues może Pani edytować. Nie ucięło Pani ostatnich punktów, tylko je idiotycznie przenumerowało.
Przepraszam za to, że się dłużej nie odzywałam, ale uczyłam się do kolokwium z JS i piszę też inne projekty.
.fetchall()
działa bez zarzutów. Muszę jeszcze trochę kod zmienić,żeby się dobrze tworzył ten finalny graf.Dziękuję za wiadomość. Plik testy.py
proszę przemianować na MPK_test.py
i po uporaniu się z innymi przeróbkami dopisać do niego ze dwa testy funkcji find_shortest_path()
na jakimś prościutkim grafie.
Dzień dobry!
.fetchall()
.Jeszcze mam pytanie: Czy będąc u Pana w grupie należy przesłać projekt na elfa Panu Gąciarzowi, czy po prostu każdy z Panów ocenia swoje grupy?
Dzień dobry, dziękuję za wiadomości. Niedługo zrobię kolejną rundę oglądania Państwa programów. Co do projektu — proszę go przesłać na elf zgodnie z wytycznymi dra Gąciarza. Również jeśli to ja będę oceniał projekty z moich grup, jakiś ślad w elfie powinien pozostać.
Jest nieźle. Cieszę się, że Pani się nauczyła innego podejścia do wyciągania danych niż przez napisy do oskubania ze znaków. Tylko parę drobiazgów i będzie po wszystkim.
MPK.py
proszę posortować: json
< sqlite3
< tkinter
, a potem numpy
< PIL
.self
, albo być oznaczone jako @staticmethod
, inaczej nie zadziała.Dobry wieczór! Wszystko poprawione, dziękuję za wskazówki! :) Dzięki nim naprawdę bardziej podoba mi się ten projekt.
Mam jeszcze kilka drobnych pytań:
Przepraszam jeśli męczę, ale wolę pytać, żeby później nie mieć wątpliwości. Dobrej nocy!
Zaliczone! Gratuluję, jest Pani dwudziesta w kolejności.
Dziękuję pięknie! Bardzo się cieszę, szczególnie, że to mój pierwszy większy projekt. Pozdrawiam serdecznie :)
.vscode
wyrzucić (1. rozdział).import tkinter as tk
, albo (ekhm, ekhm)from tkinter import *
. Z używania przez Paniątk.Button
itp. wynika, że drugie można wyrzucić.snake_case
(2. rozdział).=
spacje w normalnym kodzie, ale nie przy przekazywaniu argumentów itp. Pylint chyba to wykrywa.butnew
,Win1
,getAns
itp. są niedobre (2. rozdział).{}
zamiastdict()
.Traveler
jest zmienny atrybut klasowyjourneyCosts
. Niedobrze (3. rozdział).Error
na samą górę.FULL_PRICE
iREDUCED_PRICE
.Traveler.ticketCosts
, jest nadmiarowe i mylące. Zamiast go rzucać i łapać, wystarczyelse:
.np.sum()
, robisum()
.command=self.combine_func(...)
.Win2
dziedziczy zWin1
(iWin3
zWin2
), a nie wywołuje konstruktora rodzica, to coś jest nie tak. Przypuszczam, że chce Pani zrobić klasęWindowBase
ze wspólnymi metodami, i z niej niech dziedzicząWin1
,Win2
iWin3
.('Courier', 12)
zrobić nazwaną stałą. PodobnieBACKGROUND = 'white'
iFOREGROUND = 'black'
.str(i)
. Jak wyglądają numery linii wczytane z bazy? W zależności od odpowiedzi, powinno się udać usunąć cudzysłowy przezint(line_number)
,line_number.strip('"')
albo coś podobnego.if line_number:
(puste kolekcje są fałszywe).', '.join(final_stops[::-1])
, czy jakoś tak.newdict
są wstawiane połączenia daną linią między parami sąsiednich przystanków — w porządku, tylko że z Pani maila zrozumiałem, że pamięta Pani połączenia daną linią między wszelkimi parami przystanków na tej linii;key
ivalues
lepsze będąline_number
istops
;values[i]
? czystr()
jest konieczne?first.translate(...)
, chodziło Pani np. ofirst.replace('[', '').replace(']', '')
albofirst.strip('[]')
;newdict[first].update({k: v})
lepsze będzienewdict[first][k] = v
.Win2
. Wyekstrahować (4. rozdział).graf.py
mimo jego jednorazowości wolałbym powsadzanie kodu do funkcji.pickle
(tutaj nie polecam, lepiej mieć czytelność). Z tym, że JSON-a całego zapisanego w jednym wierszu, tak jak jest teraz, czytać się nie da. Przypuszczam, że da się to naprawić parametremindent
dojson.dump()
.