პითონის სახელმძღვანელო (კონსპექტი)

პითონის კონსპექტი დამწყები და გამოცდილი პროგრამისტებისთვის. შეინახეთ ეს ბლოგპოსტი, რათა მარტივად გაიხსენოთ პითონის ძირითადი სინტაქსი და ფუნქციები.

By გიგი ჩაკაბერია
პითონის სახელმძღვანელო (კონსპექტი)

ეს ბლოგპოსტი მოიცავს Python პროგრამირების ენის მოკლე მიმოხილვას. კონსპექტში ნახავთ პითონის სინტაქსის ძირითად ელემენტებს: მონაცემთა ტიპებს, ცვლადებს, სტრიქონებს, მართვის ნაკადს (control flow), ფუნქციებს, კლასებს, Error-handling-ს, შეტანა/გამოტანას (I/O) და მრავალ სხვას!


📝 კომენტარები (Comments)

  • ყოველთვის გამოტოვეთ ერთი ადგილი # სიმბოლოს შემდეგ, რათა ტექსტი მარტივად იკითხებოდეს.
  • გამოიყენეთ კომენტარები იმის ასახსნელად, თუ „რატომ“ დაწერეთ ეს კოდი (მაგრამ კოდმა თავად უნდა თქვას „რას“ აკეთებს).

მაგალითი:

# ეს არის სტანდარტული კომენტარი ახალ ხაზზე

# ქვედა კოდი დროებით გამორთულია, ამიტომ არ გაეშვება:
# print("ეს კოდი არ გაეშვება 🛑")

print("ეს კოდი ჩვეულებრივად იმუშავებს! 🎉")  # კომენტარებს Python სრულად აიგნორებს

მონაცემთა ტიპები (Data Types) 🧬

Python დინამიურად ტიპიზირებული ენაა, რაც იმას ნიშნავს, რომ ცვლადის შექმნისას მისი ტიპის წინასწარ მითითება არ გჭირდებათ — Python ამას თავად ხვდება! 🧠

  • გამოიყენეთ None გამოტოვებული, ცარიელი ან არასავალდებულო მნიშვნელობების გამოსახატავად (ეს იგივეა, რაც სხვა ენებში null).
  • გამოიყენეთ type() ფუნქცია, რათა ზუსტად გაიგოთ, თუ რა ტიპისაა კონკრეტული ობიექტი.
  • შეამოწმეთ, ეკუთვნის თუ არა ობიექტი კონკრეტულ ტიპს isinstance() ფუნქციის დახმარებით.
  • issubclass() ამოწმებს, არის თუ არა ერთი კლასი მეორე კლასის შთამომავალი (მემკვიდრე).

🕵️‍♂️ ტიპების გამოკვლევა (Type Investigation)

მოდით, ვნახოთ, როგორ მუშაობს ეს პრაქტიკაში უკეთესი მაგალითებით:

# გავიგოთ, რა ტიპისაა ჩვენი მონაცემები 
type(99)                   # აბრუნებს: <class 'int'> (მთელი რიცხვი)
type(99.9)                 # აბრუნებს: <class 'float'> (ათწილადი)
type("გამარჯობა Python")   # აბრუნებს: <class 'str'> (სტრიქონი / ტექსტი)
type(False)                # აბრუნებს: <class 'bool'> (ლოგიკური ტიპი)
type(None)                 # აბრუნებს: <class 'NoneType'> (სიცარიელე)

# ვამოწმებთ, არის თუ არა 99.9 ნამდვილად ათწილადი (float)
isinstance(99.9, float)    # აბრუნებს: True (ჭეშმარიტია)

# ვამოწმებთ, მოდის თუ არა 'int' კლასი მთავარი 'object' კლასიდან
issubclass(int, object)    # აბრუნებს: True — Python-ში ყველაფერი object-ის მემკვიდრეა! 👑

🔄 ტიპების კონვერტაცია (Type Conversion)

ხშირად დაგჭირდებათ მონაცემის ერთი ტიპიდან მეორეში გადაყვანა. აი, როგორ ხდება ეს:

# ტექსტის გადაქცევა რიცხვებად
int("100")                 # 100 (ტექსტი გადაიქცა მთელ რიცხვად)
float("5.75")              # 5.75 (ტექსტი გადაიქცა ათწილადად)

# რიცხვის გადაქცევა ტექსტად (მაგალითად, სხვა ტექსტთან შესაერთებლად)
str(100)                   # "100" (ახლა ის უკვე ტექსტია)

# რიცხვების ლოგიკურ ტიპად (boolean) გადაქცევა
bool(1)                    # True (1 ნიშნავს ჭეშმარიტს)
bool(0)                    # False (0 ნიშნავს მცდარს)

# ტექსტის დაშლა სიის (list) ელემენტებად
list("Python")             # აბრუნებს: ['P', 'y', 't', 'h', 'o', 'n'] 🪄

ცვლადები და მინიჭება (Variables & Assignment) 📦

  • ცვლადები იქმნება მაშინვე, როცა მათ პირველად მიანიჭებთ მნიშვნელობას (ზედმეტი ფორმალობების და წინასწარი გამოცხადების გარეშე! ✨).
  • გამოიყენეთ ინფორმაციული, აღწერილობითი სახელები, რათა კოდი მარტივად იკითხებოდეს (მაგალითად, user_age ბევრად სჯობს უბრალოდ x-ს).
  • დაიცავით snake_case (გველისებრი) წერის სტილი — ანუ სიტყვები ერთმანეთისგან გამოყავით ქვედა ტირით _ (მაგალითად: high_score).

🛠️ ბაზისური მინიჭება (Basic Assignment)

მოდით, შევქმნათ ვიდეო თამაშის პერსონაჟის მონაცემები უფრო ნათელი მაგალითისთვის:

player_name = "შოთა"        # ტექსტი (String)
level = 42                  # მთელი რიცხვი (Integer)
health_points = 99.5        # ათწილადი (Float)
has_magic_armor = True      # ლოგიკური ტიპი (Boolean - ჭეშმარიტია)
active_curse = None         # None ტიპი (პერსონაჟს არანაირი წყევლა არ ადევს! 😇)

👯‍♂️ პარალელური და ჯაჭვური მინიჭება (Parallel & Chained Assignments)

Python საშუალებას გაძლევთ, რამდენიმე ცვლადს მნიშვნელობა ერთდროულად, ერთ ხაზზე მიანიჭოთ. ეს კოდს ბევრად კომპაქტურს ხდის:

# პარალელური მინიჭება (მაგალითად, ეკრანის სიგანე და სიმაღლე)
screen_width, screen_height = 1920, 1080  

# ჯაჭვური მინიჭება (თამაშის დაწყებისას ყველა მოთამაშის ქულა ნულის ტოლია)
player1_score = player2_score = player3_score = 0  

🚀 გაფართოებული მინიჭება (Augmented Assignments)

ეს არის შემოკლებული (და ძალიან მოსახერხებელი) გზა ცვლადის უკვე არსებული მნიშვნელობის შესაცვლელად:

# დონის მომატება 1-ით (ზუსტად იგივეა, რაც: level = level + 1)
level += 1                 

# ქულების დაკარგვა (იგივეა, რაც: score = score - 50)
score -= 50                 

# სიის გაფართოება - ვამატებთ ახალ ნივთებს მოთამაშის ინვენტარში
inventory_items += ["ჯადოსნური ხმალი", "ფარი"]  

