Šajā rakstā jūs gatavojaties izveidot reizināšanas tabulu lietotni, izmantojot Python objektorientētās programmēšanas (OOP) jaudu.
Jūs praktizēsit galvenos OOP jēdzienus un to, kā tos izmantot pilnībā funkcionējošā lietojumprogrammā.
Python ir daudzparadigmu programmēšanas valoda, kas nozīmē, ka mēs kā izstrādātāji katrai situācijai un problēmai varam izvēlēties labāko variantu. Kad mēs runājam par objektorientētu programmēšanu, mēs runājam par vienu no pēdējās desmitgadēs visvairāk izmantotajām paradigmām mērogojamu lietojumprogrammu izveidei.
OOP pamati
Mēs ātri apskatīsim vissvarīgāko OOP jēdzienu Python, klasēs.
Klase ir veidne, kurā mēs definējam objektu struktūru un uzvedību. Šī veidne ļauj mums izveidot gadījumus, kas ir tikai atsevišķi objekti, kas izveidoti, ievērojot klases sastāvu.
Vienkārša grāmatu klase ar nosaukuma un krāsas atribūtiem būtu definēta šādi.
class Book: def __init__(self, title, color): self.title = title self.color = color
Ja mēs vēlamies izveidot klases grāmatas gadījumus, mums ir jāizsauc klase un jānodod tai argumenti.
# Instance objects of Book class blue_book = Book("The blue kid", "Blue") green_book = Book("The frog story", "Green")
Labs mūsu pašreizējās programmas attēlojums būtu:
Lieliski ir tas, ka, pārbaudot blue_book un green_book gadījumu veidu, mēs iegūstam “Book”.
# Printing the type of the books print(type(blue_book)) # <class '__main__.Book'> print(type(green_book)) # <class '__main__.Book'>
Kad šīs koncepcijas būs pilnīgi skaidras, mēs varam sākt veidot projektu 😃.
Projekta paziņojums
Strādājot par izstrādātājiem/programmētājiem, lielākā daļa laika netiek pavadīts koda rakstīšanai jaunumu kaudzīte mēs tikai trešdaļu sava laika pavadām, rakstot vai pārveidojot kodu.
Pārējās divas trešdaļas mēs pavadījām, lasot citu kodu un analizējot problēmu, pie kuras strādājam.
Tāpēc šim projektam es ģenerēšu problēmas izklāstu, un mēs analizēsim, kā no tā izveidot savu lietotni. Rezultātā mēs veicam visu procesu, sākot no risinājuma domāšanas un beidzot ar tā pielietošanu ar kodu.
Sākumskolas skolotājs vēlas spēli, lai pārbaudītu reizināšanas prasmes skolēniem vecumā no 8 līdz 10 gadiem.
Spēlei ir jābūt dzīvību un punktu sistēmai, kur skolēns sāk ar 3 dzīvībām un jāsasniedz noteikts punktu daudzums, lai uzvarētu. Programmai ir jāparāda ziņojums “zaudēt”, ja students noplicina visu savu dzīvi.
Spēlei jābūt diviem režīmiem, izlases reizināšanai un tabulas reizināšanai.
Pirmajam ir jādod skolēnam nejaušs reizinājums no 1 līdz 10, un viņam/viņai ir jāatbild pareizi, lai iegūtu punktu. Ja tas nenotiek, students zaudē dzīvu un spēle turpinās. Students uzvar tikai tad, kad viņš/viņš sasniedz 5 punktus.
Otrajā režīmā jāparāda reizināšanas tabula no 1 līdz 10, kur skolēnam jāievada attiecīgā reizināšanas rezultāts. Ja skolēns neizdodas 3 reizes, viņš/viņa zaudē, bet, ja viņš pabeidz divus galdus, spēle beidzas.
Zinu, ka prasības varbūt nedaudz lielākas, bet apsolu, ka šajā rakstā tās atrisināsim 😁.
Sadali un iekaro
Vissvarīgākā programmēšanas prasme ir problēmu risināšana. Tas ir tāpēc, ka pirms koda uzlaušanas jums ir nepieciešams plāns.
Es vienmēr iesaku ņemt lielāko problēmu un sadalīt to mazākās, kuras var viegli un efektīvi atrisināt.
Tātad, ja jums ir jāizveido spēle, sāciet ar to, sadalot to svarīgākajās tās daļās. Šīs apakšproblēmas būs daudz vieglāk atrisināt.
Tieši tad jums var būt skaidrība par to, kā visu izpildīt un integrēt ar kodu.
Tāpēc izveidosim grafiku, kā spēle izskatītos.
Šī grafika nosaka attiecības starp mūsu lietotnes objektiem. Kā redzat, divi galvenie objekti ir nejaušā reizināšana un tabulas reizināšana. Un vienīgais, ko viņi dala, ir atribūti Punkti un dzīvības.
Paturot prātā visu šo informāciju, iedziļināsimies kodā.
Vecāku spēles klases izveide
Strādājot ar objektorientētu programmēšanu, mēs meklējam tīrāko veidu, kā izvairīties no koda atkārtošanās. To sauc DRY (neatkārtojiet sevi).
Piezīme. Šis mērķis nav saistīts ar mazāka skaita koda rindiņu rakstīšanu (koda kvalitāti nedrīkst mērīt pēc šī aspekta), bet gan ar to, lai abstrahētu visbiežāk izmantoto loģiku.
Saskaņā ar iepriekšējo ideju mūsu lietojumprogrammas vecākajai klasei ir jānosaka pārējo divu klašu struktūra un vēlamā darbība.
Paskatīsimies, kā tas tiktu darīts.
class BaseGame: # Lenght which the message is centered message_lenght = 60 description = "" def __init__(self, points_to_win, n_lives=3): """Base game class Args: points_to_win (int): the points the game will need to be finished n_lives (int): The number of lives the student have. Defaults to 3. """ self.points_to_win = points_to_win self.points = 0 self.lives = n_lives def get_numeric_input(self, message=""): while True: # Get the user input user_input = input(message) # If the input is numeric, return it # If it isn't, print a message and repeat if user_input.isnumeric(): return int(user_input) else: print("The input must be a number") continue def print_welcome_message(self): print("PYTHON MULTIPLICATION GAME".center(self.message_lenght)) def print_lose_message(self): print("SORRY YOU LOST ALL OF YOUR LIVES".center(self.message_lenght)) def print_win_message(self): print(f"CONGRATULATION YOU REACHED {self.points}".center(self.message_lenght)) def print_current_lives(self): print(f"Currently you have {self.lives} livesn") def print_current_score(self): print(f"nYour score is {self.points}") def print_description(self): print("nn" + self.description.center(self.message_lenght) + "n") # Basic run method def run(self): self.print_welcome_message() self.print_description()
Oho, šī šķiet diezgan liela klase. Ļaujiet man to paskaidrot dziļi.
Vispirms sapratīsim klases atribūtus un konstruktoru.
Būtībā klases atribūti ir mainīgie, kas izveidoti klasē, bet ārpus konstruktora vai jebkuras metodes.
Lai gan gadījumu atribūti ir mainīgie, kas izveidoti tikai konstruktorā.
Galvenā atšķirība starp šiem diviem ir darbības joma. ti, klases atribūti ir pieejami gan no instances objekta, gan no klases. No otras puses, gadījumu atribūti ir pieejami tikai no instances objekta.
game = BaseGame(5) # Accessing game message lenght class attr from class print(game.message_lenght) # 60 # Accessing the message_lenght class attr from class print(BaseGame.message_lenght) # 60 # Accessing the points instance attr from instance print(game.points) # 0 # Accesing the points instance attribute from class print(BaseGame.points) # Attribute error
Citā rakstā var ienirt dziļāk šajā tēmā. Sazinieties, lai to izlasītu.
Funkcija get_numeric_input tiek izmantota, lai neļautu lietotājam sniegt jebkādu ievadi, kas nav ciparu. Kā jūs varat pamanīt, šī metode ir paredzēta, lai jautātu lietotājam, līdz tas saņem ciparu ievadi. Mēs to izmantosim vēlāk bērna nodarbībās.
Drukāšanas metodes ļauj mums saglabāt vienu un to pašu drukāšanas atkārtošanos katru reizi, kad spēlē notiek kāds notikums.
Pēdējais, bet ne mazāk svarīgi, palaišanas metode ir tikai iesaiņojums, ko nejaušās reizināšanas un tabulas reizināšanas klases izmantos, lai mijiedarbotos ar lietotāju un padarītu visu funkcionālu.
Bērna nodarbību veidošana
Kad esam izveidojuši šo vecākklasi, kas nosaka mūsu lietotnes struktūru un dažas funkcionalitātes, ir pienācis laiks izveidot faktiskās spēles režīmu klases, izmantojot mantošanas spēku.
Nejaušas reizināšanas klase
Šajā klasē darbosies mūsu spēles “pirmais režīms”. Tas, protams, izmantos izlases moduli, kas dos mums iespēju uzdot lietotājam nejaušās darbības no 1 līdz 10. Šeit ir lielisks raksts par nejaušajiem (un citiem svarīgiem moduļiem) 😉.
import random # Module for random operations
class RandomMultiplication(BaseGame): description = "In this game you must answer the random multiplication correctlynYou win if you reach 5 points, or lose if you lose all your lives" def __init__(self): # The numbers of points needed to win are 5 # Pass 5 "points_to_win" argument super().__init__(5) def get_random_numbers(self): first_number = random.randint(1, 10) second_number = random.randint(1, 10) return first_number, second_number def run(self): # Call the upper class to print the welcome messages super().run() while self.lives > 0 and self.points_to_win > self.points: # Gets two random numbers number1, number2 = self.get_random_numbers() operation = f"{number1} x {number2}: " # Asks the user to answer that operation # Prevent value errors user_answer = self.get_numeric_input(message=operation) if user_answer == number1 * number2: print("nYour answer is correctn") # Adds a point self.points += 1 else: print("nSorry, your answer is incorrectn") # Substracts a live self.lives -= 1 self.print_current_score() self.print_current_lives() # Only get executed when the game is finished # And none of the conditions are true else: # Prints the final message if self.points >= self.points_to_win: self.print_win_message() else: self.print_lose_message()
Šeit ir vēl viena liela nodarbība 😅. Bet, kā jau minēju iepriekš, tas nav nepieciešams rindu skaits, bet gan tas, cik tas ir lasāms un efektīvs. Un labākais Python ir tas, ka tas ļauj izstrādātājiem izveidot tīru un lasāmu kodu tā, it kā viņi runātu parastā angļu valodā.
Šajā klasē ir viena lieta, kas var jūs mulsināt, taču es to paskaidrošu pēc iespējas vienkāršāk.
# Parent class def __init__(self, points_to_win, n_lives=3): "... # Child class def __init__(self): # The numbers of points needed to win are 5 # Pass 5 "points_to_win" argument super().__init__(5)
Bērna klases konstruktors izsauc superfunkciju, kas tajā pašā laikā attiecas uz vecāku (BaseGame) klasi. Tas būtībā stāsta Python:
Aizpildiet vecākklases atribūtu “points_to_win” ar 5!
Nav nepieciešams super().__init__() daļā ievietot sevi tikai tāpēc, ka konstruktorā mēs izsaucam super, un tas radītu lieku.
Mēs arī izmantojam superfunkciju palaišanas metodē, un mēs redzēsim, kas notiek šajā koda daļā.
# Basic run method # Parent method def run(self): self.print_welcome_message() self.print_description() def run(self): # Call the upper class to print the welcome messages super().run() .....
Tā kā, iespējams, pamanīsit palaišanas metodi vecākklasē, izdrukājiet sveiciena un apraksta ziņojumu. Taču ir ieteicams saglabāt šo funkcionalitāti un pievienot papildu funkcijas bērnu klasēs. Saskaņā ar to mēs izmantojam super, lai palaistu visu vecākmetodes kodu pirms nākamās daļas palaišanas.
Otra palaišanas funkcijas daļa ir diezgan vienkārša. Tā pieprasa lietotājam numuru ar ziņojumu par operāciju, uz kuru viņam/viņai ir jāatbild. Tad rezultātu salīdzina ar reālo reizinājumu un, ja tie ir vienādi, pieliek punktu, ja nenoņem 1 dzīvību.
Ir vērts teikt, ka mēs izmantojam while-else cilpas. Tas pārsniedz šī raksta darbības jomu, bet es par to publicēšu pēc dažām dienām.
Visbeidzot, get_random_numbers izmanto funkciju random.randint, kas atgriež nejaušu veselu skaitli norādītajā diapazonā. Tad tas atgriež divu nejaušu veselu skaitļu kopu.
Nejaušas reizināšanas klase
“Otrajam režīmam” ir jāparāda spēle reizināšanas tabulas formātā un jāpārliecinās, ka lietotājs pareizi atbild vismaz uz 2 tabulām.
Šim nolūkam mēs atkal izmantosim super jaudu un mainīsim vecāku klases atribūtu point_to_win uz 2.
class TableMultiplication(BaseGame): description = "In this game you must resolve the complete multiplication table correctlynYou win if you solve 2 tables" def __init__(self): # Needs to complete 2 tables to win super().__init__(2) def run(self): # Print welcome messages super().run() while self.lives > 0 and self.points_to_win > self.points: # Gets two random numbers number = random.randint(1, 10) for i in range(1, 11): if self.lives <= 0: # Ensure that the game can't continue # if the user depletes the lives self.points = 0 break operation = f"{number} x {i}: " user_answer = self.get_numeric_input(message=operation) if user_answer == number * i: print("Great! Your answer is correct") else: print("Sorry your answer isn't correct") self.lives -= 1 self.points += 1 # Only get executed when the game is finished # And none of the conditions are true else: # Prints the final message if self.points >= self.points_to_win: self.print_win_message() else: self.print_lose_message()
Kā jūs saprotat, mēs tikai modificējam šīs klases palaišanas metodi. Tā ir mantojuma maģija, mēs rakstām loģiku, ko lietojam vairākās vietās, un aizmirstam par to 😅.
Izpildes metodē mēs izmantojam for cilpu, lai iegūtu skaitļus no 1 līdz 10, un izveidojam operāciju, kas tiek parādīta lietotājam.
Atkal, ja dzīvības ir izsmeltas vai ir sasniegti uzvarai nepieciešamie punkti, kamēr cilpa pārtrūks un tiks parādīts uzvaras vai zaudējuma ziņojums.
JĀ, mēs izveidojām divus spēles režīmus, taču līdz šim, palaižot programmu, nekas nenotiks.
Tātad, pabeigsim programmu, ieviešot režīma izvēli un veidojot nodarbības atkarībā no šīs izvēles.
Izvēles īstenošana
Lietotājs varēs izvēlēties, kādu režīmu vēlas spēlēt. Tātad, redzēsim, kā to īstenot.
if __name__ == "__main__": print("Select Game mode") choice = input("[1],[2]: ") if choice == "1": game = RandomMultiplication() elif choice == "2": game = TableMultiplication() else: print("Please, select a valid game mode") exit() game.run()
Pirmkārt, mēs lūdzam lietotāju izvēlēties 1 vai 2 režīmus. Ja ievade nav derīga, skripts tiek pārtraukts. Ja lietotājs izvēlas pirmo režīmu, programma palaidīs nejaušās reizināšanas spēles režīmu, un, ja viņš izvēlēsies otro, tiks palaists tabulas reizināšanas režīms.
Lūk, kā tas izskatītos.
Secinājums
Apsveicu, jūs vienkārši izveidot Python lietotni ar objektorientētu programmēšanu.
Viss kods ir pieejams vietnē Github repozitorijs.
Šajā rakstā jūs uzzinājāt:
- Izmantojiet Python klases konstruktorus
- Izveidojiet funkcionālu lietotni ar OOP
- Izmantojiet superfunkciju Python klasēs
- Pielietojiet mantojuma pamatjēdzienus
- Ieviest klases un instances atribūtus
Laimīgu kodēšanu 👨💻
Pēc tam izpētiet dažus no labākajiem Python IDE, lai uzlabotu produktivitāti.