Próba przekszałcenie kodu proceduralnego w typowo obiektowy

Próba przekszałcenie kodu proceduralnego w typowo obiektowy
P7
  • Rejestracja:ponad 3 lata
  • Ostatnio:ponad 2 lata
  • Postów:75
0

Witam ponownie . Zacząłem się bawić w obiektówkę . Przykładowo mam kod proceduralny z liczeniem wieku :

Kopiuj
import datetime

def pobierz_imie():
    return input('podaj imie: ')

def pobierz_rok_urodzenia():
    return int(input('podaj rok urodzenia: '))

def policz_ile_lat(rok_urodzenia, aktualny_rok):
    return aktualny_rok - rok_urodzenia

def odpowiedz_uzytkownikowi(imie, wiek):
    print(f'Czesc {imie}! Masz {wiek} lat.')

while True:
    imie = pobierz_imie()
    rok_urodzenia = pobierz_rok_urodzenia()
    aktualny_rok = datetime.datetime.now().year
    wiek = policz_ile_lat(rok_urodzenia, aktualny_rok)
    odpowiedz_uzytkownikowi(imie, wiek)

Kod w obiektówce:

Kopiuj
import datetime

class Dane:
    def __init__(self):
        self.imie = self.Pobierz_imie   #konstruktor/  - powinno być self.imie = imie /jak takzrobię mam bład
        self.rok_urodzenia = self.pobierz_rok_urodzenia()
        self.aktualny_rok = datetime.datetime.now().year
        self.wiek = self.policz_ile_lat(self.rok_urodzenia, self.aktualny_rok)
        self.odpowiedz_uzytkownikowi(self.imie, self.wiek)

    def Pobierz_imie(self):
        return input('Podaj imie: ')

    def pobierz_rok_urodzenia(self):
        return int(input('podaj rok urodzenia: '))
        

    def policz_ile_lat(self,rok_urodzenia, aktualny_rok):
        return self.aktualny_rok - self.rok_urodzenia

    def odpowiedz_uzytkownikowi(self,imie,wiek):
        print(f'Czesc {self.imie}! Masz {self.wiek} lat.')

    def wyswietl(self):
      #print(self.Pobierz_imie,self.pobierz_rok_urodzenia,self.odpowiedz_uzytkownikowi,self.policz_ile_lat)
      print(self.imie,self.aktualny_rok,self.rok_urodzenia,self.wiek)
      

dane1 = Dane()
dane1.wyswietl()

I ten program próbuję przekształcić w typową obiektówkę... Niby wynik obliczenia wieku mi wychodzi (z błedami) , ale nie mam pytania o imie, żebym podał.... Tylko od razu pytanie o rok urodzenia... Czy w konstruktorze klasy dobrze dodałem te wszystkie "dane"? Powinno być self.imie = imie, self.rok_urodzenia = rok_urodzenia itp..., a zrobiłem trochę inaczej ! Czy jest możliwość całkowitego przerobienia tego programu w typową "obiektówkę" Ogólnie czy dobrze kombinuję, jeśli chodzi o przerobienie tego kodu na obiektówkę? Chętnie bym zobaczył prawidlowy kod obiektowy według was, zebym sobie porównał lub wskazówki co robię zle. Pozdrawiam

OR
OR
  • Rejestracja:ponad 3 lata
  • Ostatnio:prawie 3 lata
  • Postów:6
2

W konstruktorze powinno być self.imie = self.Pobierz_imie(), dlatego od razu pyta o rok urodzenia.
Generalnie to rozdziela się pobieranie danych od obiektów na których pracujesz, a dane umieszczasz w obiekcie przekazując je przez konstruktor np.

Kopiuj
import datetime


class Dane:
    def __init__(self, imie, rok_urodzenia):
        self.imie = imie
        self.rok_urodzenia = rok_urodzenia
        self.aktualny_rok = datetime.datetime.now().year
        self.wiek = self.policz_ile_lat()
        self.odpowiedz_uzytkownikowi(self.imie, self.wiek)

    def policz_ile_lat(self):
        return self.aktualny_rok - self.rok_urodzenia

    def odpowiedz_uzytkownikowi(self):
        print(f'Czesc {self.imie}! Masz {self.wiek} lat.')

    def wyswietl(self):
        print(self.imie, self.aktualny_rok, self.rok_urodzenia, self.wiek)