სტრიქონები / ტექსტური მონაცემები (Strings) 🧵

  • ტექსტური მონაცემებისთვის (სტრიქონებისთვის) რეკომენდებულია ორმაგი ბრჭყალების (" ") გამოყენება.
  • გამოიყენეთ \n სტრიქონში ახალი ხაზის (Line break) შესაქმნელად.
  • თუ ტექსტში უკუქანობის (\, ე.წ. backslash) დაწერა გსურთ, უნდა გამოიყენოთ ორი ცალი: \\.

✍️ ტექსტუალური მონაცემების (სტრიქონების) შექმნა

ტექსტის დაწერა რამდენიმე გზით შეგვიძლია:

single_quotes = 'გამარჯობა'
double_quotes = "საქართველო"
multi_line = """ეს არის
მრავალხაზიანი
ტექსტი 📝"""

🧮 სტრიქონების ოპერაციები (String Operations)

ტექსტებზე შეგვიძლია გამოვიყენოთ მათემატიკური ოპერატორებიც!

# ტექსტების გადაბმა (Concatenation)
greeting = "გამარ" + "ჯობა!"         # აბრუნებს: "გამარჯობა!"

# ტექსტის გამრავლება (გამეორება)
cheer = "ჰეი! " * 3                  # აბრუნებს: "ჰეი! ჰეი! ჰეი! "

# ტექსტის სიგრძის (სიმბოლოების რაოდენობის) გაგება
text_length = len("პროგრამირება")     # აბრუნებს: 12

🛠️ სტრიქონების მეთოდები (String Methods)

Python-ს ტექსტებთან სამუშაოდ ბევრი ჩაშენებული „სუპერძალა“ აქვს:

"Python".upper()                     # "PYTHON" (ყველა ასო დიდი)
"PYTHON".lower()                     # "python" (ყველა ასო პატარა)
"   სიცარიელე   ".strip()            # "სიცარიელე" (აშორებს ზედმეტ სივრცეებს)
"ბნელი ღამე".replace("ბნელი", "ნათელი") # "ნათელი ღამე" (ანაცვლებს სიტყვას)
"ვაშლი მსხალი ატამი".split()         # ['ვაშლი', 'მსხალი', 'ატამი'] (ტექსტს შლის სიად)
", ".join(["თბილისი", "ბათუმი"])     # "თბილისი, ბათუმი" (აერთებს სიას ერთ ტექსტად)

✂️ ინდექსირება და ამოჭრა (String Indexing & Slicing)

Python-ში თვლა 0-დან იწყება. თქვენ შეგიძლიათ ამოიღოთ კონკრეტული ასოები ან ტექსტის ნაწილი:

word = "პროგრამა"

word[0]      # "პ" (პირველი სიმბოლო)
word[-1]     # "ა" (ბოლო სიმბოლო - ითვლის უკნიდან!)
word[1:4]    # "როგ" (ამოჭრა მე-1-დან მე-4 ინდექსამდე)
word[:3]     # "პრო" (დასაწყისიდან მე-3 ინდექსამდე)
word[3:]     # "გრამა" (მე-3 ინდექსიდან ბოლომდე)
word[::2]    # "პორმ" (აბრუნებს ყოველ მეორე სიმბოლოს)
word[::-1]   # "ამარგორპ" (მთლიანი ტექსტის შებრუნება 🔄)

🎨 სტრიქონების ფორმატირება (String Formatting)

ცვლადების ტექსტში ჩასმის საუკეთესო და თანამედროვე გზა ე.წ. f-strings არის.

# f-strings (თანამედროვე და უმარტივესი გზა ✨)
hero = "ბეტმენი"
city = "გოთემი"

f"გამარჯობა, მე ვარ {hero}!"                 # "გამარჯობა, მე ვარ ბეტმენი!"
f"{hero} იცავს ქალაქს სახელით: {city}"       # "ბეტმენი იცავს ქალაქს სახელით: გოთემი"
f"Debug: {hero=}"                          # "Debug: hero='ბეტმენი'" 

# .format() მეთოდი
template = "გამარჯობა, {user}! შენი ბალანსია {balance} ₾."
template.format(user="გიორგი", balance=150)  # "გამარჯობა, გიორგი! შენი ბალანსია 150 ₾."

🛡️ დაუფორმატებელი, ნედლი სტრიქონები (Raw Strings)

როდესაც გინდათ, რომ Python-მა დააიგნოროს სპეციალური სიმბოლოები (მაგალითად \n ან \t), ტექსტის წინ უნდა დაწეროთ ასო r. ეს განსაკუთრებით გამოსადეგია ფაილების მისამართების (File paths) წერისას!

# ჩვეულებრივი სტრიქონი 
normal_path = "C:\new_folder\test"    # ❌ არასწორია! დაიბეჭდება უცნაურად.

# Raw (ნედლი) სტრიქონი
raw_path = r"C:\new_folder\test"      # ✅ სწორია! დაიბეჭდება ზუსტად ისე, როგორც წერია.

რიცხვები და მათემატიკა (Numbers & Math) 🧮

Python ნამდვილი მათემატიკური გენიოსია! მასთან ერთად რთული გამოთვლებიც კი ძალიან მარტივი და სახალისო ხდება. მოდით, ვნახოთ ძირითადი ოპერაციები და ჩაშენებული ფუნქციები. 🚀

➕ მათემატიკური ოპერატორები (Arithmetic Operators)

20 + 5      # 25 (მიმატება)
20 - 5      # 15 (გამოკლება)
20 * 5      # 100 (გამრავლება)

# გაყოფა Python-ში ყოველთვის აბრუნებს ათწილადს (Float)
20 / 4      # 5.0 (ჩვეულებრივი გაყოფა)

# მთელ რიცხვამდე გაყოფა (Floor division) - აშორებს ათწილადის ნაწილს
20 // 3     # 6 (რადგან 20-ში 3 მოთავსდება 6-ჯერ)

# ნაშთი (Modulo) - გვიბრუნებს იმას, რაც გაყოფის შემდეგ მორჩა
20 % 3      # 2 (18 იყოფა 3-ზე, რჩება 2)

# ხარისხში აყვანა
3 ** 2      # 9 (3 კვადრატში)

🧰 სასარგებლო ფუნქციები (Useful Functions)

Python-ს აქვს წინასწარ გამზადებული, ძალიან მოსახერხებელი ფუნქციები რიცხვებთან სამუშაოდ:

# აბსოლუტური მნიშვნელობა (მოდული) - ყოველთვის აბრუნებს დადებით რიცხვს
abs(-42)                 # 42 

# დამრგვალება უახლოეს მთელ რიცხვამდე
round(9.8)               # 10

# დამრგვალება კონკრეტულ ათწილადამდე (მაგალითად, 2 ნიშნა მძიმის შემდეგ)
round(2.71828, 2)        # 2.72 

# ყველაზე პატარა რიცხვის პოვნა
min(10, 5, 100, 2)       # 2

# ყველაზე დიდი რიცხვის პოვნა
max(10, 5, 100, 2)       # 100

# სიაში არსებული ყველა რიცხვის ჯამის გამოთვლა
sum([10, 20, 30])        # 60 (ძალიან გამოსადეგია ფინანსების დამთვლელ კოდში! 💰)

