Funkcijos
Sąvoką funkciją turėjote matyti iki šio momento daug kartų. Šį kartą būsime jų kūrėjai ir išsiaiškinsime, kaip jos veikia viduje.
Anksčiau funkciją naudojome, kaip juodą dėžę:
Čia x laikykime, kaip visumą argumentų, kuriuos rašėme į funkciją. Juoda dėžė tai funkcijos kodo eilutės, sakiniai, kurių kviesdami mes nematėme. Išvestis y yra tas rezultatas, kurį gaudavome iškvietę funkciją (kartais grąžinamos reikšmės gali nebūti, pvz. print()). Mūsų užduotis - išmokti kurti tą juodą dėžę.
Dar galima funkciją įsivaizduoti, kaip mašiną, įrenginį gamykloje, kuriai vienoje vietoje duodami kažkokios tai žaliavos, o tos mašinos kitoje pusėje gaunami pabaigtas produktas. Tas grąžinimas yra tarsi galutinio produkto atkeliavimas konvejerio juosta.
Tic-tac-toe perdarymas
Temoje „ciklas cikle“ turėjote padaryti tic-tac-toe žaidimą. Pabandysime keletą vietų perdaryti su funkcijomis. Pasiruoškite analizuotį didelį kiekį kodo.
# 3x3 Tic-Tac-Toe board
board = [
[' ', ' ', ' '],
[' ', ' ', ' '],
[' ', ' ', ' ']
]
game_running=True
print("-"*25)
print("Tic-Tac-Toe @ Vilijus")
print("-"*25)
print("Rules:")
print("1. First player is defined as P1 and he places \"X\" on the board;")
print("2. Second player is defined as P2 and he places \"O\" on the board;")
print("3. Enter coordinates in the format \"X,Y\"; for example, \"1,2\" - this represents the first row and the second column.")
print("="*50)
print("")
print("Game Board:")
print("-"*13)
for row in board:
for cell in row:
print(f"| {cell} ", end="")
print("|")
print("-"*13)
print()
moves=0
while true:
# Game winning condition
winners_status = ["", "", "", ""]
# Player 1 input processing
P1_input_ok = False
while not P1_input_ok:
P1_input = input("Enter P1 (X) move: ")
P1_input_split = P1_input.split(",")
if(len(P1_input_split) != 2):
print("Invalid coordinates entered!")
continue
P1_x = int(P1_input_split[0])
P1_y = int(P1_input_split[1])
if(not (1 <= P1_x <= 3 and 1 <= P1_y <= 3)):
print("Coordinates are outside the board!")
continue
if(board[P1_x-1][P1_y-1] != ' '):
print("Cell is occupied!")
continue
board[P1_x-1][P1_y-1] = "X"
P1_input_ok = True
moves=moves+1
# Check rows
for row in board:
if row[0] == row[1] == row[2] and row[0] != ' ':
winners_status[0]=row[0]
# Check columns
for col in range(3):
if board[0][col] == board[1][col] == board[2][col] and board[0][col] != ' ':
winners_status[1]=board[0][col]
# Check diagonals
if board[0][0] == board[1][1] == board[2][2] and board[0][0] != ' ':
winners_status[2]=board[0][0] # Return the winning symbol (X or O)
if board[0][2] == board[1][1] == board[2][0] and board[0][2] != ' ':
winners_status[3]=board[0][2] # Return the winning symbol (X or O)
if("X" in winners_status):
print("Player 1 won the game")
print("Congratulations!!!")
break
if(moves >= 9):
print("No more moves left; the game is ended.")
break
# Player 2 input processing
P2_input_ok = False
while not P2_input_ok and 4:
P2_input = input("Enter P2 (0) move: ")
P2_input_split = P2_input.split(",")
if(len(P2_input_split) != 2):
print("Invalid coordinates entered!")
continue
P2_x = int(P2_input_split[0])
P2_y = int(P2_input_split[1])
if(not (1 <= P2_x <= 3 and 1 <= P2_y <= 3)):
print("Coordinates are outside the board!")
continue
if(board[P2_x-1][P2_y-1] != ' '):
print("Cell is occupied!")
continue
board[P2_x-1][P2_y-1] = "0"
P2_input_ok = True
# Game board drawing
print("\nGame Board:")
print("-"*13)
for row in board:
for cell in row:
print(f"| {cell} ", end="")
print("|")
print("-"*13)
print()
# Check rows
for row in board:
if row[0] == row[1] == row[2] and row[0] != ' ':
winners_status[0]=row[0]
# Check columns
for col in range(3):
if board[0][col] == board[1][col] == board[2][col] and board[0][col] != ' ':
winners_status[1]=board[0][col]
# Check diagonals
if board[0][0] == board[1][1] == board[2][2] and board[0][0] != ' ':
winners_status[2]=board[0][0] # Return the winning symbol (X or O)
if board[0][2] == board[1][1] == board[2][0] and board[0][2] != ' ':
winners_status[3]=board[0][2] # Return the winning symbol (X or O)
if("0" in winners_status):
print("Player 2 won the game")
print("Congratulations!!!")
break
Pažymėtos eilutės (21-27 ir 70-78) veikia taip pat. Programavime tokius pat veiksmus mums reikia atlikinėti dažnai. Kad nereiktų perrašinėti kodo, kuris veikia taip pat, programuotojai kuria funkcijas. Kol kas mes funkcijas kvietėme, bet dar nesusitikome jų aprašymų.
Pagrindiniai funkcijų principai:
- Funkcija gali grąžinti (funkcijos kvietimą galima panaudoti, kaip reikšmę) reikšmę, pvz.:
sum(),avg(),len(); - Funkcija gali negrąžinti reikšmės, o tik atlikti veiksmus, pvz.:
print(); - Funkcija turi būti aprašyta anksčiau (aukščiau), negu ji iškviečiama (panaudojama);
- Funkcija gali turėti parametrus (tai, ką galima įrašyti į skliausteliius) arba gali neturėti;
- Funkcija turėtų būti sukurta vienai paskirčiai.
Kad galėtume kurti funkcijas dar reikia pasiaiškinti pagrindines sintaksės dalis:
# - "def" is a keyword that is always required to define a function.
# - "my_function" is the function name that will be used to call it.
# It is best to name the function based on its functionality.
# - "parameter1" is the first parameter.
# - "parameter2" is the second parameter.
# Lines that are indented from the function header make up the function body.
# "return 10" means that the function returns the value 10.
def my_function(parameter1, parameter2):
print(f"My parameters: {parameter1}, {parameter2}")
return 10
my_number = my_function(1, 2)
print(f"Function 'my_function' returned: {my_number}")
Eilutės nuo 9-11 yra funkcija, kuri iškviečiama 13-14 eilutėse. Funkcija visada prasideda raktažodžiu def, o po jas seka funkcijos pavadinimas ir skliausteliuose parametrai. Toliau funkcijoje (atitraukus nuo kairės) rašomi funkcijos sakiniai. Funkcija baigiasi paskutine atitraukta eilute arba return raktažodžiu.
Grįžkime prie kodo perdarymo. Perkelkime žaidimo lentos paišymo kodą:
def draw_board():
print("\nGame Board:")
print("-"*13)
for row in board:
for cell in row:
print(f"| {cell} ", end="")
print("|")
print("-"*13)
print()
# 3x3 Tic-Tac-Toe board
board = [
[' ', ' ', ' '],
[' ', ' ', ' '],
[' ', ' ', ' ']
]
game_running=True
print("-"*25)
print("Tic-Tac-Toe @ Vilijus")
print("-"*25)
print("Rules:")
print("1. First player is defined as P1 and he places \"X\" on the board;")
print("2. Second player is defined as P2 and he places \"O\" on the board;")
print("3. Enter coordinates in the format \"X,Y\"; for example, \"1,2\" - this represents the first row and the second column.")
print("="*50)
draw_board()
moves=0
while game_running:
# Game winning condition
winners_status = ["", "", "", ""]
# Player 1 input processing
P1_input_ok = False
while not P1_input_ok:
P1_input = input("Enter P1 (X) move: ")
P1_input_split = P1_input.split(",")
if(len(P1_input_split) != 2):
print("Invalid coordinates entered! Please enter in the format x,y.")
continue
P1_x = int(P1_input_split[0])
P1_y = int(P1_input_split[1])
if(not (1 <= P1_x <= 3 and 1 <= P1_y <= 3)):
print("Coordinates are outside the board! Please enter values between 1 and 3.")
continue
if(board[P1_x-1][P1_y-1] != ' '):
print("Cell is occupied! Please choose another cell.")
continue
board[P1_x-1][P1_y-1] = "X"
P1_input_ok = True
moves=moves+1
# Check rows
for row in board:
if row[0] == row[1] == row[2] and row[0] != ' ':
winners_status[0]=row[0]
# Check columns
for col in range(3):
if board[0][col] == board[1][col] == board[2][col] and board[0][col] != ' ':
winners_status[1]=board[0][col]
# Check diagonals
if board[0][0] == board[1][1] == board[2][2] and board[0][0] != ' ':
winners_status[2]=board[0][0] # Return the winning symbol (X or O)
if board[0][2] == board[1][1] == board[2][0] and board[0][2] != ' ':
winners_status[3]=board[0][2] # Return the winning symbol (X or O)
if("X" in winners_status):
print("Player 1 won the game")
print("Congratulations!!!")
break
if(moves >= 9):
print("No more moves left; the game is ended.")
break
# Player 2 input processing
P2_input_ok = False
while not P2_input_ok and 4:
P2_input = input("Enter P2 (0) move: ")
P2_input_split = P2_input.split(",")
if(len(P2_input_split) != 2):
print("Invalid coordinates entered! Please enter in the format x,y.")
continue
P2_x = int(P2_input_split[0])
P2_y = int(P2_input_split[1])
if(not (1 <= P2_x <= 3 and 1 <= P2_y <= 3)):
print("Coordinates are outside the board! Please enter values between 1 and 3.")
continue
if(board[P2_x-1][P2_y-1] != ' '):
print("Cell is occupied! Please choose another cell.")
continue
board[P2_x-1][P2_y-1] = "0"
P2_input_ok = True
moves=moves+1
# Game board drawing
draw_board()
# Check rows
for row in board:
if row[0] == row[1] == row[2] and row[0] != ' ':
winners_status[0]=row[0]
# Check columns
for col in range(3):
if board[0][col] == board[1][col] == board[2][col] and board[0][col] != ' ':
winners_status[1]=board[0][col]
# Check diagonals
if board[0][0] == board[1][1] == board[2][2] and board[0][0] != ' ':
winners_status[2]=board[0][0] # Return the winning symbol (X or O)
if board[0][2] == board[1][1] == board[2][0] and board[0][2] != ' ':
winners_status[3]=board[0][2] # Return the winning symbol (X or O)
if("0" in winners_status):
print("Player 2 won the game")
print("Congratulations!!!")
break
Nuo 1 iki 9 eilutės sukūrėme funkciją, kurios pavadinimas draw_board(), ji neturi jokių parametrų. 29 ir 73 eilutėje ją iškviesdami panaudojame.
Taip išvengėme pakartojimų ir jeigu norėsime pakeisti lentos piešimą, tą reikės padaryti tik vienoje vietoje, anksčiau būtų reikėję pakeisti dvi kodo vietas.
Šiame kode yra dar panašių vietų, kurias galėtume perdaryti su funkcijomis:
# ...
# Player 1 input processing
P1_input_ok = False
while not P1_input_ok:
P1_input = input("Enter P1 (X) move: ")
P1_input_split = P1_input.split(",")
if(len(P1_input_split) != 2):
print("Invalid coordinates entered! Please enter in the format x,y.")
continue
P1_x = int(P1_input_split[0])
P1_y = int(P1_input_split[1])
if(not (1 <= P1_x <= 3 and 1 <= P1_y <= 3)):
print("Coordinates are outside the board! Please enter values between 1 and 3.")
continue
if(board[P1_x-1][P1_y-1] != ' '):
print("Cell is occupied! Please choose another cell.")
continue
board[P1_x-1][P1_y-1] = "X"
P1_input_ok = True
# Player 2 input processing
P2_input_ok = False
while not P2_input_ok and 4:
P2_input = input("Enter P2 (0) move: ")
P2_input_split = P2_input.split(",")
if(len(P2_input_split) != 2):
print("Invalid coordinates entered! Please enter in the format x,y.")
continue
P2_x = int(P2_input_split[0])
P2_y = int(P2_input_split[1])
if(not (1 <= P2_x <= 3 and 1 <= P2_y <= 3)):
print("Coordinates are outside the board! Please enter values between 1 and 3.")
continue
if(board[P2_x-1][P2_y-1] != ' '):
print("Cell is occupied! Please choose another cell.")
continue
board[P2_x-1][P2_y-1] = "0"
P2_input_ok = True
# ...
Iš esmės šie du blokai atlieka vienodos veiksmus, tik vienu atveju tai padaroma su pirmuoju žaidėju, kitu su antruoju. Galima padaryti bendrą funkcija:
def draw_board():
print("\nGame Board:")
print("-"*13)
for row in board:
for cell in row:
print(f"| {cell} ", end="")
print("|")
print("-"*13)
print()
def process_player_input(player_symbol, board):
while True:
player_input = input(f"Enter {player_symbol} move (format: x,y): ")
input_split = player_input.split(",")
if len(input_split) != 2:
print("Invalid coordinates entered! Please enter in the format x,y.")
continue
x = int(input_split[0])
y = int(input_split[1])
if not (1 <= x <= 3 and 1 <= y <= 3):
print("Coordinates are outside the board! Please enter values between 1 and 3.")
continue
if board[x-1][y-1] != ' ':
print("Cell is occupied! Please choose another cell.")
continue
return x,y
# 3x3 Tic-Tac-Toe board
board = [
[' ', ' ', ' '],
[' ', ' ', ' '],
[' ', ' ', ' ']
]
game_running=True
print("-"*25)
print("Tic-Tac-Toe @ Vilijus")
print("-"*25)
print("Rules:")
print("1. First player is defined as P1 and he places \"X\" on the board;")
print("2. Second player is defined as P2 and he places \"O\" on the board;")
print("3. Enter coordinates in the format \"X,Y\"; for example, \"1,2\" - this represents the first row and the second column.")
print("="*50)
draw_board()
moves=0
while game_running:
# Game winning condition
winners_status = ["", "", "", ""]
# Player 1 input processing
x1, y1 = process_player_input("P1", board)
board[x1-1][y1-1] = "X"
moves=moves+1
# Check rows
for row in board:
if row[0] == row[1] == row[2] and row[0] != ' ':
winners_status[0]=row[0]
# Check columns
for col in range(3):
if board[0][col] == board[1][col] == board[2][col] and board[0][col] != ' ':
winners_status[1]=board[0][col]
# Check diagonals
if board[0][0] == board[1][1] == board[2][2] and board[0][0] != ' ':
winners_status[2]=board[0][0] # Return the winning symbol (X or O)
if board[0][2] == board[1][1] == board[2][0] and board[0][2] != ' ':
winners_status[3]=board[0][2] # Return the winning symbol (X or O)
if("X" in winners_status):
print("Player 1 won the game")
print("Congratulations!!!")
game_running = False
x2, y2 = process_player_input("P2", board)
board[x2-1][y2-1] = "0"
moves=moves+1
# Game board drawing
draw_board()
# Check rows
for row in board:
if row[0] == row[1] == row[2] and row[0] != ' ':
winners_status[0]=row[0]
# Check columns
for col in range(3):
if board[0][col] == board[1][col] == board[2][col] and board[0][col] != ' ':
winners_status[1]=board[0][col]
# Check diagonals
if board[0][0] == board[1][1] == board[2][2] and board[0][0] != ' ':
winners_status[2]=board[0][0] # Return the winning symbol (X or O)
if board[0][2] == board[1][1] == board[2][0] and board[0][2] != ' ':
winners_status[3]=board[0][2] # Return the winning symbol (X or O)
if("0" in winners_status):
print("Player 2 won the game")
print("Congratulations!!!")
game_running = False
Padarėme funkciją, kuri grąžina koordinates, kurios yra teisingos ir tada naudojantis jomis papildome lentą. Vėl išvengiame kodo dublikavimo. Šioje vietoje kodas sumažėjo nuo 113 iki 98. Šioje vietoje reiktų atkreipti į tai, kad galima grąžinti dvi reikšmes, ir į tai, kaip jos panaudojamos.
Kodą dar galima tiesiog iškelti į funkciją, taip kažkuriai kodo daliai uždedant vardą. Dabar žaidimo laimėjimo patikrinimą iškelkime į atskirą funkciją:
def draw_board(board):
print("\nGame Board:")
print("-"*13)
for row in board:
for cell in row:
print(f"| {cell} ", end="")
print("|")
print("-"*13)
print()
def process_player_input(player_symbol, board):
while True:
player_input = input(f"Enter {player_symbol} move (format: x,y): ")
input_split = player_input.split(",")
if len(input_split) != 2:
print("Invalid coordinates entered! Please enter in the format x,y.")
continue
x = int(input_split[0])
y = int(input_split[1])
if not (1 <= x <= 3 and 1 <= y <= 3):
print("Coordinates are outside the board! Please enter values between 1 and 3.")
continue
if board[x-1][y-1] != ' ':
print("Cell is occupied! Please choose another cell.")
continue
return x,y
def check_winner(board):
# Game winning condition
winners_status = ["", "", "", ""]
# Check rows
for row in board:
if row[0] == row[1] == row[2] and row[0] != ' ':
winners_status[0]=row[0]
# Check columns
for col in range(3):
if board[0][col] == board[1][col] == board[2][col] and board[0][col] != ' ':
winners_status[1]=board[0][col]
# Check diagonals
if board[0][0] == board[1][1] == board[2][2] and board[0][0] != ' ':
winners_status[2]=board[0][0] # Return the winning symbol (X or O)
if board[0][2] == board[1][1] == board[2][0] and board[0][2] != ' ':
winners_status[3]=board[0][2] # Return the winning symbol (X or O)
if("X" in winners_status):
print("Player 1 won the game")
print("Congratulations!!!")
return True
if("0" in winners_status):
print("Player 2 won the game")
print("Congratulations!!!")
return True
return False
# 3x3 Tic-Tac-Toe board
board = [
[' ', ' ', ' '],
[' ', ' ', ' '],
[' ', ' ', ' ']
]
game_running=True
print("-"*25)
print("Tic-Tac-Toe @ Vilijus")
print("-"*25)
print("Rules:")
print("1. First player is defined as P1 and he places \"X\" on the board;")
print("2. Second player is defined as P2 and he places \"O\" on the board;")
print("3. Enter coordinates in the format \"X,Y\"; for example, \"1,2\" - this represents the first row and the second column.")
print("="*50)
draw_board()
moves=0
while game_running:
# Player 1 input processing
x1, y1 = process_player_input("P1", board)
board[x1-1][y1-1] = "X"
if check_winner(board):
break
moves=moves+1
if(moves >= 9):
print("No more moves left; the game is ended.")
break
x2, y2 = process_player_input("P2", board)
board[x2-1][y2-1] = "0"
if check_winner(board):
break
# Game board drawing
draw_board(board)
Dabar pažvelkime į sutvarkytą kodą, pagrindinę jo dalį, nuo 87 eilutės. Šis kodas tapo labiau abstraktesnis, išskirstytas į akivaizdžius procesus:
- Apdorojima pirmojo žaidėjo įvestis;
- Apdorojama antrojo žaidėjo įvestis;
- Atspausdina žaidimų lentą;
- Patikrinama, ar yra laimėtojas.
Tokį suskirstymą mums leidžia padaryti funkcijos. Toliau gilinsimės į funkcijų principus ir detales.
Reikšmes grąžinančios funkcijos ir negrąžinančios
Tarkime turime dvi paprastas funkcijas - viena turi return raktažodį, kita ne. Pasižiūrėkime, kas atsitinka, kai jos priskiriamos kintamąjam.
def function_that_returns():
a = 10 + 10
return a
def func_that_not_returns():
a = 10 + 10
# This function does not return a value
v1 = function_that_returns()
print(f"First function value: {v1}")
v2 = func_that_not_returns()
print(f"Second function value: {v2}") # This will print "None" because the function does not return anything.
Tokio kodo išvestis:
First function value: 20
Second function value: None
Matome, kad pirmoji funkcija kintamajam suteikia tokį reikšmę, kuri yra užrašyta po return, kita nesuteikia reikšmės arba konkrečiau suteikia None reikšmę, kuri reiškia reikšmės neegzistavimą.
Taip pat funkcija gali kartu grąžinti ir negrąžinti reikšmės, priklausomai nuo argumentų. Tarkime, norime sukurti funkciją, kuri grąžina mums skaičiaus atvirkštinį skaičių. Atvirkštinis skaičius gaunamas vienetą padalinus iš to skaičiaus: . Tik problema ta, kad matematikoje, kartu ir programavime, negalima dalyba iš nulio. Tokiu atveju, kai gausime argumentą nulį, mes grąžinsime None.
def inverse_number(x):
if x != 0:
return 1 / x
return None
arguments = [10, 0, -15]
for x in arguments:
y = inverse_number(x)
if y is None:
print(f"Number {x} has no inverse number")
else:
print(f"{y:.3f} is the inverse for {x}")
Tokio kodo išvestis:
0.100 is the inverse for 10
Number 0 has no inverse number
-0.067 is the inverse for -15
None grąžinimą galima pakeisti į kitus du ekvivalentiškus - veikimas bus lygiai toks pat. Galima neprirašyti grąžinamos reikšmės:
def inverse_number(x):
if x != 0:
return 1 / x
return
arba galima pabaigti funkciją be return raktažodžio:
def inverse_number(x):
if x != 0:
return 1 / x
Visais trimis atvejais funkcija grąžins None reikšmę.
None lyginimasNone tikrinamas su is raktažodžiu, ženklas == šioje vietoje netinka.Keletas grąžinamų reikšmių
Python kalba suteikia galimybę su funkcija grąžinti daugiau negu vieną reikšmę, nors dažniausiai funkcijos kuriamos, kad grąžintų vieną reikšmę. Sukurkime funkciją, kuri iš datos (pvz. 2024-09-24) ištrauktų atskiras datos reikšmes: metų, mėnesio ir dienos:
def extract_date_components(date_string):
year, month, day = date_string.split("-")
return int(year), int(month), int(day)
date = "2024-09-24"
year, month, day = extract_date_components(date)
print(f"Year: {year}, Month: {month}, Day: {day}")
Terminale turėtumėte matyti tokią išvestį:
Year: 2023, Month: 9, Day: 23
Kai funkcija grąžina keletą reikšmių, nėra būtina nurodyti tiek pat kintamųjų. Galima nurodyti vieną kintamąjį ir atskiras grąžinamas reikšmes pasiekti su indeksais (kaip sąraše):
def extract_date_components(date_string):
year, month, day = date_string.split("-")
return int(year), int(month), int(day)
date = "2024-09-24"
date_components = extract_date_components(date)
print(f"Year: {date_components[0]}, Month: {date_components[1]}, Day: {date_components[2]}")
Reikšmių išpakavimas su *
Kai jau žinome, kad gali būti funkcijų su keleta grąžinamų reikšmių, išmoksime dar vieną gudrybę - jų išpakavimą.
Pirmiausiai, pasižiūrėkime, kad keletas grąžinamų reikšmių veikia, kaip sąrašo reikšmės grąžinimas. Demonstracijai sukurkime funkciją, kuri grąžina skaičiaus kartotinių. Jeigu nurodysime, kad ir , tai programa mums turėtų grąžinti sąrašą su skaičiais .
def multiples(a, n):
multiples = []
for i in range(n):
multiples.append(a * (i + 1))
return multiples
a = 3
n = 3
print(f"{n} multiples of the number {a}:")
print(multiples(a, n))
Kol kas skaičiuojame mažą kiekį kartotinių:
3 multiples of the number 3:
[3, 6, 9]
Kai žinome, kad turėsime tris grąžinamas reikšmes, galima funkcijos rezultatą priskirti trims kintamiesiems:
# ...
a=3
n=3
first_m, second_m, third_m = multiples(a, n)
print(f"Multiples of {a}:")
print(f"First: {first_m}, Second: {second_m}, Third: {third_m}")
Grąžinamas sąrašas veikia (beveik) taip pat, kaip grąžinant tris atskiras reikšmės:
Multiples of 3:
First: 3; Second: 6; Third: 9
O kas jeigu nurodytume n didesnį, o mums reiktų išskirti tris pirmas reikšmes, o kitų ne? Kad nereiktų rašyti 10 kintamųjų, Python kalba turi unpacking operatorių *:
# ...
a = 3
n = 10
first_m, second_m, third_m, *rest_multiples = multiples(a, n)
print(f"Multiples of {a}:")
print(f"First: {first_m}, Second: {second_m}, Third: {third_m}")
print(f"Rest of the multiples: {rest_multiples}")
Multiples of 3:
First: 3, Second: 6, Third: 9
Rest of the multiples: [12, 15, 18, 21, 24, 27, 30]
Rašydami * prieš kintamojo vardą, mes Python sakom, kad jis priskirtų visas likusias, nepriskirtas reikšmes tam kintamajam.
Šį kintamąjį su operatoriumi nebūtina rašyti gale, jis gali būti priekyje ir viduryje:
a=4
n=5
m_1, m_2, *m_middle, m_last = multiples(a, n)
print(f"Multiples of {a}:")
print(f"First: {m_1}; Second: {m_2}; Last: {m_last}")
print(f"Rest of the multiples: {m_middle}")
print("-"*10)
b=2
n=6
m_1, m_2, *m_middle, m_last = multiples(a, n)
print(f"Multiples of {b}:")
print(f"First: {m_1}; Second: {m_2}; Last: {m_last}")
print(f"Rest of the multiples: {m_middle}")
Multiples of 4:
First: 4; Second: 8; Last: 20
Rest of the multiples: [12, 16]
----------
Multiples of 2:
First: 4; Second: 8; Last: 24
Rest of the multiples: [12, 16, 20]
Šį operatorių nebūtina naudoti su funkcijos kvietimu, galima panaudoti tiesiog su sąrašu:
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9]
first, *leftovers = numbers
print(f"First number: {first}")
print(f"Rest of the numbers: {leftovers}")
print("*" * 15)
*leftovers, last = numbers
print(f"Last number: {last}")
print(f"Rest of the numbers: {leftovers}")
print("*" * 15)
first, *leftovers, last = numbers
print(f"First number: {first}; Last number: {last}")
print(f"Rest of the numbers: {leftovers}")
First number: 1
Rest of the numbers: [2, 3, 4, 5, 6, 7, 8, 9]
***************
Last number: 9
Rest of the numbers: [1, 2, 3, 4, 5, 6, 7, 8]
***************
First number: 1; Last number: 9
Rest of the numbers: [2, 3, 4, 5, 6, 7, 8]
Parametrai ir argumentai
Kalbant apie programavimą svarbu naudoti teisingus terminus.Funkcijoje skliausteliuose esančioms reikšmėms nusakyti naudojamos dvi sąvokos: parametras ir argumentas. Ar užrašas skliausteliuose yra argumentas, ar parametras, apibrėžia šių sąvokų apibrėžimai:
- Parametras - kintamasis funkcijos apraše, kuris nurodo kokią informaciją funkcija gali priimti;
- Argumentas - reali reikšmė, kuri yra įrašoma į funkciją, kai ji yra kviečiama. Ši reikšmė atitinka funkcijos apraše esantį kintamąjį.
Sąvokų apibrėžimas gali atrodyti šiek tiek sudėtingas be pavyzdžių. Tai pasižiūrėkime į paprastą pavyzdį. Turime funkcija, kuri spausdina pasisveikinimą:
def greet(name): # 'name' is a parameter
print(f"Hello, {name}!")
greet("Alice") # "Alice" is an argument
Funkcijos apraše def greet(name) esantis kintamasis name yra parametras. Šiame apraše jis neturi jokios reikšmės. Kai funkcija iškviečiama greet("Alice"), jai suteikiamas argumentas "Alice" - konkreti reikšmė, kuri perduodama funkcijai.
Argumentai su vardais
Sukurkime funkciją, kuriai reikia įrašyti daug argumentų. Tegul tai būna lentelės spausdinimo funkcija:
def print_table_header():
header = f"| {'Make':<15} | {'Model':<15} | {'Year':<6} | {'Color':<10} | {'Fuel':<10} | {'Gearbox':<10} | {'Mandatory technical inspection':<30} |"
print("=" * len(header))
print(header)
print("=" * len(header))
def print_car_info_row(make, model, year, color, fuel, is_manual, TI):
TI_str = "not provided" # Default value
if TI is True:
TI_str = "YES"
elif TI is False:
TI_str = "NO"
gearbox="Automatic"
if is_manual:
gearbox="Manual"
car_info = f"| {make:15} | {model:15} | {year:6} | {color:10} | {fuel:<10} | {gearbox:<10} | {TI_str:<30} |"
print(car_info)
print("-"*len(car_info))
print_table_header()
print_car_info_row("Toyota", "Avensis", "2008", "Black", "Diesel", True, True)
print_car_info_row("Volkswagen", "Beetle", "2003", "White", "Diesel", False, True)
print_car_info_row("Fiat", "Multipla", "1999", "Red", "Gasoline", True, False)
======================================================================================================================
| Make | Model | Year | Color | Fuel | Gearbox | Mandatory technical inspection |
======================================================================================================================
| Toyota | Avensis | 2008 | Black | Diesel | Manual | YES |
----------------------------------------------------------------------------------------------------------------------
| Volkswagen | Beetle | 2003 | White | Diesel | Automatic | YES |
----------------------------------------------------------------------------------------------------------------------
| Fiat | Multipla | 1999 | Red | Gasoline | Manual | NO |
----------------------------------------------------------------------------------------------------------------------
Kai yra tiek daug argumentų, ypatingai ten, kur gali pasitaikyti vienodos reikšmės (True ir True), galima pasimesti. Dėl kodo skaitomumo Python kalba mums leidžia nurodant argumentus, nurodyti jų vardus:
# ...
print_car_info_row("Toyota", "Avensis", "2008", "Black", "Diesel", is_manual=True, TI=True)
print_car_info_row("Volkswagen", "Beetle", "2003", "White", "Diesel", TI=False, is_manual=True)
print_car_info_row("Fiat", "Multipla", "1999", "Red", "Gasoline", True, TI=False)
Atkreipkite dėmesį į eiliškumą. Nurodant vardus būtina laikytis taisyklių:
- Nurodant argumentą(-us) su vardu, jų eiliškumas gali nesutapti su funkcijos apraše parametrų eiliškumu (23-24 eilutės);
- Nurodomas vardų kiekis pasirenkamas savo nuožiūrą;
- Vardai nurodomi tik nurodžius argumentus be vardų (pavyzdyje visi nurodyti argumentų vardai yra gale);
Svarbus trečiasis principas, nes jo nesilaikius, jūsų kodas tiesiog nepasileis. Žemiau esanti eilutė yra negalima:
# ...
print_car_info_row(make="Fiat", model="Multipla", "1999", "Red", "Gasoline", True, False)
Jeigu norėtume nurodyti markės argumentą su vardu, turėtume nurodyti visus argumentus su vardais:
# ...
print_car_info_row(make="Fiat", model="Multipla", year="1999", color="Red", fuel="Gasoline", is_manual=True, TI=False)
Numatytosios argumentų reikšmės
Funkcijoms galima nustatyti numatytasias reikšmes (angl. default), tai reiškias, jeigu nėra nurodomas argumentas, jo reikšmė tampa tokia, kokia yra numatyta. Pagrindinė taisyklė - apibrėžiant funkciją visi parametrai, turintys numatytąsias reikšmes, turi būti po parametrų be numatytųjų reikšmių.
Parametrui numatyta reikšmė suteikiama parašius ją po parametro:
def function_with_defaults(param1, param2="default", param3="another_default"):
print(param1, param2, param3)
# Valid calls
function_with_defaults("first")
function_with_defaults("first", "second")
first default another_default
first second another_default
Jeigu pabandytume suteikti numatytąją reikšmę tik pirmam parametrui, programa tai laikytų klaida, kadangi parametrai su numatytosiomis reikšmėmis turi eiti po įprastai nurodytais parametrais:
def function_with_defaults(param1="default", param2, param3):
print(param1, param2, param3)
Pakeiskime anksčiau sukurtą lentelės spausdinimo funkciją, suteikime numatytas reikšmės:
fuel="Gasoline";is_manual=True;is_manual=True.
def print_table_header():
header = f"| {'Make':<15} | {'Model':<15} | {'Year':<6} | {'Color':<10} | {'Fuel':<10} | {'Gearbox':<10} | {'Mandatory technical inspection':<30} |"
print("=" * len(header))
print(header)
print("=" * len(header))
def print_car_info_row(make, model, year, color, fuel="Gasoline", is_manual=True, TI=None):
TI_str = "not provided" # Default value
if TI is True:
TI_str = "YES"
elif TI is False:
TI_str = "NO"
gearbox="Automatic"
if is_manual:
gearbox="Manual"
car_info = f"| {make:15} | {model:15} | {year:6} | {color:10} | {fuel:<10} | {gearbox:<10} | {TI_str:<30} |"
print(car_info)
print("-"*len(car_info))
print_table_header()
print_car_info_row("Toyota", "Avensis", "2008", "Black", "Diesel", TI=True)
print_car_info_row("Volkswagen", "Beetle", "2003", "White", "Diesel", TI=False, is_manual=True)
print_car_info_row(make="Fiat", model="Multipla", year="1999", color="Red")
======================================================================================================================
| Make | Model | Year | Color | Fuel | Gearbox | Mandatory technical inspection |
======================================================================================================================
| Toyota | Avensis | 2008 | Black | Diesel | Manual | YES |
----------------------------------------------------------------------------------------------------------------------
| Volkswagen | Beetle | 2003 | White | Diesel | Manual | NO |
----------------------------------------------------------------------------------------------------------------------
| Fiat | Multipla | 1999 | Red | Gasoline | Manual | not provided |
----------------------------------------------------------------------------------------------------------------------
Jeigu yra nurodyta numatyta reikšmė ir mums ji tinka, jos galima nenurodyti. Ją galima praleisti nurodanti argumentą su vardu, kaip 24 eilutėje nėra nurodytas argumentas is_manual, nors nurodytas po jo einant TI.
Funkcijos aprašymas
Užėjus ant kai kurių funkcijų, mes galima pamatyti informaciją apie tai, ką jos daro, kokius argumentus priima, kokie jie, kokio tipo, kokias klaidas gali sukelti ta funkcija ir kokiais atvejais. Pavyzdžiui, užėjus ant open() funkcijos:
Šį aprašą galite slinkti žemiau ir pamatysite visą paklodę informacijos. Python viduje - kode, šitas užrašas yra pateikiamas, kaip funkcijos komentaras:
def open(file, mode="r", buffering=-1, encoding=None, errors=None,
newline=None, closefd=True, opener=None):
"""Open file and return a stream. Raise OSError upon failure.
file is either a text or byte string giving the name (and the path
if the file isn't in the current working directory) of the file to
be opened or an integer file descriptor of the file to be
wrapped. (If a file descriptor is given, it is closed when the
returned I/O object is closed, unless closefd is set to False.)
mode is an optional string that specifies the mode in which the file is
opened. It defaults to 'r' which means open for reading in text mode. Other
common values are 'w' for writing (truncating the file if it already
exists), 'x' for exclusive creation of a new file, and 'a' for appending
(which on some Unix systems, means that all writes append to the end of the
file regardless of the current seek position). In text mode, if encoding is
not specified the encoding used is platform dependent. (For reading and
writing raw bytes use binary mode and leave encoding unspecified.) The
available modes are:
========= ===============================================================
Character Meaning
--------- ---------------------------------------------------------------
'r' open for reading (default)
'w' open for writing, truncating the file first
'x' create a new file and open it for writing
'a' open for writing, appending to the end of the file if it exists
'b' binary mode
't' text mode (default)
'+' open a disk file for updating (reading and writing)
========= ===============================================================
The default mode is 'rt' (open for reading text). For binary random
access, the mode 'w+b' opens and truncates the file to 0 bytes, while
'r+b' opens the file without truncation. The 'x' mode implies 'w' and
raises an `FileExistsError` if the file already exists.
Python distinguishes between files opened in binary and text modes,
even when the underlying operating system doesn't. Files opened in
binary mode (appending 'b' to the mode argument) return contents as
bytes objects without any decoding. In text mode (the default, or when
't' is appended to the mode argument), the contents of the file are
returned as strings, the bytes having been first decoded using a
platform-dependent encoding or using the specified encoding if given.
buffering is an optional integer used to set the buffering policy.
Pass 0 to switch buffering off (only allowed in binary mode), 1 to select
line buffering (only usable in text mode), and an integer > 1 to indicate
the size of a fixed-size chunk buffer. When no buffering argument is
given, the default buffering policy works as follows:
* Binary files are buffered in fixed-size chunks; the size of the buffer
is chosen using a heuristic trying to determine the underlying device's
"block size" and falling back on `io.DEFAULT_BUFFER_SIZE`.
On many systems, the buffer will typically be 4096 or 8192 bytes long.
* "Interactive" text files (files for which isatty() returns True)
use line buffering. Other text files use the policy described above
for binary files.
encoding is the str name of the encoding used to decode or encode the
file. This should only be used in text mode. The default encoding is
platform dependent, but any encoding supported by Python can be
passed. See the codecs module for the list of supported encodings.
errors is an optional string that specifies how encoding errors are to
be handled---this argument should not be used in binary mode. Pass
'strict' to raise a ValueError exception if there is an encoding error
(the default of None has the same effect), or pass 'ignore' to ignore
errors. (Note that ignoring encoding errors can lead to data loss.)
See the documentation for codecs.register for a list of the permitted
encoding error strings.
newline is a string controlling how universal newlines works (it only
applies to text mode). It can be None, '', '\n', '\r', and '\r\n'. It works
as follows:
* On input, if newline is None, universal newlines mode is
enabled. Lines in the input can end in '\n', '\r', or '\r\n', and
these are translated into '\n' before being returned to the
caller. If it is '', universal newline mode is enabled, but line
endings are returned to the caller untranslated. If it has any of
the other legal values, input lines are only terminated by the given
string, and the line ending is returned to the caller untranslated.
* On output, if newline is None, any '\n' characters written are
translated to the system default line separator, os.linesep. If
newline is '', no translation takes place. If newline is any of the
other legal values, any '\n' characters written are translated to
the given string.
closedfd is a bool. If closefd is False, the underlying file descriptor will
be kept open when the file is closed. This does not work when a file name is
given and must be True in that case.
The newly created file is non-inheritable.
A custom opener can be used by passing a callable as *opener*. The
underlying file descriptor for the file object is then obtained by calling
*opener* with (*file*, *flags*). *opener* must return an open file
descriptor (passing os.open as *opener* results in functionality similar to
passing None).
open() returns a file object whose type depends on the mode, and
through which the standard file operations such as reading and writing
are performed. When open() is used to open a file in a text mode ('w',
'r', 'wt', 'rt', etc.), it returns a TextIOWrapper. When used to open
a file in a binary mode, the returned class varies: in read binary
mode, it returns a BufferedReader; in write binary and append binary
modes, it returns a BufferedWriter, and in read/write mode, it returns
a BufferedRandom.
It is also possible to use a string or bytearray as a file for both
reading and writing. For strings StringIO can be used like a file
opened in a text mode, and for bytes a BytesIO can be used like a file
opened in a binary mode.
"""
# ...
# Implementation
# ...
Funkcijų antraštės aprašymas sudaromas (kintamųjų tipai, grąžinama reikšmė) iš to, kas parašyta funkcijos apraše ir jos kode.
Visi komentarai, įskaitant ir funkcijos aprašymą, yra nebūtini. Jie rašomi tam, kad kiti suprastų mūsų kodą, tie kiti gali būti ir mes patys. Kai projektas tampa didelis arba prie jo dirbama retai, nors kodas būna parašytas mūsų pačių, mes, dėl elementarių žmogaus atminties galimybių, negalime atsiminti visų detalių, kaip kodas veikia, ką mes tuo metu galvojome kurdami, kuriose vietose palikome klaidas ir t.t. Tai po ilgo laiko grįžus prie savojo kodo, tikriausiai jį skaitysime, kaip svetimo parašytą.
Sukurkime funkciją, kurią vėliau aprašysime, kuri patikrina, ar duotasis skaičius yra pirminis. Pirminis skaičius yra toks skaičius, kuris turi tik du daliklius: save patį ir vienetą:
- 1 nėra pirminis, kadangi jis dalijasi tik iš savęs (trūksta dar vieno daliklio);
- 2 yra pirminis, nes dalijasi iš 2 ir 1;
- 3 yra piminis, nes dalijasi iš 3 ir 1;
- 4 nėra pirminis, nes dalijasi iš 1, 2, 4 (3 dalikliai);
- ir t.t.
def is_prime(num):
if num < 0:
raise ValueError("Input must be a non-negative integer.")
if num == 1:
return False
# Check for factors from 2 to num-1
for i in range(2, num):
if num % i == 0:
return False
# If no divisors were found, num is prime
return True
Mūsų funkcijoje negalima pateikti mažesnio skaičiaus negu 0. Tokiu atveju iškelsime klaidą (susipažinsime su šiuo dalyku vėliau) - programa rodys įvykusią klaidą. Toliau tikrinama, ar pateiktas skaičius turi daliklių, jeigu yra, tai skaičius nėra pirminis ir grąžinama reikšmė False.
Funkcijos aprašai rašomi tokie, kad skaitantysis suprastų:
- Pirmiausia, ką šita funkcija daro;
- Jeigu funkcija sudėtinga, turėtų būti aprašyta, koks jos veikimo principas;
- Kokią įtaką daro ar kokia prasmė parametrų;
- Kokia yra grąžinama reikšmė, kokia jos prasmė;
- Jeigu gali funkcijoje gali įvykti išimčių (
raise ValueError("Input must be a natural number greater than 0.")), tai irgi gali būti aprašyta;
Papildykime funkciją prasmingu komentaru:
def is_prime(num):
"""
Determine if a given number is a prime number.
A prime number is a natural number greater than 1 that has no positive
divisors other than 1 and itself. For example, 2, 3, 5, and 7 are
prime numbers.
Args:
num (int): The number to check.
Returns:
bool: True if the number is prime, False otherwise.
Raises:
ValueError: If num is less than 1.
"""
if num < 0:
raise ValueError("Input must be a non-negative integer.")
if num == 1:
return False
# Check for factors from 2 to num-1
for i in range(2, num):
if num % i == 0:
return False
# If no divisors were found, num is prime
return True
Dabar užėję ant funkcijos galite pamatyti, kaip VS code programavimo aplinka leidžia lengvai pasižiūrėti į sukurtos funkcijos informaciją:
Šie aprašai gali būti rašomi bet kaip tarp trigubų kabučių, bet dažniausiai yra laikomosi tam tikrų gairių:
- Pirmoje eilutėje pateikiama svarbiausia funkcijos informacija - ką ji daro;
- Toliau detaliau pristatoma funkcija;
- Galima pateikti skyrelius apie argumentus (Args), grąžinama reikšmę (Returns), galimas išimtis (Raises);
Šis pateiktas aprašymo formatas yra paremtas Google dokumentacijos gairėmis. Galima aprašymus rašyti ir pagal kitokias gaires, kurios taip pat suderinamos su VS code aplinka. Pavyzdžiui naudojantis numpydoc gairėmis ir formatu, mūsų aprašymą galėtume papildyti papildomais skyreliais:
def is_prime(num):
"""
Check if a number is prime.
A prime number[1]_ is a natural number greater than 1 that
has no positive divisors other than 1 and itself. For example,
2, 3, 5, and 7 are prime numbers.
Parameters
----------
num : int
The number to check.
Returns
-------
bool
True if num is prime, False otherwise.
Raises
------
ValueError
If num is a negative integer.
Examples
--------
Basic usage of the function:
print(is_prime(5)) # Outputs: True
print(is_prime(10)) # Outputs: False
print(is_prime(1)) # Outputs: False
Notes
-----
This function checks for factors from 2 to num-1. It can be inefficient
for large values of num[2]_.
References
----------
.. [1] "Prime Number" In Wikipedia. Available at:
(``https://en.wikipedia.org/wiki/Prime_number``)
.. [2] Knuth, Donald E. *The Art of Computer Programming, Volume 2:
Seminumerical Algorithms*. Addison-Wesley, 1998.
See Also
--------
isqrt : A function to compute the integer square root, useful for
optimizing primality tests by limiting the range of divisors to check.
Sieve of Eratosthenes : An efficient algorithm for finding all prime
numbers up to a specified integer, which can be more efficient for
generating lists of primes than checking individual numbers.
"""
if num < 0:
raise ValueError("Input must be a non-negative integer.")
if num == 1:
return False
# Check for factors from 2 to num-1
for i in range(2, num):
if num % i == 0:
return False
# If no divisors were found, num is prime
return True
Tokį aprašą VS code atvaizduoja šitaip:
Sužinoję visus šiuos dalykus šiame skyriuje, būtų puiku, jeigu jau pradėtume aprašinėti savo funkcijas nors viena eilute:
def is_prime(num):
"""
Check if a number is prime.
"""
# ....
Parametrų tipų užuominos
Nors Python turi tipus (str, int, float, bool ir kt.), jie nėra matomi, nėra tiesiogiai naudojami. Python palaiko kintamųjų tipų užuominas (angl. type hinting). Mes kintamajam galime suteikti tipą, kuris padės mums programuojant:
Sukurkime funkciją, kuri, pateikus tekstą, grąžina mums unikalius žodžius. Ši funkcija taip pat gali ignoruoti blogus žodžius, kurie aprašomi funkcijoje:
def extract_unique_words(text, filter_offensive):
"""
Extract unique words from a text.
If filter_offensive is `True`, the function will remove offensive words.
If `False`, it will return all words in the text.
"""
offensive_words = ["badword1", "badword2", "badword3"]
words = text.split()
unique_words = []
for word in words:
word_lower = word.lower()
if filter_offensive:
if word_lower not in offensive_words and word_lower not in unique_words:
unique_words.append(word_lower)
else:
if word_lower not in unique_words:
unique_words.append(word_lower)
return unique_words
Jeigu pasižiūrėtumėte į kodo spalvas, metodai split() ir lower() yra nespalvoti. Tai reiškias, kad Python neatpažįsta šių kintamųjų tipų:
Nors funkcija veikia teisingai, programuojant mums VS code aplinka nepateiks užuominų (angl. code suggestions), neveiks kodo automatinis pabaigimas (angl. autocomplete):
Būtų geriau, jeigu būtų taip:
Norint sutvarkyti šią problemą, mes galime kode nurodyti koks turėtų būti kintamojo tipas, Python kalboje tai vadinasi tipų užuominomis (angl. type hints). Tai daroma prie kintamojo parašius dvitaškį ir jo tipą:
def extract_unique_words(text: str, filter_offensive):
# ...
Dabar jau turėtų nusispalvinti šis kintamasis teisingai ir kodo užbaigimas veikti teisingai. Taip pat tai padeda kodą skaitančiam asmeniui suprasti, kokio tipo kintamąjį pateikti (ypatingai tai gelbėjai, kai nėra parašyta funkcijos apraše). Taip pat šie tipai atsiranda, kai norime pažvelgti į funkcijos informaciją:
Matome, kad dabar funkcijai reikia pateikti kintamąjį text, kurio tipas yra str. Kintamojo filter_offensive Python neatpažįsta. Užrašas po rodyklės -> rodo, koks bus grąžinamos reikšmės tipas, šiuo atveju tai list.
Toliau galime tai patobulinti ir nurodyti tipą kintamajam filter_offensive ir patikslinti grąžinomos reikšmės tipą, kad tai sąrašas iš str tipo reikšmių.
def extract_unique_words(text: str, filter_offensive: bool = True) -> list[str]:
# ...
Funkcijai taip pat suteikėme numatytąją reikšmę, kad pamatytumėte, kaip tai užrašoma. Dabar rašant kode, mums teisingai siūlomos reikšmės ir pateikiama pilna funkcijos informacija:
Toliau iškvietus funkciją ir dirbant su jos grąžinama reikšme, jeigu nustatyti (teisingi) tipai, programa ir toliau pateikimi kodo užbaigimo pasiūlymai:
Jeigu norite pamatyti efektą be jų, galite pabandyti išsitrinti tipus ir pabandyti rašyti kodą.
Toliau pateikiami tipai, kuriuos jūs jau turėtumėte žinoti ir suprasti. Be to tipai gali būti priskiriami tiesiog kintamajam.
x1: int = 1
x2: float = 1.0
x3: bool = True
x4: str = "test"
x4: list[int] = [1]
def my_func(a: int, b: float, c: bool, d: str, e: list[list[bool]]):
print("Hello, world!")
Taip pat galima nurodyti, kad kintamasis gali įgyti keletą skirtingų tipų reikšmių, taip galima nurodyti, kad kintamasis gali turėti None reikšmę:
from typing import Optional
x5: list[int | str] = [3, 5, "test", "fun"] # This list can contain either int or str values.
x6: Optional[str] = "something" # This line is valid.
x6 = None # This line is also valid because x6 can be str or None.
# The function below takes g as a list of ints or strings, and h as a string or None.
# It returns either None or a list of floats.
def my_other_func(g: list[int | str], h: Optional[str]) -> Optional[list[float]]:
print("Hello, world!")
Daugiau apie tipus galite pasiskaityt Type hints cheat sheet - mypy 1.11.2 documentation.
Suprasti kintamųjų tipus padės jums pereinant prie kitų programavimo kalbų, kur sukuriant kintamąjį privaloma iš karto nurodyti jo tipą. Python kalboje kintamųjų tipų rašymas nėra būtinas, bet jis padeda programuojant. Toliau jūs patys renkatės, ar jūs tai darysite, ar ne.
Užduotys
1. Skaičiaus transformacijos
Sukurkite programą, kuri jūsų pateiktą skaičių (iš terminalo), transformuotų:
- Padvigubintų kiekvieną skaičiaus skaitmenį.
- Suskaičiuotų naujojo skaičiaus skaitmenų sumą;
- Pakartotų pirmąjį žingsnį;
Skaičiuje esantis minusas negali būti dvigubinamas arba sumuojamas prie skaitmenų, todėl jis turi išlikti galutiniame skaičiuje.
Jeigu skaičius yra pateiktas slankiojo kablelio (float), jo sveikoji ir trupmeninė dalys yra apdorojamos atskirai, o tada vėl sujungiamas atgal.
Rezultatus pateikite terminale;
Užduočiai padaryti turite būti sukurtos trys funkcijos (atkreipkite dėmesį į argumentų tipus ir grąžinamų reikšmių tipus):
def double_digits(n: int) -> int
def sum_digits(n: int) -> int
def transform_number(n: int|float) -> int|float
Detalesnis paaiškinimas
Tarkime įvedame skaičių 246. Pirmiausia skaičiaus skaitmenys padvigubinami:
2tampa4;4tampa8;6tampa12.
Galiausiai rezultatus sujungiame ir gauname 4812.
Tada suskaičiuojame šių skaitmenų sumą: 15.
Gavus sumą pakartojame skaitmenų dvigubinimą ir gauname 15->210.
Įvestys ir tikėtini rezultatas
| Įvestis | tikėtinas rezultatas |
|---|---|
| 123 | 24 |
| -123 | -24 |
| 89 | 32 |
| 789 | 42 |
| 135 | 18 |
| 78.901 | 22.22 |
| -678.9 | -18.18 |
| 0.34 | 0.28 |
| 0 | 0 |
| -5 | -2 |
| 999 | 54 |
| 1001 | 12 |
| 9876543210987654321 | 180 |
| 2468024680 | 810 |
| -2468024680 | -810 |
| -12345.6789 | -42.48 |
2. Pasikartojančių elementų pašalinimas
Iš duotų sąrašų ištrinkite pasikartojančius elementus - pakeistame sąraše turi likti tik unikalūs elementai:
Sukurkite funkciją, kuri iš duotojo sąrašo grąžina tik unikalius elementus.
def remove_duplicates(elements: list) -> list
Duomenys:
apple,banana,apple,orange,grape,banana,apple,cherry,peach,plum
5,2,5,7,10,5,2,3,5,15,20,25,2
3.14,2.71,3.14,1.61,3.14,2.71
Berlin,Paris,Berlin,Rome,Madrid,London,Berlin,Paris
Dog,Cat,Bird,Dog,Fish,Cat,Lizard,Dog,Horse,Fish
hello,world,hello,code,python,world,hello,script,programming
Alice,Bob,Alice,Eve,Charlie,Alice,David,Eve,Bob
-10,-20,-10,-30,-40,-50,-10,-60,-70,-10
9.81,3.14,9.81,2.71,1.61,9.81,3.14,1.41,9.81,2.71,1.61
2001,1984,2001,2020,1984,2001,2020,1984,1999
Monday,Friday,Monday,Wednesday,Monday,Tuesday,Monday,Thursday,Saturday,Monday
10,10,10
Green,Green,Blue,Yellow,Green
Alice,alice,ALICE,Alice
1
a,b,a,c,b,d,e,f,e
True,False,True,True,False
Rezultatus pateikite tekstiniame faile:
Original List 1: ['apple', 'banana', 'apple', 'orange', 'grape', 'banana', 'apple', 'cherry', 'peach', 'plum']
After Removing Duplicates: ['apple', 'banana', 'orange', 'grape', 'cherry', 'peach', 'plum']
Number of Removed Elements: 3
Original List 2: [5, 2, 5, 7, 10, 5, 2, 3, 5, 15, 20, 25, 2]
After Removing Duplicates: [5, 2, 7, 10, 3, 15, 20, 25]
Number of Removed Elements: 5
Original List 3: [3.14, 2.71, 3.14, 1.61, 3.14, 2.71]
After Removing Duplicates: [3.14, 2.71, 1.61]
Number of Removed Elements: 3
Original List 4: ['Berlin', 'Paris', 'Berlin', 'Rome', 'Madrid', 'London', 'Berlin', 'Paris']
After Removing Duplicates: ['Berlin', 'Paris', 'Rome', 'Madrid', 'London']
Number of Removed Elements: 3
Original List 5: ['Dog', 'Cat', 'Bird', 'Dog', 'Fish', 'Cat', 'Lizard', 'Dog', 'Horse', 'Fish']
After Removing Duplicates: ['Dog', 'Cat', 'Bird', 'Fish', 'Lizard', 'Horse']
Number of Removed Elements: 4
Original List 6: ['hello', 'world', 'hello', 'code', 'python', 'world', 'hello', 'script', 'programming']
After Removing Duplicates: ['hello', 'world', 'code', 'python', 'script', 'programming']
Number of Removed Elements: 3
Original List 7: ['Alice', 'Bob', 'Alice', 'Eve', 'Charlie', 'Alice', 'David', 'Eve', 'Bob']
After Removing Duplicates: ['Alice', 'Bob', 'Eve', 'Charlie', 'David']
Number of Removed Elements: 4
Original List 8: [-10, -20, -10, -30, -40, -50, -10, -60, -70, -10]
After Removing Duplicates: [-10, -20, -30, -40, -50, -60, -70]
Number of Removed Elements: 3
Original List 9: [9.81, 3.14, 9.81, 2.71, 1.61, 9.81, 3.14, 1.41, 9.81, 2.71, 1.61]
After Removing Duplicates: [9.81, 3.14, 2.71, 1.61, 1.41]
Number of Removed Elements: 6
Original List 10: [2001, 1984, 2001, 2020, 1984, 2001, 2020, 1984, 1999]
After Removing Duplicates: [2001, 1984, 2020, 1999]
Number of Removed Elements: 5
Original List 11: ['Monday', 'Friday', 'Monday', 'Wednesday', 'Monday', 'Tuesday', 'Monday', 'Thursday', 'Saturday', 'Monday']
After Removing Duplicates: ['Monday', 'Friday', 'Wednesday', 'Tuesday', 'Thursday', 'Saturday']
Number of Removed Elements: 4
Original List 12: [10, 10, 10]
After Removing Duplicates: [10]
Number of Removed Elements: 2
Original List 13: ['Green', 'Green', 'Blue', 'Yellow', 'Green']
After Removing Duplicates: ['Green', 'Blue', 'Yellow']
Number of Removed Elements: 2
Original List 14: ['Alice', 'alice', 'ALICE', 'Alice']
After Removing Duplicates: ['Alice', 'alice', 'ALICE']
Number of Removed Elements: 1
Original List 15: []
After Removing Duplicates: []
Number of Removed Elements: 0
Original List 16: [1]
After Removing Duplicates: [1]
Number of Removed Elements: 0
Original List 17: ['a', 'b', 'a', 'c', 'b', 'd', 'e', 'f', 'e']
After Removing Duplicates: ['a', 'b', 'c', 'd', 'e', 'f']
Number of Removed Elements: 3
Original List 18: [True, False, True, True, False]
After Removing Duplicates: [True, False]
Number of Removed Elements: 3
3. Elementų skaičius sąraše
Parašykite programa, kuri suskaičiuotų nurodyto elementų pasikartojimų skaičių. Elementas, kurio kiekį sąraše skaičiuosime, ir sąrašas nurodytas .csv faile. Eilutėje pirma reikšmė yra tas elementas, kurio kiekį sąraše skaičiuosime, sekantys yra sąrašas, kuriame to elemento ieškosime. Duomenų failas:
apple,banana,apple,orange,grape,banana,apple,cherry,peach,plum
5,2,5,7,10,5,5,3,5,15,20,25,5
3.14,2.71,3.14,1.61,3.14
Berlin,Paris,Berlin,Rome,Madrid,London,Berlin
Dog,Cat,Bird,Dog,Fish,Cat,Lizard,Dog,Horse
hello,world,hello,code,python,world,hello,script,programming
Alice,Bob,Alice,Eve,Charlie,Alice,David,Eve,Bob
-10,-20,-10,-30,-40,-50,-10,-60,-70,-10
9.81,3.14,9.81,2.71,1.61,9.81,3.14,1.41,9.81,2.71,1.61
2001,1984,2001,2020,1984,2001,2020,1984,1999
Monday,Friday,Monday,Wednesday,Monday,Tuesday,Monday,Thursday,Saturday,Monday
10
Green,Green,Green
Alice,alice
Bob,Lorem,ipsum,dolor,sit,amet,consectetur,adipiscing,elit,Etiam,dignissim,nibh
Turite sukurti pagrindę funkciją nenaudodami Python kalboje esančios funkcijos count():
def count_element_occurrence(elements: list, e) -> int:
Rezultatus pateikite terminale, atkreipkite dėmesį, kad reikia atsižvelgti, ar raidės didžiosios, ar mažosios ("Python" == "python" # False):
In list 1, the element 'apple' occurs 2 times.
In list 2, the element '5' occurs 5 times.
In list 3, the element '3.14' occurs 2 times.
In list 4, the element 'Berlin' occurs 2 times.
In list 5, the element 'Dog' occurs 2 times.
In list 6, the element 'hello' occurs 2 times.
In list 7, the element 'Alice' occurs 2 times.
In list 8, the element '-10' occurs 3 times.
In list 9, the element '9.81' occurs 3 times.
In list 10, the element '2001' occurs 2 times.
In list 11, the element 'Monday' occurs 4 times.
In list 12, the element '10' occurs 0 times.
In list 13, the element 'Green' occurs 2 times.
In list 14, the element 'Alice' occurs 0 times.
In list 15, the element 'Bob' occurs 0 times.
4. Skaitmenų suma
Skaičiai yra sudaryti iš skaitmenų. Skaičius turi skaitmenis , , , , . Jeigu sudėtume šiuos skaičius gautume skaičiaus skaitmenų suma. Tai skaičiaus skaitmenų suma yra lygi .
def sum_of_digits(n: float|int) -> int
numbers = [
-345,
-1234.56,
0,
42,
567.89,
9821,
-0.678,
12.34,
123456,
-98765.4321
]
Rezultatus pateikite terminale, šie galėtų atrodyti šitaip:
-345: 3+4+5 = 12
-1234.56: 1+2+3+4+5+6 = 21
0: 0 = 0
42: 4+2 = 6
567.89: 5+6+7+8+9 = 35
9821: 9+8+2+1 = 20
-0.678: 0+6+7+8 = 21
12.34: 1+2+3+4 = 10
123456: 1+2+3+4+5+6 = 21
-98765.4321: 9+8+7+6+5+4+3+2+1 = 45
5. Balsių skaičiavimas
Suskaičiuokite tekstuose esančias balses. Rezultatus išspausdinkite terminale:
texts=[
"Graži tu, mano brangi tėvyne,\nŠalis, kur miega kapuos didvyriai!\nNe veltui bočiai tave taip gynė,Ne veltui dainiai plačiai išgyrė!",
"Ei, tai vija,\nPinavija, -\nVisą dieną\nGrybais lija.\nVisą dieną\nNuo pat ryto\nGrybai krito,\nKrito, krito...",
"Everything that happens is either endurable or not. If it’s endurable, then endure it. Stop complaining. If it’s unendurable… then stop complaining. Your destruction will mean its end as well. Just remember: you can endure anything your mind can make endurable, by treating it as in your interest to do so",
"It followed from the special theory of relativity that mass and energy are both but different manifestations of the same thing - a somewhat unfamiliar conception for the average mind. Furthermore, the equation E is equal to m c-squared, in which energy is put equal to mass, multiplied by the square of the velocity of light, showed that very small amounts of mass may be converted into a very large amount of energy and vice versa. The mass and energy were in fact equivalent, according to the formula mentioned above. This was demonstrated by Cockcroft and Walton in 1932, experimentally.",
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed imperdiet.",
"Lrm psm dlr st mt, cnscttr dpscng lt. Sd mprdt.",
]
def count_vowels(text: str) -> int
Išvestis galėtų atrodyti šitaip:
Text Vowel Count
0 Graži tu, mano brangi tėvyne,\nŠalis, kur mieg... 50
1 Ei, tai vija,\nPinavija, -\nVisą dieną\nGrybai... 36
2 Everything that happens is either endurable or... 94
3 It followed from the special theory of relativ... 182
4 Lorem ipsum dolor sit amet, consectetur adipis... 24
5 Lrm psm dlr st mt, cnscttr dpscng lt. Sd mprdt... 0
6. Temperatūrų konvertavimas
Duotas tekstinis failas su temperatūrų sąrašu. Šios temperatūros pateiktos celsijais arba farenheitais. Sukurkite funkcijas, kuriuos konvertuotų iš matavimo vieneto į kitą. Pradines ir pakeistas temperatūras pateikite rezultatų faile.
Šiai užduočiai padaryti būtina, sukurti dvi funkcijas:
def celsius_to_fahrenheit(celsius: float) -> float
def fahrenheit_to_celsius(fahrenheit: float) -> float
Pradiniai duomenys:
55.5°F
120.4°F
29.0°C
107.2°F
64.6°F
47.2°F
-11°C
40.4°F
64°F
30.6°C
27.4°C
81°F
-14.8°C
54.3°F
13.5°C
63.2°F
-18.5°C
5°C
35.2°F
84.6°F
Rezultatus pateikite suformatavę skaičius. Temperatūras pateikite 2 skaičių po kablbelio tikslumu. Rezultatų failas turėtų atrodyti šitaip:
55.5°F -> 13.06°C
120.4°F -> 49.11°C
29.0°C -> 84.2°F
107.2°F -> 41.78°C
64.6°F -> 18.11°C
47.2°F -> 8.44°C
...
...
...
35.2°F -> 1.78°C
84.6°F -> 29.22°C
7. Sąrašo rūšiavimas
Duotas tekstinis failas su skaičių sąrašais:
42 17 3 89 23 -10 20 100
2.5 3.1 1.8 4.6 2.2 3.3
7 2.5 3 8.8 4 1.1 5
-10 -3.99 -25 -7.1 -15 -1
3.14 2.71 1.41 1.73 0.57 6.28
-6.4 2.1 -3.3 7.9 -0.2 4 -8.1 9.9
42
5 10
-12.5 -2.0
0 0 0 0 0 0 0 0 0 0
Nuskaitykite šiuos duomenis ir sukūrę skaičių rūšiavimo funkciją pateikite juos išrūšiuotus mmažėjančiai ir didėjančiai. Rūšiavimo funkcija turi būti sukurta rankiniu būdu, nenaudojant Python kalboje jau esančios sort() funkcijos:
def sort_list(numbers: list[int|float], reverse: bool = False) -> list[int|float]
Jūsų rezultatų failas galėtų atrodyti šitaip:
1. Original List: [42, 17, 3, 89, 23, -10, 20, 100]
Sorted List: [-10, 3, 17, 20, 23, 42, 89, 100]
Reversed Sorted List: [100, 89, 42, 23, 20, 17, 3, -10]
2. Original List: [2.5, 3.1, 1.8, 4.6, 2.2, 3.3]
Sorted List: [1.8, 2.2, 2.5, 3.1, 3.3, 4.6]
Reversed Sorted List: [4.6, 3.3, 3.1, 2.5, 2.2, 1.8]
3. Original List: [7, 2.5, 3, 8.8, 4, 1.1, 5]
Sorted List: [1.1, 2.5, 3, 4, 5, 7, 8.8]
Reversed Sorted List: [8.8, 7, 5, 4, 3, 2.5, 1.1]
4. Original List: [-10, -3.99, -25, -7.1, -15, -1]
Sorted List: [-25, -15, -10, -7.1, -3.99, -1]
Reversed Sorted List: [-1, -3.99, -7.1, -10, -15, -25]
5. Original List: [3.14, 2.71, 1.41, 1.73, 0.57, 6.28]
Sorted List: [0.57, 1.41, 1.73, 2.71, 3.14, 6.28]
Reversed Sorted List: [6.28, 3.14, 2.71, 1.73, 1.41, 0.57]
6. Original List: [-6.4, 2.1, -3.3, 7.9, -0.2, 4, -8.1, 9.9]
Sorted List: [-8.1, -6.4, -3.3, -0.2, 2.1, 4, 7.9, 9.9]
Reversed Sorted List: [9.9, 7.9, 4, 2.1, -0.2, -3.3, -6.4, -8.1]
7. Original List: [42]
Sorted List: [42]
Reversed Sorted List: [42]
8. Original List: [5, 10]
Sorted List: [5, 10]
Reversed Sorted List: [10, 5]
9. Original List: [-2.0, -12.5]
Sorted List: [-12.5, -2.0]
Reversed Sorted List: [-2.0, -12.5]
10. Original List: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
Sorted List: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
Reversed Sorted List: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
8. Savaitės pardavimų analizė
Faile sales_data.csv saugomi duomenys apie parduotus produktų kiekius per savaitę. Šį failą galite atsiųsti čia (trys atvejai).
Duomenyse eilutė prasideda produkto pavadinimu, o toliau seka pardavimų skaičius nuo pirmadienio iki sekmadienio.
Rezultatai
Rezultatai turi būti pateikiami tekstiniame faile. Jame turi būti:
- Kiekvienos dienos geriausiai parduodamas produktas;
- Kiekvieno produkto pardavimų skaičius per savaitę, iš viso;
- Produktas su didžiausiu vidutiniu dienos pardavimu;
Rezultatų failo pavyzdys:
Sales Analysis Report
==================================================
Best-Selling Product Each Day:
--------------------------
Day Product
--------------------------
Monday Product C
Tuesday Product C
Wednesday Product C
Thursday Product C
Friday Product C
Saturday Product C
Sunday Product A
Total Weekly Sales Per Product:
--------------------------
Product Total Sales
--------------------------
Product A 35
Product B 24
Product C 49
Product with the Highest Average Daily Sales: Product C
Reikalavimai
Užduočiai atlikti būtina sukurti tokias funkcijas:
def read_sales_data(file_name: str) -> list[list[int]]
def calculate_daily_best_sellers(data: list[list[int]]) -> list[int]
def calculate_weekly_totals(data: list[list[int]]) -> list[int]
def find_highest_average(data: list[list[int]]) -> int
def write_sales_summary(daily_best_sellers: list[int], weekly_totals: list[int], highest_avg_index: int, product_names: list[str]) -> None
9. Temperatūros
Situacija
Esate metereologistas renkantis 12 (3 mėnesius) savaičių orų pokyčius, kuriuos turite išanalizuoti. Visą šį periodą, jūs renkate temperatūrų duomenis kas valandą. Savaitės temperatūrų duomenys išsaugomi failuose week1.csv, week2.csv, week3.csv, ..., week12.csv. Šiose failuose yra 7 dienų temperatūrų duomenys - eilutėje yra aprašytos 24 valandų temperatūros. Kiekviena eilutė reprezentuoja dieną.
Jūsų užduotis yra išanalizuoti ketvirčio orų duomenis, kad nustatytumėte tendencijas ir temperatūros anomalijas.
Tikslai
- Suskaičiuoti vidutinę ketvirčio temperatūrą;
- Identifikuoti anomalijas - temperatūras, kurios nuo mėnesio vidurkio skiriasi per 5°C laipsnius;
- Pateikite suvestinės failą.
Pradiniai duomenys
Duomenis galite atsisiųsti čia (43 atvejai). Čia rasite dvylikos savaičių failus, kurių formatas vienodas. Failo pavyzdys:
00:00,01:00,02:00,03:00,04:00,05:00,06:00,07:00,08:00,09:00,10:00,11:00,12:00,13:00,14:00,15:00,16:00,17:00,18:00,19:00,20:00,21:00,22:00,23:00
20.5,21.0,19.8,18.5,17.2,16.0,15.5,15.2,16.5,17.8,19.0,21.0,22.5,23.0,24.0,25.5,27.0,28.0,29.5,30.0,29.0,27.5,25.0,22.0
21.5,22.0,20.8,19.0,18.0,17.5,16.8,16.0,17.2,18.5,20.0,22.5,24.0,25.5,26.0,27.5,29.0,30.0,31.5,32.0,30.0,28.5,26.0,23.5
22.0,23.5,21.0,20.0,19.5,18.5,17.5,17.0,18.0,19.5,21.0,23.0,25.0,26.0,27.0,28.0,29.0,30.5,31.0,32.0,30.0,28.0,25.0,23.0
19.5,20.0,19.0,18.5,18.0,17.0,16.0,15.5,16.0,17.5,19.0,20.0,21.5,22.0,23.0,24.5,26.0,27.0,28.0,29.0,27.5,25.0,23.0,20.0
18.0,18.5,17.5,17.0,16.0,15.0,14.5,14.0,15.0,16.5,18.0,19.5,20.0,21.0,22.0,23.0,24.0,25.0,26.5,27.0,26.0,24.5,22.0,19.0
20.0,21.5,19.5,18.0,17.0,16.5,15.5,15.0,16.0,18.0,19.0,20.5,22.0,23.0,24.0,25.0,26.5,27.5,28.0,27.0,25.0,23.0,21.0,19.5
22.5,23.0,21.5,20.0,19.0,18.5,17.5,16.0,15.5,17.0,18.5,20.0,21.0,22.5,24.0,25.5,26.5,27.0,28.0,29.0,27.5,25.0,23.5,21.0
Rezultatų failas
Failas gali būti pateiktas tekstiniame faile paprastu tekstu arba lentele. Jame turi būti pateikta:
- vidutinės mėnesių temperatūros;
- anomalijų skaičius;
- vidutinis anomalijų temperatūrų nuokrypis nuo vidurkio;
- anomalijų sąrašas:
1 month average: 15.2°C
2 month average: 14.2°C
3 month average: 15.1°C
Anomalies Found: 23
Average Anomaly Deviation: +3.0°C
Week,Day,Hour,Temperature,Deviation
2,3,15,21.8,+6.6
5,6,02,9.1,-6.1
...
arba
1 month average: 15.2°C
2 month average: 14.2°C
3 month average: 15.1°C
Anomalies Found: 23
Average Anomaly Deviation: +3.0°C
===============================================
| Week | Day | Hour | Temperature | Deviation |
===============================================
| 2 | 3 | 15 | 21.8 | +6.6 |
| 5 | 6 | 02 | 9.1 | -6.1 |
|... | | | | |
===============================================
Reikalavimai
Darant šią užduotį turite sukurti tokias funkcijas:
# Reads all temperature data from the provided CSV files and
# returns a nested list containing temperature records for each week, day, and hour.
def read_all_data(file_names: list) -> list[list[list[float]]]
# Calculates and returns a list of average temperatures for each month in the quarter.
def calculate_month_average(data: list[list[list[float]]]) -> list[float]
# Identifies temperature anomalies and returns a list containing anomalies with details for each entry
# The return value example: [[2, 3, 15, 21.8, 6.6], [5, 6, 2, 9.1, -6.1]].
# The first number represents week, 2nd - day, 3rd - hour, 4th - temperature of that day, 5 - deviation
def find_anomalies(list: list[list[list[float]]], month_averages: list[float]) -> list[list[int|float]]
# Calculates and returns the average deviation of all identified anomalies.
def calculate_anomalies_average(anomalies: list[list[int|float]]) -> float
# Writes the summary to a CSV file, including the average temperature of each month, the average deviation of anomalies, and the list of anomalies.
def write_quarter_summary(month_averages: list[float], anomalies_average: float, anomalies: list[list[int|float]]) -> None
Būtina suformatuoti rezultatus:
- Visos temperatūros turi būti pateikos vieno skaičiaus po kablelio tikslumu;
- Vidutinės temperatūros turi būti pateikos su celsijaus žymėjimu (°C);
- Diena turi būti pateikta su nuliu priekyje, jeigu dienos reikšmė sudaryta iš vieno skaitmens;
- Nuokrypiai (vidutinis ir sąraše esantys) turi pateikti su ženklus (- arba +);