def Pobierz_imie():
    return input('Podaj imie: ')


def pobierz_rok_urodzenia():
    return int(input('podaj rok urodzenia: '))


pobrane_imie = Pobierz_imie()
pobrany_rok = pobierz_rok_urodzenia()

dane1 = Dane(pobrane_imie, pobrany_rok) # można też dać Dane(rok_urodzenia=pobrany_rok, imie=pobrane_imie) wtedy kolejność parametrów nie ma znaczenia
dane1.wyswietl()

Nie musisz też przekazywać zmiennych to funkcji wewnątrz klasy jak np. w twoim policz_ile_lat. Ustawiasz wartości dla rok_urodzenia i aktualny_rok w konstruktorze, a potem możesz się odwołać do nich przez self.rok_urodzenia i będzie tam dokładnie to co ustawiłeś.

ledi12
  • Rejestracja:ponad 5 lat
  • Ostatnio:22 dni
  • Lokalizacja:Wrocław
1

Ja bym te inputy wyrzucil poza klase i przekazywal jako atrybut do obiektu, cos jak kolega up ;)


Robię http response status cody w martwych ciągach
edytowany 1x, ostatnio: ledi12
vpiotr
  • Rejestracja:ponad 13 lat
  • Ostatnio:prawie 3 lata
3

Ja bym nie dodawał pola aktualny_rok - to powinno sie liczyc na bieżąco.

ledi12
Aż się prosi zrobić z tego @staticmethod :D
LukeJL
  • Rejestracja:około 11 lat
  • Ostatnio:minuta
  • Postów:8403
0

Niespójność: napisałeś metodę Pobierz_imie(self) nie wiadomo dlaczego z dużej litery (później autocomplete rozumiem, że umocniło ten błąd. Czy raczej nie tyle błąd, bo to jest technicznie poprawne, tylko niespójność stylu).


edytowany 1x, ostatnio: LukeJL
Arthan
  • Rejestracja:prawie 18 lat
  • Ostatnio:ponad rok
1

Ja bym sobie kod podzielił na klasę "ludka" i klasę odpowiadającą za komunikację z użytkownikiem. Klasy w osobnych plikach. Aktualny rok dałbym jako metodę prywatną, albo property nie widoczne za weznątrz. Wiek wystawione jako property readonly. Wyświetlanie obiektu poprzez __str__. Do obiektu osoby dopisałbym testy liczenia wieku. Komunikację rozszerzył o logi. Brakuje też zabezpieczeń przed niewłaściwymi danymi.

osoby.py:

Kopiuj
from datetime import datetime

class Osoba:
    def __init__(self, imie=None, rok_urodzenia=None):
        self.imie = imie
        self.rok_urodzenia = rok_urodzenia

    @property
    def __aktualny_rok(self):
        return datetime.now().year

    @property
    def wiek(self):
        if not self.rok_urodzenia: return None
        return self.__aktualny_rok - self.rok_urodzenia

    def __str__(self):
        return f'{self.imie} {self.__aktualny_rok} {self.rok_urodzenia} {self.wiek}'

komunikacja.py:

Kopiuj
class Komunikacja:
    def pobierz_imie(self):
        return input('Podaj imie: ')

    def pobierz_rok_urodzenia(self):
        return int(input('podaj rok urodzenia: '))

    def odpowiedz_uzytkownikowi(self, osoba):
        print(f'Cześć {osoba.imie}! Masz {osoba.wiek} lat.')

main.py:

Kopiuj
from osoba import Osoba
from komunikacja import Komunikacja

def main():
    komunikacja = Komunikacja()
    osoba = Osoba()
    osoba.imie = komunikacja.pobierz_imie()
    osoba.rok_urodzenia = komunikacja.pobierz_rok_urodzenia()
    print(osoba)
    komunikacja.odpowiedz_uzytkownikowi(osoba)
    
if __name__ == '__main__':
    main()
P7
  • Rejestracja:ponad 3 lata
  • Ostatnio:ponad 2 lata
  • Postów:75
0

Dzięki Wam wszystkim za pomocne informacje....