პირობითი ოპერატორები (Conditionals) 🚦

სხვა ენებისგან განსხვავებით, სადაც კოდის ბლოკები ფიგურული ფრჩხილებით {} გამოიყოფა, Python იყენებს შეწევას (indentation — ხაზის დასაწყისში გამოტოვებულ ადგილებს).

  • 🌟 ოქროს წესი: ყოველი ახალი ბლოკის დასაწყებად გამოიყენეთ 4 ცარიელი ადგილი (space).

🔀 If-Elif-Else (თუ, სხვა შემთხვევაში, ყველა სხვა შემთხვევაში)

მოდით, შევქმნათ პროგრამა, რომელიც მოთამაშეს მისი ქულების მიხედვით წოდებას ანიჭებს:

score = 350

if score < 100:
    rank = "დამწყები მოთამაშე 🐣"
elif score < 500:
    rank = "გამოცდილი გეიმერი 🎮"
else:
    rank = "ნამდვილი ლეგენდა 👑"

⚖️ შედარების ოპერატორები (Comparison Operators)

აი, როგორ ვადარებთ მონაცემებს ერთმანეთს უფრო გასაგები ცვლადებით:

health == 100       # უდრის (არის თუ არა სიცოცხლე ზუსტად 100-ის ტოლი?)
password != "1234"  # არ უდრის (პაროლი არ არის "1234")
level < 10          # ნაკლებია 
temperature <= 0    # ნაკლებია ან ტოლია (გაიყინა წყალი? 🧊)
speed > 120         # მეტია (ჯარიმა სიჩქარის გადაჭარბებისთვის! 🚓)
age >= 18           # მეტია ან ტოლია (არის თუ არა პირი სრულწლოვანი?)

🧠 ლოგიკური ოპერატორები (Logical Operators)

ლოგიკური ოპერატორები დაგეხმარებათ რამდენიმე პირობის ერთდროულად შემოწმებაში:

# AND (და) - ორივე პირობა აუცილებლად ჭეშმარიტი უნდა იყოს
if has_sword and level >= 10:
    print("შენ მზად ხარ დრაკონთან საბრძოლველად! 🐉")

# OR (ან) - საკმარისია, მხოლოდ ერთი პირობა იყოს ჭეშმარიტი
if is_saturday or is_sunday:
    print("დღეს შაბათ-კვირაა! შეგვიძლია დავისვენოთ. 🏖️")

# NOT (არა) - აბრუნებს საპირისპიროს
if not is_tired:
    print("დაღლილი არ ვარ, მოდი სერიალის კიდევ ერთ ეპიზოდს ვუყუროთ... 📺")

ციკლები (Loops) 🔄

ციკლები საშუალებას გვაძლევს, ერთი და იგივე კოდი რამდენჯერმე, ავტომატურად გავუშვათ.

  • range(5) გამოიმუშავებს რიცხვებს 0-დან 4-ის ჩათვლით (რადგან Python თვლას 0-დან იწყებს).
  • გამოიყენეთ enumerate(), თუ ციკლში ელემენტთან ერთად მისი ინდექსის (რიგითი ნომრის) გაგებაც გჭირდებათ.
  • break სრულად აჩერებს და წყვეტს ციკლს, ხოლო continue უბრალოდ ტოვებს მიმდინარე ნაბიჯს და მაშინვე გადადის შემდეგზე.
  • გაფრთხილება: ფრთხილად იყავით while ციკლთან — დარწმუნდით, რომ მისი გაჩერების პირობა აუცილებლად შესრულდება, თორემ უსასრულო ციკლში (infinite loop) გაიჭედებით და პროგრამა "გაიჭედება"! ♾️

🔁 For ციკლები (For Loops)

ეს არის საუკეთესო გზა, როცა წინასწარ ვიცით, რამდენჯერ გვინდა კოდის გამეორება, ან როცა სიის ელემენტებზე გვინდა გადავლა.

# 1. რიცხვების გენერაცია range()-ით
for i in range(5):      # დაიბეჭდება 0, 1, 2, 3, 4
    print(f"მიმდინარე რიცხვია: {i}")

# 2. კოლექციაზე (მაგალითად, სიაზე) გადავლა
heroes = ["ბეტმენი", "სპაიდერმენი", "რკინის კაცი"]
for hero in heroes:
    print(f"ქალაქს იცავს: {hero} 🦸‍♂️")

# 3. enumerate()-ის გამოყენება ინდექსის (რიგითობის) მისაღებად
for index, hero in enumerate(heroes):
    print(f"გმირი №{index}: {hero}") 

⏳ While ციკლები (While Loops)

while ციკლი მუშაობს მანამ, სანამ მითითებული პირობა ჭეშმარიტია (True). ის იდეალურია ისეთი სიტუაციებისთვის, როცა არ ვიცით, ზუსტად რამდენჯერ მოგვიწევს კოდის გამეორება.

# ინტერაქტიული პროგრამა, რომელიც არ გაჩერდება, სანამ მომხმარებელი არ მოინდომებს
while True:
    command = input("შეიყვანეთ ბრძანება (ან დაწერეთ 'quit' გასასვლელად): ")
    
    if command == "quit":
        print("პროგრამა დასრულდა. ნახვამდის! 👋")
        break  # ციკლიდან სასწრაფო გამოსვლა
        
    print(f"თქვენი ბრძანება '{command}' მიღებულია! 🚀")

🎮 ციკლის კონტროლი (Loop Control)

ზოგჯერ გვჭირდება ციკლის სტანდარტულ მსვლელობაში ჩარევა და მისი წესების შეცვლა:

for step in range(1, 11):  # ითვლის 1-დან 10-მდე (11 არ შედის)
    
    if step == 4:
        print("--- მე-4 ნაბიჯი გამოვტოვეთ! 🚫")
        continue  # აიგნორებს ქვედა კოდს და ეგრევე გადადის მე-5 ნაბიჯზე
        
    if step == 8:
        print("--- მივაღწიეთ მე-8 ნაბიჯს, ვწყვეტთ მუშაობას! 🛑")
        break     # სრულად ამსხვრევს და აჩერებს ციკლს
        
    print(f"ვასრულებთ ნაბიჯს: {step}")

ჩადგმული For ციკლები (Nested For Loops) 🪆

ჩადგმული ციკლი ნიშნავს ციკლს მეორე ციკლის შიგნით. მთავარი წესი ასეთია: შიდა ციკლი სრულად ასრულებს თავის მუშაობას გარე ციკლის თითოეულ ნაბიჯზე.

მოდით, შევქმნათ პროგრამა, რომელიც ყველა შესაძლო ნაყინის დესერტს დაგვიმზადებს! 🍦

# გვაქვს ნაყინის გემოების და დანამატების (ტოპინგების) სიები
ice_cream_flavors = ["შოკოლადის", "ვანილის"]
toppings = ["კარამელით", "თხილით", "მარწყვის სიროფით"]

print("მოემზადეთ, ვიწყებთ ნაყინის კომბინაციების შექმნას! 👨‍🍳👇\n")

# გარე ციკლი - გადის ნაყინის თითოეულ გემოზე
for flavor in ice_cream_flavors:
    
    print(f"--- 🍨 ვაკეთებთ {flavor} ნაყინს: ---")
    
    # შიდა ციკლი - უმატებს ყველა შესაძლო ტოპინგს მიმდინარე გემოს
    for topping in toppings:
        print(f"  ✨ {flavor} ნაყინი {topping}")
        
    print()  # ვბეჭდავთ ცარიელ ხაზს ვიზუალური სილამაზისთვის

ფუნქციები (Functions) ⚙️

ფუნქციები პროგრამირებაში ჯადოსნურ რეცეპტებს ჰგავს — ერთხელ დაწერთ ინსტრუქციას და შემდეგ შეგიძლიათ უთვალავჯერ გამოიყენოთ! 🧑‍🍳

  • ფუნქციები იქმნება (განისაზღვრება) def საკვანძო სიტყვის გამოყენებით.
  • ფუნქციის გასაშვებად (გამოსაძახებლად) ყოველთვის აუცილებელია ფრჩხილების () მიწერა.
  • გამოიყენეთ return, რათა ფუნქციამ თავისი მუშაობის შედეგი უკან დაგიბრუნოთ.
  • თუ პატარა, ერთჯერადი ფუნქცია გჭირდებათ, შეგიძლიათ შექმნათ ანონიმური ფუნქცია lambda სიტყვის დახმარებით.

📝 ფუნქციების შექმნა (Defining Functions)

# მარტივი ფუნქცია, რომელიც არ ითხოვს პარამეტრებს
def make_coffee():
    return "თქვენი ცხელი ყავა მზადაა! ☕"

# ფუნქცია, რომელიც იღებს ერთ პარამეტრს (მომხმარებლის სახელს)
def greet_customer(name):
    return f"გამარჯობა, {name}! რას ინებებთ დღეს?"

# ფუნქცია საწყისი (Default) მნიშვნელობით
def calculate_total(price, tip=2):
    return price + tip

📞 ფუნქციების გამოძახება (Calling Functions)

make_coffee()                   # აბრუნებს: "თქვენი ცხელი ყავა მზადაა! ☕"

greet_customer("გიორგი")       # აბრუნებს: "გამარჯობა, გიორგი! რას ინებებთ დღეს?"

# ვუთითებთ ფასსაც და ჩაის რაოდენობასაც
calculate_total(10, 5)          # აბრუნებს: 15 (10 + 5)

# ვუთითებთ მხოლოდ ფასს, "tip" ავტომატურად გახდება 2
calculate_total(10)             # აბრუნებს: 12 (10 + 2)

🔄 მნიშვნელობების დაბრუნება (Return Values)

ფუნქციას შეუძლია ერთდროულად რამდენიმე მნიშვნელობა დააბრუნოს. მოდით, დავწეროთ ფუნქცია, რომელიც ტესტის ქულებიდან ყველაზე დაბალსა და მაღალს იპოვის:

def get_lowest_and_highest(grades):
    return min(grades), max(grades)

# ფუნქციის დაბრუნებული ორი მნიშვნელობა შეგვიძლია პირდაპირ ორ ცვლადს მივანიჭოთ!
lowest_score, highest_score = get_lowest_and_highest([85, 92, 78, 100, 65])

# lowest_score გახდება 65
# highest_score გახდება 100

🧰 სასარგებლო ქარხნულად მოცემული ფუნქციები პითონში (Built-in Functions)

Python-ში უკვე არსებობს უამრავი გამზადებული ფუნქცია, რომელიც ცხოვრებას გვიმარტივებს:

callable(make_coffee) # ამოწმებს, შეიძლება თუ არა ამ ობიექტის ფუნქციად გამოძახება
dir(text)             # გიჩვენებთ კონკრეტული ობიექტის ყველა შესაძლო მეთოდს და ატრიბუტს
globals()             # გაძლევთ ლექსიკონს ყველა გლობალური ცვლადით
hash("პაროლი")        # აბრუნებს ობიექტის ჰეშს (უნიკალურ რიცხვობრივ კოდს)
id(name)              # გიჩვენებთ ობიექტის უნიკალურ მისამართს კომპიუტერის მეხსიერებაში
locals()              # გაძლევთ ლოკალური ცვლადების სიას 
repr("ტექსტი")        # აბრუნებს ობიექტის ტექსტურ რეპრეზენტაციას (კარგია დებაგინგისთვის 🐛)

⚡ Lambda ფუნქციები (Lambda Functions)

lambda არის ძალიან მოკლე, 1-ხაზიანი ფუნქცია, რომელსაც სახელიც კი არ სჭირდება. ის ხშირად გამოიყენება მონაცემების გასაფილტრად ან შესაცვლელად.

# ვქმნით ლამბდა ფუნქციას, რომელიც აორმაგებს რიცხვს
double_power = lambda power: power * 2
result = double_power(50)  # აბრუნებს: 100

# map და filter ფუნქციებთან კომბინაციაში ლამბდა ნამდვილი მხეცია! 🐉
power_levels = [10, 25, 40, 100]

# map: ყველა მნიშვნელობას ვუორმაგებთ ძალას
doubled = list(map(lambda p: p * 2, power_levels))        
# შედეგი: [20, 50, 80, 200]

# filter: ვტოვებთ მხოლოდ იმ გმირებს, ვისი ძალაც 30-ზე მეტია
strong_only = list(filter(lambda p: p > 30, power_levels)) 
# შედეგი: [40, 100]

კლასები (Classes) 🏗️

კლასები ობიექტზე ორიენტირებული პროგრამირების (OOP-ის) გულია! წარმოიდგინეთ, რომ კლასი არის შაბლონი, პროექტი ან ნახაზი, რომლის მიხედვითაც რეალურ ობიექტებს ვქმნით.

  • კლასები არის შაბლონები (blueprints) ობიექტების შესაქმნელად.
  • ერთი კლასიდან შეგიძლიათ შექმნათ მრავალი ეგზემპლარი (instance / რეალური ობიექტი).
  • ისინი გამოიყენება მონაცემების ერთ სივრცეში მოსაქცევად (encapsulate), რათა კოდი უფრო ორგანიზებული იყოს.
  • კლასის შიგნით თქვენ ქმნით მეთოდებს (იგივე ფუნქციებს), რომლებიც ამ მონაცემებთან მუშაობენ.
  • __init__() არის კონსტრუქტორი მეთოდი — ის ავტომატურად ეშვება ობიექტის შექმნისას.
  • self მიუთითებს თავად იმ კონკრეტულ ეგზემპლარზე, რომელზეც იმ მომენტში ვმუშაობთ.

🛠️ კლასების შექმნა (Defining Classes)

მოდით, შევქმნათ რობოტების ქარხანა. კლასი გვეტყვის, როგორი უნდა იყოს რობოტი, შემდეგ კი რეალურ რობოტს ავაწყობთ!

class Robot:
    # კონსტრუქტორი, რომელიც რობოტის შექმნისას ავტომატურად გაეშვება
    def __init__(self, name, version):
        self.name = name         # რობოტის სახელი
        self.version = version   # მოდელის ვერსია

    # მეთოდი, რომელიც რობოტს ლაპარაკის საშუალებას აძლევს
    def say_hello(self):
        return f"გამარჯობა! მე ვარ {self.name}, ვერსია: {self.version}. ბიპ-ბუპ! 🤖"

# ვქმნით კლასის ეგზემპლარს (ანუ ვაწყობთ რეალურ რობოტს)
my_robot = Robot("ვალ-ი", 2.0)