@Arthan Jeśi chodzi o zabezpiecznie danych przed nieprawidłową odpowiedzią , czy mogę tu w klasach zastosować tzw. wyjątki tzn:

Kopiuj
def pobierz_rok_urodzenia(self):
        while True: 
            try:
                return int(input('podaj rok urodzenia: '))
            except ValueError:
                print('Wpisałeś złą wartosć, wpisz liczbę jeszcze raz')

Z wyjatkiem kod działa, tylko czy mogę to w klasach stosować?. Chodzi mi o poprawność kodu w obiektówce. Tzw while , for to tu się w obiektówce stosuje podobnie jak w proceduralnym kodzie? , co do testów, logów , może pokombinuję (choć nie wiem do konca o co chodzi tu ), co do property to wiedzę sobie uzupełnię na ten temat

OR
OR
  • Rejestracja:ponad 3 lata
  • Ostatnio:prawie 3 lata
  • Postów:6
2

Generalnie założyłbym, że możesz robić w klasach wszystko, co do tej pory robiłeś. Obiekty służą tylko po to, żeby opakować dane w wygodne pudełka i zdefiniować operacje, które można na nich wykonywać.

Arthan
  • Rejestracja:prawie 18 lat
  • Ostatnio:ponad rok
2

Tak jak napisał @ObywatelRP. Kiedy pudełka są wygodne? Wtedy kiedy poszczególne pudełko odpowiada za pojedynczą funkcjonalność, a nie że obiekt Pralka zmywa naczynia (a niekiedy nawet służy do gotowania). Pudełko takie powinno też udostępniać w miarę wygodny interfejs i bronić dostępu do niektórych części wewnętrznych, do których nie powinno być takiego dostępu z zewnątrz (hermetyzacja).

Wracając jeszcze do pobierania roku, zamiast przechwytywać wyjątek możesz tak napisać program by do niego tu nie dochodziło. Czy użytkownik podał poprawną liczbę możesz sprawdzić używając .isdigit(), do tego przydałoby się sprawdzanie czy liczba jest w jakimś sensownym zakresie, np. większa od 1900 i mniejsza niż obecny rok. Ja tam nie lubię używać pętli gdy nie muszę, dlatego tu zamiast while dałbym rekurencję przy niepowodzeniu.

Tu masz przykład prostych testów:

Kopiuj
import unittest
from osoba import Osoba

class TestOsoba(unittest.TestCase):
    def setUp(self):
        self.osoba = Osoba()

    def test_rok_urodzenia_niepodany(self):
        self.assertIsNone(self.osoba.wiek)
        
    def test_rok_urodzenia_2000(self):
        self.osoba.rok_urodzenia = 2000
        self.assertEqual(self.osoba.wiek, 21)

if __name__ == '__main__':
    unittest.main()

Odpalasz ten plik jako osobny program, te testy są trochę słabe bo za miesiąc przestaną działać, ale masz jakiś przykład ;)

ledi12
Testy!? Ja ufam dla swojego kodu! :DD
Arthan
Ja też testów prawie nigdy nie piszę, chyba że zespół mnie zmusi :P Potem czasami bez nich boli :) Testy są nieocenione przy wprowadzaniu zmian w dużych programach. Poza tym testy są czasami dobrymi przykładami zastosowania, nie mówiąc o tym, że istnieje coś takiego jak TDD :)
ledi12
Nie no śmieszkuje sobie :P
Arthan
Ja wiem, ale jeszcze ktoś w to uwierzy i będziesz miał czyjeś zdrowie psychiczne na sumieniu :D
ledi12
I potem będzie: "A bo taki jeden typ na 4p mi powiedział!" :D
P7
  • Rejestracja:ponad 3 lata
  • Ostatnio:ponad 2 lata
  • Postów:75
0