# გამოვიძახოთ რობოტის მეთოდი
print(my_robot.say_hello())  # დაიბეჭდება: გამარჯობა! მე ვარ ვალ-ი, ვერსია: 2.0. ბიპ-ბუპ! 🤖

✨ კლასის ატრიბუტები და მეთოდები (Class Attributes & Methods)

ზოგიერთი მახასიათებელი საერთოა კლასის ყველა ობიექტისთვის, ზოგი კი — ინდივიდუალური. ვნახოთ ეს ჯადოქრების მაგალითზე:

class Wizard:
    # კლასის ატრიბუტი (ეს ყველასთვის საერთოა - ყველა ჯადოქარი იყენებს მანას)
    power_source = "მაგიური ენერგია (Mana)"   

    def __init__(self, name):
        # ეგზემპლარის ატრიბუტი (უნიკალურია თითოეულისთვის)
        self.name = name      

    def cast_spell(self):
        return f"{self.name} იყენებს ჯადოსნურ შელოცვას! ✨"

    # კლასის მეთოდი მუშაობს თავად კლასზე (cls) და არა კონკრეტულ ობიექტზე (self)
    @classmethod
    def create_apprentice(cls, master_name):
        return cls(f"{master_name}-ის შეგირდი")

# ვქმნით ახალ ჯადოქარს კლასის მეთოდის (@classmethod) გამოყენებით
new_wizard = Wizard.create_apprentice("განდალფ")

print(new_wizard.cast_spell())  # დაიბეჭდება: განდალფ-ის შეგირდი იყენებს ჯადოსნურ შელოცვას! ✨

🧬 მემკვიდრეობითობა (Inheritance)

მემკვიდრეობითობა საშუალებას გვაძლევს, შევქმნათ მთავარი (მშობელი) კლასი, ხოლო მისმა შვილობილმა კლასებმა "მემკვიდრეობით" მიიღონ მისი თვისებები. ეს გვეხმარება კოდის განმეორების თავიდან არიდებაში.

# მთავარი, ზოგადი კლასი (მშობელი კლასი)
class Character:
    def __init__(self, name):
        self.name = name

    def attack(self):
        pass  # 'pass' ნიშნავს, რომ ფუნქცია ჯერ ცარიელია

# შვილობილი კლასი, რომელიც Character-ისგან იღებს თვისებებს
class Warrior(Character):
    # აქ ჩვენ მშობლის ცარიელ attack მეთოდს ვცვლით ჩვენთვის სასურველით (Overriding)
    def attack(self):
        return f"{self.name} უტევს მძიმე მახვილით! ⚔️"

# კიდევ ერთი შვილობილი კლასი
class Archer(Character):
    def attack(self):
        return f"{self.name} ზუსტად ისვრის ცეცხლოვან ისარს! 🏹"

# შევქმნათ სხვადასხვა ტიპის პერსონაჟები
hero1 = Warrior("არაგორნი")
hero2 = Archer("ლეგოლასი")

print(hero1.attack())  # დაიბეჭდება: არაგორნი უტევს მძიმე მახვილით! ⚔️
print(hero2.attack())  # დაიბეჭდება: ლეგოლასი ზუსტად ისვრის ცეცხლოვან ისარს! 🏹

გამონაკლისები და შეცდომები (Exceptions) 🚨

როდესაც Python კოდის გაშვებისას პრობლემას აწყდება, პროგრამის უბრალოდ გათიშვის ნაცვლად, ის წარმოქმნის ე.წ. "გამონაკლისს" (Exception). ჩვენ შეგვიძლია ეს შეცდომები დავიჭიროთ და ვმართოთ, რათა პროგრამამ მუშაობა განაგრძოს! 🦸‍♂️

  • მაქსიმალურად შეეცადეთ, გამოიყენოთ შეცდომის კონკრეტული ტიპები (და არა უბრალოდ ზოგადი).
  • else ბლოკი გაეშვება მხოლოდ მაშინ, თუ კოდმა შეცდომის გარეშე იმუშავა.
  • finally ბლოკი გაეშვება ყოველთვის, მიუხედავად იმისა მოხდა თუ არა შეცდომა (იდეალურია საქმის საბოლოოდ დასასრულებლად!).

🛡️ Try-Except (შეცდომების დაჭერა)

მოდით, დავწეროთ პროგრამა, რომელიც ერთ მთლიან პიცას მეგობრებზე ანაწილებს. აქ მომხმარებლის მხრიდან ბევრი რამ შეიძლება წავიდეს ცუდად!

try:
    friends = int(input("რამდენი მეგობარი ინაწილებს პიცას? "))
    slices_per_person = 8 / friends
    
except ValueError:
    # გაეშვება, თუ მომხმარებელი რიცხვის ნაცვლად ასოებს ჩაწერს (მაგ: "ორი")
    print("❌ შეცდომა: გთხოვთ, შეიყვანოთ ციფრი და არა ტექსტი!")
    
except ZeroDivisionError:
    # გაეშვება, თუ მომხმარებელი ჩაწერს 0-ს
    print("❌ შეცდომა: ნულ მეგობარზე პიცას ვერ გავყოფთ! მარტო ხარ? 😢🍕")
    
else:
    # გაეშვება მხოლოდ მაშინ, თუ ყველაფერმა კარგად ჩაიარა
    print(f"✅ შესანიშნავია! თითოეულს შეხვდება {slices_per_person} ნაჭერი პიცა.")
    
finally:
    # გაეშვება ნებისმიერ შემთხვევაში
    print("🏁 პიცის კალკულატორმა დაასრულა მუშაობა.")

👾 გავრცელებული შეცდომები (Common Exceptions)

აი, ის ძირითადი შეცდომები, რომლებსაც ყველაზე ხშირად შეხვდებით კოდის წერისას:

ValueError         # არასწორი მნიშვნელობა (მაგ: ტექსტის "ა"-ს გადაქცევა რიცხვად)
TypeError          # არასწორი ტიპი (მაგ: ტექსტისა და რიცხვის შეკრების მცდელობა 💥)
IndexError         # ინდექსი საზღვრებს გარეთაა (ცდილობთ მე-10 ელემენტის ამოღებას სიიდან, სადაც მხოლოდ 3 ნივთია)
KeyError           # ლექსიკონში (Dictionary) მითითებული გასაღები ვერ მოიძებნა
FileNotFoundError  # ფაილი კომპიუტერში არ არსებობს (ვერ ვიპოვეთ! 🕵️‍♂️)

💣 შეცდომების ხელოვნურად გამოწვევა (Raising Exceptions)

ზოგჯერ გვინდა, რომ ჩვენმა პროგრამამ თავად ატეხოს განგაში და გაჩერდეს, თუ რაიმე წესების საპირისპიროდ ხდება. ამისთვის ვიყენებთ raise სიტყვას.

def set_warp_speed(speed):
    # თუ სისწრაფე კრიტიკულ ზღვარს სცდება, ჩვენ თავად ვქმნით შეცდომას!
    if speed > 10:
        raise ValueError("ძრავები აფეთქდება! სისწრაფე 10-ს არ უნდა აღემატებოდეს! 🚀💥")
        
    return f"კოსმოსური ხომალდი მიფრინავს სისწრაფით: {speed}"

# თუ გამოვიძახებთ set_warp_speed(15)-ს, პროგრამა გაჩერდება 
# და ჩვენს მიერ დაწერილ შეტყობინებას გამოიტანს ეკრანზე.