Dzięki za info, wskazówki.... W wolnej chwili posprawdzam co i jak.... Tak się ostatnio zastanawiałem nad bootcampem python ( dostaję od nich zaproszenie na szkolenia online/stacjonarne) , trochę to kosztuje.... Ale jednak wolę iść samemu w naukę, online, ksiązki , fora... Po pierwsze szkoda mi kasy na to ( jak sam mogę wiedzę zdobyć) ale za to więcej wysiłku i czasu mi to zajmnie, bo nie mam nauczyciela który by poprawiał moje błedy w programowaniu. Czasowo dłużej nauka mi zajmnie jak się domyślam. Druga sprawa to czas, którego za bardzo nie mam i bym się musiał dostosować do rytmu szkolenia takiego. A u mnie z tym byłoby krucho. Na razie kupiłem cienką książkę z przykładami ćwiczeń , zadaniami, i wytłumaczeniami jak co działa. Po trochu coś tam zdziałam dla siebie. A po trzecie wolę wydać kasę na jakieś ebooki, filmiki instruktażowe itp...., niż ponad 10 K za szkolenia z którymi jestem uwiązany czasowo. Opinie na temat bootcampów są zróżnicowane w sieci. . Pozdrawiam

Arthan
a idź Pan :P Niedoceniasz Nas... My Cię tu szkolimy, tłumaczymy teorię z przykładami, wskazujemy błędy, wyjaśniamy co i jak, pokazujemy dobre praktyki i ani złotówki nie widzimy za nasze wysiłki. Chcesz 10K dać obcym ludziom, którzy obiecują że znajdziesz pracę po ich kursie do zawodu, w którym na juniora potrzebne jest 3 lata doświadczenia, a kolegom z 4P nie dasz ani złotówki? :P Idę stąd ... bootcampa se stworzę.
P7
:) Naprawdę doceniam Was ) Po prostu reklamami bootcampu jestem "atakowany" he he he... Ale jak poczytałem opinie na temat bootcampów to dałem sobie spokój, no i tak duża kaassaaa na to potrzeba... A tak poważnie, dziękuję Wam za wszelką pomoc, a także za krytykę, swoje zdanie o moich postępach :)
P7
  • Rejestracja:ponad 3 lata
  • Ostatnio:ponad 2 lata
  • Postów:75
0

@ObywatelRP: Własnie analizuję kod, uruchamia się z błedem.
W klasie Dane na końcu powinno być bez argumentów: self.imie , self wiek tzn:

Kopiuj
 self.odpowiedz_uzytkownikowi()

choć jak tej funkcji w ogóle nie podam , to kod też się wywołuje poprawnie.
Grunt , ze kod się uruchamia :) A tak z ciekawośći, dlaczego dwie ostatnie funkcje w kodzie są akapitami różne? Tak sobie porównuję do innych kodów.

Kopiuj
  
      def wyswietl(self):
        print(self.imie, self.aktualny_rok, self.rok_urodzenia, self.wiek)

def Pobierz_imie():
        return input('Podaj imie: ')

def pobierz_rok_urodzenia():
        return int(input('podaj rok urodzenia: '))
edytowany 1x, ostatnio: pythonowiec74
OR
OR
  • Rejestracja:ponad 3 lata
  • Ostatnio:prawie 3 lata
  • Postów:6
1

Generalnie, to może zacznijmy od tego, że python to taki śmieszny język, gdzie wcięcia służą do definiowania bloków kodu

Kopiuj
def test_indent():
    if False:
        print("To się nie wyświetli")
        print("To też się nie wyświetli")
    print("A to już, tak bo jest inne wcięcie")

test_indent()

Tak samo jest z klasami

Kopiuj
class Clazz:
    def method_in_class(self):
        print("method")

    def method2_in_class(self):
        print("method 2")

def method3_not_in_class(self):
    print("method 3")


clazz = Clazz()
clazz.method_in_class()
clazz.method2_in_class()
clazz.method3_not_in_class() # error

Nie chciałem, żeby metody pobierające dane były w klasie, która na nich operuje, więc nie są na tym samym poziomie wcięcia . Popatrz na kod, który dał ci @Arthan na poprzedniej stronie, Klasa osoba ma tylko metody służące do operowania na danych, które dostaje, a cała reszta, czyli pobieranie danych jest w klasie Komunikacja. U mnie też można by dać je w osobnej klasie, ale jestem leniwy i nie chciało mi się tego pisać, więc dałem tylko inne wcięcie żeby zaznaczyć, że te metody nie powinny tam być.

P7
  • Rejestracja:ponad 3 lata
  • Ostatnio:ponad 2 lata
  • Postów:75
0

@ObywatelRP: Dzięki za info. Dla testów dałem to w osobnej klasie (inny plik) , działa bez problemu :)

Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)