კოლექციები (Collections) 🎒

კოლექცია არის ნებისმიერი კონტეინერის ტიპის მონაცემთა სტრუქტურა, რომელიც ერთად ინახავს რამდენიმე ელემენტს.

  • თუ ობიექტი კოლექციაა, თქვენ შეგიძლიათ მასზე ციკლით (loop) გადავლა. (სხვათა შორის, ტექსტებიც, ანუ Strings, კოლექციებს წარმოადგენს! 🧶)
  • გამოიყენეთ len(), რათა გაიგოთ, რამდენი ელემენტია კოლექციაში.
  • იმის შესამოწმებლად, მოიძებნება თუ არა კონკრეტული ელემენტი კოლექციაში, გამოიყენეთ in საკვანძო სიტყვა.
  • ზოგიერთი კოლექცია შეიძლება ერთმანეთს ჰგავდეს, მაგრამ თითოეული მათგანი სრულიად კონკრეტულ საჭიროებებს ემსახურება.

📋 სიები (Lists)

სია არის ელემენტების მოწესრიგებული კოლექცია, რომლის შეცვლაც შეგიძლიათ. იდეალურია ნივთების ჩამონათვალის შესანახად.

# სიების შექმნა
empty_list = []
games = ["Minecraft"]
mixed_box = ["ჯადოსნური ჯოხი", 50, True, 3.14] # სიაში შეგიძლიათ სხვადასხვა ტიპის მონაცემი აურიოთ!

# სიის მეთოდები (როგორ ვმართოთ სია)
games.append("GTA V")             # სიაში ელემენტის ბოლოში დამატება
games.insert(0, "Tetris")         # კონკრეტულ ინდექსზე (დასაწყისში) ჩასმა
games.extend(["Zelda", "Mario"])  # სხვა სიის ელემენტების გადმოწერა ჩვენს სიაში
games.remove("Minecraft")         # კონკრეტული ელემენტის წაშლა (პირველს რასაც იპოვის)
last_game = games.pop()           # ამოაგდებს და დააბრუნებს სიის ბოლო ელემენტს ("Mario")

# ინდექსირება და შემოწმება
movies = ["მატრიცა", "ავატარი", "ინტერსტელარი"]

movies[0]                # "მატრიცა" (პირველი ელემენტი)
movies[-1]               # "ინტერსტელარი" (ბოლო ელემენტი)
"ავატარი" in movies        # True (ნამდვილად სიაშია! 🍿)
len(movies)              # 3 (სიაში სულ 3 ფილმია)

📦 კორტეჟები (Tuples)

Tuples ჰგავს სიებს, მაგრამ ისინი შეუცვლელია (immutable). მას შემდეგ რაც შექმნით, შიგნით ელემენტებს ვეღარ შეცვლით, წაშლით ან დაამატებთ. იდეალურია ისეთი მონაცემებისთვის, რომელიც მუდმივი უნდა იყოს.

# კორტეჟების (Tuples) შექმნა
treasure_cords = (41.71, 44.82)  # თბილისის კოორდინატები 🌍
single_item = ("ოქრო",)          # ყურადღება: 1 ელემენტისგან შემდგარ tuple-ს ბოლოში მძიმე სჭირდება! 
empty_tuple = ()

# ძირითადი განშლა (Unpacking)
lat, lon = treasure_cords 
# lat გახდება 41.71
# lon გახდება 44.82

# გაფართოებული განშლა (Extended unpacking)
first, *others = ("პირველი", "მეორე", "მესამე", "მეოთხე")

# first გახდება "პირველი"
# others გახდება სია: ["მეორე", "მესამე", "მეოთხე"] (ვარსკვლავი * აგროვებს დარჩენილებს)

🔮 სიმრავლეები (Sets)

Sets არის უნიკალური ელემენტებისგან შემდგარი კოლექცია, სადაც თანმიმდევრობა დაცული არ არის. იდეალურია დუბლიკატების წასაშლელად და მათემატიკური ოპერაციებისთვის.

# სიმრავლეების შექმნა
magic_spells = {"ცეცხლი", "ყინული", "მეხი"}
duplicate_list = ["ვაშლი", "მსხალი", "ვაშლი", "ატამი"]
unique_fruits = set(duplicate_list) # შედეგი: {"ვაშლი", "მსხალი", "ატამი"} - დუბლიკატები გაქრა! ✨

# სიმრავლეების ოპერაციები (ავიღოთ ორი მეგობრის საყვარელი ფერები)
zuka_colors = {"წითელი", "ლურჯი", "შავი"}
ani_colors = {"ლურჯი", "ყვითელი", "თეთრი"}

zuka_colors | ani_colors  # გაერთიანება (Union): ყველა უნიკალური ფერი ორივე სიმრავლიდან
zuka_colors & ani_colors  # თანაკვეთა (Intersection): რომელი ფერი უყვარს ორივეს? -> {"ლურჯი"} 
zuka_colors - ani_colors  # სხვაობა (Difference): რა უყვარს ზუკას ისეთი, რაც ანიმ არ აირჩია? -> {"წითელი", "შავი"} 
zuka_colors ^ ani_colors  # სიმეტრიული სხვაობა: ფერები, რომლებიც მხოლოდ ერთ-ერთს უყვარს (საერთოს გამოკლებით)

📖 ლექსიკონები (Dictionaries)

ლექსიკონები ინახავენ მონაცემებს "გასაღები-მნიშვნელობის" (key-value) წყვილებად. ეს მართლაც რეალურ ლექსიკონს ჰგავს, სადაც ეძებთ სიტყვას (key) და კითხულობთ მის განმარტებას (value).

# ლექსიკონების შექმნა
empty_dict = {}
player = {"nickname": "Shadow", "level": 99}

# ლექსიკონის ოპერაციები
player["weapon"] = "კატანა"         # ახალი გასაღებისა და მნიშვნელობის დამატება
player["level"] = 100               # არსებული მნიშვნელობის განახლება (გილოცავთ! 🎉)
xp = player.get("xp", 0)            # მნიშვნელობის წამოღება (.get გვიცავს შეცდომისგან. თუ 'xp' არ არსებობს, 0-ს დააბრუნებს)
del player["weapon"]                # გასაღების და მისი მნიშვნელობის სამუდამოდ წაშლა
removed_lvl = player.pop("level")   # შლის ელემენტს და თან გიბრუნებთ წაშლილ მნიშვნელობას (100)

# ლექსიკონის მეთოდები
enemy = {"name": "გობლინი", "hp": 50}

enemy.keys()         # აბრუნებს მხოლოდ გასაღებებს: dict_keys(['name', 'hp'])
enemy.values()       # აბრუნებს მხოლოდ მნიშვნელობებს: dict_values(['გობლინი', 50])
enemy.items()        # აბრუნებს ორივეს ერთად წყვილებად: dict_items([('name', 'გობლინი'), ('hp', 50)]

კომპრეჰენსიები (Comprehensions - შემოკლებული ციკლები) ⚡

წარმოიდგინეთ, რომ კომპრეჰენსიები არის მაქსიმალურად შეკუმშული, ერთ ხაზზე დაწერილი for ციკლები! 🪄

  • გარდა იმისა, რომ ასეთი კოდი ვიზუალურად უფრო ლამაზი და ლაკონიურია, ის სტანდარტულ ციკლებთან შედარებით გაცილებით სწრაფიცაა! 🏎️💨

📝 სიის კომპრეჰენსიები (List Comprehensions)

ეს არის ახალი სიის გენერირების (შექმნის) ყველაზე ელეგანტური გზა:

# ბაზისური: ვქმნით სიას 1-დან 5-ის ჩათვლით რიცხვების კვადრატებით
power_levels = [x**2 for x in range(1, 6)]  
# შედეგი: [1, 4, 9, 16, 25]

# პირობით (if): ვირჩევთ მხოლოდ ლუწ რიცხვებს 0-დან 20-მდე
even_numbers = [num for num in range(20) if num % 2 == 0]
# შედეგი: [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

# ჩადგმული (Nested): ვქმნით 3x3 სათამაშო დაფის კოორდინატებს (მატრიცას)
game_board = [[f"{row}x{col}" for col in range(3)] for row in range(3)]

# რას მოგვცემს game_board?
# [['0x0', '0x1', '0x2'], 
#  ['1x0', '1x1', '1x2'], 
#  ['2x0', '2x1', '2x2']]

🧩 სხვა სახის კომპრეჰენსიები (Other Comprehensions)

იგივე პრინციპი იდეალურად მუშაობს ლექსიკონებზე, სიმრავლეებსა და გენერატორებზეც!

# 📖 ლექსიკონის (Dictionary) კომპრეჰენსია
friends = ["ლუკა", "მარიამი", "ანა"]
name_lengths = {name: len(name) for name in friends}
# შედეგი: {'ლუკა': 4, 'მარიამი': 7, 'ანა': 3}

# 🔮 სიმრავლის (Set) კომპრეჰენსია
fruits = ["ვაშლი", "კივი", "ატამი", "ბალი"]
unique_lengths = {len(fruit) for fruit in fruits}
# შედეგი იქნება მხოლოდ უნიკალური რიცხვები: {4, 5}

# ⚙️ გენერატორის გამოსახულება (Generator expression)
# იდეალურია უზარმაზარი მონაცემებისთვის! ის არ ინახავს მთლიან სიას მეხსიერებაში.
massive_sum = sum(x**2 for x in range(1000)) 

ფაილების შეტანა/გამოტანა (File I/O) 📂

ფაილებთან მუშაობა Python-ში ძალიან მარტივია! with open(...) სტრუქტურის გამოყენება ოქროს სტანდარტია, რადგან ის ფაილს ავტომატურად ხურავს მასთან მუშაობის დასრულების შემდეგ (ასე თქვენს კომპიუტერს ზედმეტი "ღია კარებისგან" იცავთ 🧹).

📄 ფაილის ოპერაციები (File Operations)

მოდით, ვნახოთ როგორ ვკითხულობთ და ვწერთ ფაილებში, უფრო საინტერესო მაგალითებით:

# 1. მთლიანი ფაილის ერთიანად წაკითხვა (mode="r" ნიშნავს Read / წაკითხვას)
with open("secret_message.txt", mode="r", encoding="utf-8") as file:
    content = file.read()
    # ახლა 'content' ცვლადში შენახულია მთელი ფაილის ტექსტი! 🕵️‍♂️

# 2. ფაილის ხაზ-ხაზ წაკითხვა 
with open("spellbook.txt", mode="r", encoding="utf-8") as file:
    for line in file:
        print(line.strip()) 

# 3. ფაილში ჩაწერა (mode="w" ნიშნავს Write / ჩაწერას)
# ⚠️ ფრთხილად: "w" რეჟიმი სრულად წაშლის ფაილის ძველ შიგთავსს და თავიდან დაწერს!
with open("shopping_list.txt", mode="w", encoding="utf-8") as file:
    file.write("1. ჯადოსნური ჯოხი 🪄\n")
    file.write("2. მფრინავი ცოცხი 🧹\n")

# 4. ფაილში ინფორმაციის დამატება (mode="a" ნიშნავს Append / დამატებას)
with open("adventure_log.txt", mode="a", encoding="utf-8") as file:
    file.write("დღე 42: დრაკონი დამარცხებულია! 🐉⚔️\n")

იმპორტები და მოდულები (Imports & Modules) 📦

სხვა მოდულებისა და ბიბლიოთეკების კოდში შემოტანა (იმპორტი) Python-ს ნამდვილ სუპერძალას ანიჭებს! აი, საუკეთესო პრაქტიკები:

  • მოერიდეთ ვარსკვლავით (import *) შემოტანას. უმჯობესია, ზუსტად მიუთითოთ, რისი გამოყენება გსურთ. ეს გიცავთ გაუთვალისწინებელი შეცდომებისგან.
  • გამოიყენეთ მეტსახელები (aliases) გრძელი ან ძალიან ხშირად გამოყენებადი მოდულების სახელებისთვის (მაგ: import pandas as pd).
  • დააჯგუფეთ იმპორტები კოდის დასაწყისში: ჯერ Python-ის სტანდარტული ბიბლიოთეკები, შემდეგ გარე (გადმოწერილი) პაკეტები და ბოლოს თქვენ მიერ შექმნილი ლოკალური მოდულები.

🎨 შემოტანის სტილები (Import Styles)

მოდით, ვნახოთ სხვადასხვა გზა, თუ როგორ შეგვიძლია გამზადებული ინსტრუმენტების ჩვენს კოდში გადმოტანა:

# 1. მთლიანი მოდულის შემოტანა
import math
hero_power = math.sqrt(100)  # კვადრატული ფესვი 100-დან (აბრუნებს 10.0-ს)

# 2. კონკრეტული ფუნქციის შემოტანა (ეს ყველაზე გავრცელებული და მოსახერხებელი გზაა!)
from random import randint
dice_roll = randint(1, 6)    # კამათლის გაგორება 1-დან 6-მდე 🎲

# 3. მოდულის შემოტანა მეტსახელით (Alias) დასახელების შესამოკლებლად
import numpy as np
game_matrix = np.array([10, 20, 30])  # ვიყენებთ np-ს ნაცვლად numpy-სა

# 4. ყველაფრის ერთიანად შემოტანა ❌ (არ არის რეკომენდებული!)
from math import *

📦 პაკეტებიდან შემოტანა (Package Imports)

როდესაც დიდ პროექტზე მუშაობთ (მაგალითად, ვიდეო თამაშზე), კოდი ხშირად დაყოფილია მრავალ საქაღალდედ და ფაილად (პაკეტებად). აი, როგორ ვუკავშირდებით მათ:

# პაკეტიდან მთლიანი მოდულის შემოტანა
import game_engine.graphics                      # პირდაპირი გზა
from game_engine import physics                # უფრო მოსახერხებელი გზა
from game_engine.characters.monsters import ai # ქვე-პაკეტიდან შემოტანა

# პაკეტიდან კონკრეტული ნაწილების (ფუნქციის, კლასის) ამოღება
from weapons.swords import swing_sword, MagicSword

# მოდულის/ფუნქციის შემოტანა მეტსახელით 
from database.connection import connect as connect_to_db

# ახლა შეგვიძლია გამოვიყენოთ: connect_to_db() 🔌

სხვადასხვა (Miscellaneous) 🌟

🏷️ ტიპების მითითება (Type Hinting)

მიუხედავად იმისა, რომ Python დინამიური ენაა (ტიპებს თავად ხვდება), შეგიძლიათ მიუთითოთ ცვლადის ტიპები, რათა კოდი უფრო მარტივად წასაკითხი იყოს სხვა პროგრამისტებისთვის და თქვენმა ტექსტურმა რედაქტორმა (IDE) უკეთ დაგეხმაროთ შეცდომების პოვნაში.

# ვუთითებთ, რომ 'name' არის ტექსტი (str), 'age' - მთელი რიცხვი (int) 
# '-> str' კი ნიშნავს, რომ ფუნქცია საბოლოოდ ტექსტს დააბრუნებს.
def create_profile(name: str, age: int) -> str:
    return f"ახალი მოთამაშე: {name}, დონე: {age}"

# ეს კოდი ჩვეულებრივად იმუშავებს, უბრალოდ ახლა ის ბევრად უფრო ინფორმატიულია!

🦭 ლომვეშაპას ოპერატორი (Walrus Operator :=)

ეს სახალისო ოპერატორი (რომელიც მართლა ჰგავს ლომვეშაპას სახეს და ეშვებს!) საშუალებას გაძლევთ, მნიშვნელობა მიანიჭოთ ცვლადს და იმავდროულად გამოიყენოთ ის პირობაში. ეს ამცირებს კოდის ხაზების რაოდენობას.

secret_word = "ჰიდროელექტროსადგური"

# ვითვლით სიგრძეს, ვანიჭებთ 'length' ცვლადს და იქვე ვამოწმებთ მას!
if (length := len(secret_word)) > 15:
    print(f"ეს სიტყვა ძალიან გრძელია! ის შეიცავს {length} ასოს. 🤯")

დეკორატორების გზამკვლევი 🎁

დეკორატორი ხშირად ერთ-ერთი ყველაზე დამაბნეველი თემაა დამწყებთათვის, მაგრამ რეალურად ის ძალიან მარტივი და ლოგიკურია.

მარტივად რომ ვთქვათ: დეკორატორი არის ფუნქცია, რომელიც იღებს სხვა ფუნქციას, უკეთებს მას "შეფუთვას" (უმატებს ახალ თვისებებს) და აბრუნებს უკან ისე, რომ თავდაპირველი კოდი არ იცვლება. წარმოიდგინეთ, რომ ჩვეულებრივ ადამიანს უკბინა რადიოაქტივობით დასხივებულმა ობობამ — ადამიანი იგივე დარჩა, მაგრამ ახლა ქსელების გაშვება შეუძლია! 🦸‍♂️

1. შიდა სამზარეულო: როგორ მუშაობს ის?

Python-ში ფუნქციები ე.წ. "პირველი კლასის მოქალაქეები" არიან. ეს ნიშნავს, რომ თქვენ შეგიძლიათ ფუნქცია გადასცეთ სხვა ფუნქციას, როგორც ჩვეულებრივი ცვლადი.

მოდით, შევქმნათ მარტივი მაგალითი ნულიდან:

# 1. ეს არის ჩვენი დეკორატორი
def add_sprinkles(func):
    def wrapper():
        print("✨ ვამატებთ ფერად მოსართავებს")
        func() # აქ ვიძახებთ ორიგინალ ფუნქციას
        print("🍒 ვადგამთ ალუბალს თავზე!")
    return wrapper

# 2. ეს არის ჩვენი ჩვეულებრივი ფუნქცია
def make_ice_cream():
    print("🍨 ვამზადებთ ვანილის ნაყინს")

# 3. ვაკეთებთ "შეფუთვას" (დეკორირებას) ხელით:
decorated_ice_cream = add_sprinkles(make_ice_cream)

decorated_ice_cream() 
# დაიბეჭდება:
# ✨ ვამატებთ ფერად მოსართავებს (Sprinkles)...
# 🍨 ვამზადებთ ვანილის ნაყინს
# 🍒 ვადგამთ ალუბალს თავზე!

2. @ სიმბოლოს მაგია

ხელით decorated_ice_cream = add_sprinkles(make_ice_cream)-ის წერა დამღლელია. ამიტომ, Python-მა შემოგვთავაზა ულამაზესი სინტაქსი — @ (ე.წ. Pie syntax). ეს ზუსტად იმავეს აკეთებს, რასაც წინა კოდი, ოღონდ ავტომატურად.

# ვიყენებთ იგივე add_sprinkles დეკორატორს

@add_sprinkles
def make_chocolate_ice_cream():
    print("🍫 ვამზადებთ შოკოლადის ნაყინს")

make_chocolate_ice_cream() 
# ფუნქცია უკვე შეფუთულია! ის ავტომატურად დაამატებს მოსართავებსა და ალუბალს.

3. უნივერსალური დეკორატორები (*args, **kwargs)

რა მოხდება, თუ ჩვენს ორიგინალ ფუნქციას პარამეტრები სჭირდება (მაგალითად, ნაყინის ფასი ან ზომა)? ჩვენი წინა wrapper ფუნქცია შეცდომას ამოაგდებს, რადგან ის პარამეტრებს არ ელოდება.

ამის მოსაგვარებლად, wrapper-ში ვიყენებთ *args და **kwargs სიმბოლოებს. ეს ნიშნავს: "მიიღე ნებისმიერი რაოდენობის პარამეტრი და უბრალოდ გადააწოდე ორიგინალ ფუნქციას". მოდით, დავწეროთ დროის მთვლელი დეკორატორი, რომელიც ნებისმიერ ფუნქციას მოერგება:

import time

def timer_decorator(func):
    def wrapper(*args, **kwargs):
        start_time = time.time()          # ვინიშნავთ დაწყების დროს
        
        result = func(*args, **kwargs)    # ვუშვებთ მთავარ ფუნქციას
        
        end_time = time.time()            # ვინიშნავთ დასრულების დროს
        print(f"⏱️ ფუნქციამ '{func.__name__}' იმუშავა {end_time - start_time:.4f} წამი.")
        return result                     # ვაბრუნებთ ფუნქციის შედეგს
    return wrapper

@timer_decorator
def slow_function(name, delay_seconds):
    print(f"გამარჯობა {name}, ვიწყებ ფიქრს...")
    time.sleep(delay_seconds) # ვაჩერებთ პროგრამას რამდენიმე წამით
    return "ფიქრი დასრულებულია! 🧠"

# გამოვიძახოთ:
message = slow_function("გიორგი", 2)
print(message)

# დაიბეჭდება:
# გამარჯობა გიორგი, ვიწყებ ფიქრს...
# ⏱️ ფუნქციამ 'slow_function' იმუშავა 2.0021 წამი.
# ფიქრი დასრულებულია! 🧠

თუ ეს კონსპექტი სასარგებლო აღმოჩნდა და გსურთ, რომ Python-ის საფუძვლებიდან პროფესიონალურ დონემდე გაიზარდოთ, შემოგვიერთდით ScaleUp Academy-ის Python-ის კურსზე. ჩვენთან ერთად თქვენ არა მხოლოდ ისწავლით მშრალ სინტაქსს, არამედ შექმნით რეალურ პროექტებს, გაივლით სრულფასოვან პრაქტიკას და მიიღებთ გამოცდილი მენტორების მუდმივ მხარდაჭერას!


ავტორის შესახებ

გიგი ჩაკაბერია

back-end დეველოპერი და მენტორი