Ana içeriğe geç

Python Tiplerine Giriş

🌐 Yapay Zekâ ve İnsanlar Tarafından Çeviri

Bu çeviri, insanlar tarafından yönlendirilen bir yapay zekâ ile oluşturuldu. 🤝

Orijinal anlamın yanlış anlaşılması ya da kulağa doğal gelmeme gibi hatalar içerebilir. 🤖

Yapay zekâ LLM'ini daha iyi yönlendirmemize yardımcı olarak bu çeviriyi iyileştirebilirsiniz.

İngilizce sürüm

Python, isteğe bağlı "type hints" (diğer adıyla "type annotations") desteğine sahiptir.

Bu "type hints" veya annotations, bir değişkenin tip'ini bildirmeye yarayan özel bir sözdizimidir.

Değişkenleriniz için tip bildirerek, editörler ve araçlar size daha iyi destek sağlayabilir.

Bu, Python type hints hakkında sadece hızlı bir eğitim / bilgi tazeleme dokümanıdır. FastAPI ile kullanmak için gereken minimum bilgiyi kapsar... ki aslında bu çok azdır.

FastAPI tamamen bu type hints üzerine kuruludur; bunlar ona birçok avantaj ve fayda sağlar.

Ancak hiç FastAPI kullanmasanız bile, bunlar hakkında biraz öğrenmeniz size fayda sağlayacaktır.

Not

Eğer bir Python uzmanıysanız ve type hints hakkında her şeyi zaten biliyorsanız, sonraki bölüme geçin.

Motivasyon

Basit bir örnekle başlayalım:

def get_full_name(first_name, last_name):
    full_name = first_name.title() + " " + last_name.title()
    return full_name


print(get_full_name("john", "doe"))

Bu programı çalıştırınca şu çıktıyı alırsınız:

John Doe

Fonksiyon şunları yapar:

  • first_name ve last_name değerlerini alır.
  • title() ile her birinin ilk harfini büyük harfe çevirir.
  • Ortada bir boşluk olacak şekilde Birleştirir.
def get_full_name(first_name, last_name):
    full_name = first_name.title() + " " + last_name.title()
    return full_name


print(get_full_name("john", "doe"))

Düzenleyelim

Bu çok basit bir program.

Ama şimdi bunu sıfırdan yazdığınızı hayal edin.

Bir noktada fonksiyon tanımını yazmaya başlamış olacaktınız, parametreler hazır...

Ama sonra "ilk harfi büyük harfe çeviren method"u çağırmanız gerekiyor.

upper mıydı? uppercase miydi? first_uppercase? capitalize?

Sonra eski programcı dostuyla denersiniz: editör autocomplete.

Fonksiyonun ilk parametresi olan first_name'i yazarsınız, sonra bir nokta (.) ve ardından autocomplete'i tetiklemek için Ctrl+Space'e basarsınız.

Ama ne yazık ki, işe yarar bir şey göremezsiniz:

Tipleri ekleyelim

Önceki sürümden tek bir satırı değiştirelim.

Fonksiyonun parametreleri olan şu parçayı:

    first_name, last_name

şuna çevireceğiz:

    first_name: str, last_name: str

Bu kadar.

Bunlar "type hints":

def get_full_name(first_name: str, last_name: str):
    full_name = first_name.title() + " " + last_name.title()
    return full_name


print(get_full_name("john", "doe"))

Bu, aşağıdaki gibi default değerler bildirmekle aynı şey değildir:

    first_name="john", last_name="doe"

Bu farklı bir şey.

Eşittir (=) değil, iki nokta (:) kullanıyoruz.

Ve type hints eklemek, normalde onlarsız ne oluyorsa onu değiştirmez.

Ama şimdi, type hints ile o fonksiyonu oluşturmanın ortasında olduğunuzu tekrar hayal edin.

Aynı noktada, Ctrl+Space ile autocomplete'i tetiklemeye çalışırsınız ve şunu görürsünüz:

Bununla birlikte, seçenekleri görerek kaydırabilirsiniz; ta ki "tanıdık gelen" seçeneği bulana kadar:

Daha fazla motivasyon

Şu fonksiyona bakın, zaten type hints içeriyor:

def get_name_with_age(name: str, age: int):
    name_with_age = name + " is this old: " + age
    return name_with_age

Editör değişkenlerin tiplerini bildiği için, sadece completion değil, aynı zamanda hata kontrolleri de alırsınız:

Artık bunu düzeltmeniz gerektiğini, age'i str(age) ile string'e çevirmeniz gerektiğini biliyorsunuz:

def get_name_with_age(name: str, age: int):
    name_with_age = name + " is this old: " + str(age)
    return name_with_age

Tipleri Bildirmek

Type hints bildirmek için ana yeri az önce gördünüz: fonksiyon parametreleri.

Bu, FastAPI ile kullanırken de onları en çok kullanacağınız yerdir.

Basit tipler

Sadece str değil, tüm standart Python tiplerini bildirebilirsiniz.

Örneğin şunları kullanabilirsiniz:

  • int
  • float
  • bool
  • bytes
def get_items(item_a: str, item_b: int, item_c: float, item_d: bool, item_e: bytes):
    return item_a, item_b, item_c, item_d, item_e

typing modülü

Bazı ek kullanım durumları için standart kütüphanedeki typing modülünden bazı şeyleri import etmeniz gerekebilir. Örneğin bir şeyin "herhangi bir tip" olabileceğini bildirmek istediğinizde, typing içindeki Any'yi kullanabilirsiniz:

from typing import Any


def some_function(data: Any):
    print(data)

Generic tipler

Bazı tipler, köşeli parantez içinde "type parameters" alarak iç tiplerini tanımlayabilir; örneğin "string listesi" list[str] olarak bildirilir.

Bu şekilde type parameter alabilen tiplere Generic types veya Generics denir.

Aynı builtin tipleri generics olarak kullanabilirsiniz (köşeli parantez ve içinde tiplerle):

  • list
  • tuple
  • set
  • dict

List

Örneğin, str'lerden oluşan bir list olan bir değişken tanımlayalım.

Değişkeni, aynı iki nokta (:) sözdizimiyle bildirin.

Tip olarak list yazın.

list, bazı iç tipleri barındıran bir tip olduğundan, bunları köşeli parantez içine yazarsınız:

def process_items(items: list[str]):
    for item in items:
        print(item)

Bilgi

Köşeli parantez içindeki bu iç tiplere "type parameters" denir.

Bu durumda str, list'e verilen type parameter'dır.

Bu şu demektir: "items değişkeni bir list ve bu listedeki her bir öğe str".

Bunu yaparak, editörünüz listeden öğeleri işlerken bile destek sağlayabilir:

Tipler olmadan, bunu başarmak neredeyse imkansızdır.

item değişkeninin, items listesindeki elemanlardan biri olduğuna dikkat edin.

Ve yine de editör bunun bir str olduğunu bilir ve buna göre destek sağlar.

Tuple ve Set

tuple'ları ve set'leri bildirmek için de aynısını yaparsınız:

def process_items(items_t: tuple[int, int, str], items_s: set[bytes]):
    return items_t, items_s

Bu şu anlama gelir:

  • items_t değişkeni 3 öğeli bir tuple'dır: bir int, bir başka int ve bir str.
  • items_s değişkeni bir set'tir ve her bir öğesi bytes tipindedir.

Dict

Bir dict tanımlamak için, virgülle ayrılmış 2 type parameter verirsiniz.

İlk type parameter, dict'in key'leri içindir.

İkinci type parameter, dict'in value'ları içindir:

def process_items(prices: dict[str, float]):
    for item_name, item_price in prices.items():
        print(item_name)
        print(item_price)

Bu şu anlama gelir:

  • prices değişkeni bir dict'tir:
    • Bu dict'in key'leri str tipindedir (örneğin her bir öğenin adı).
    • Bu dict'in value'ları float tipindedir (örneğin her bir öğenin fiyatı).

Union

Bir değişkenin birkaç tipten herhangi biri olabileceğini bildirebilirsiniz; örneğin bir int veya bir str.

Bunu tanımlamak için, her iki tipi ayırmak üzere dikey çizgi (|) kullanırsınız.

Buna "union" denir, çünkü değişken bu iki tip kümesinin birleşimindeki herhangi bir şey olabilir.

def process_item(item: int | str):
    print(item)

Bu, item'ın int veya str olabileceği anlamına gelir.

Muhtemelen None

Bir değerin str gibi bir tipi olabileceğini ama aynı zamanda None da olabileceğini bildirebilirsiniz.

def say_hi(name: str | None = None):
    if name is not None:
        print(f"Hey {name}!")
    else:
        print("Hello World")

Sadece str yerine str | None kullanmak, aslında değer None olabilecekken her zaman str olduğunu varsaydığınız hataları editörün yakalamanıza yardımcı olur.

Tip olarak sınıflar

Bir sınıfı da bir değişkenin tipi olarak bildirebilirsiniz.

Örneğin, adı olan bir Person sınıfınız olsun:

class Person:
    def __init__(self, name: str):
        self.name = name


def get_person_name(one_person: Person):
    return one_person.name

Sonra bir değişkeni Person tipinde olacak şekilde bildirebilirsiniz:

class Person:
    def __init__(self, name: str):
        self.name = name


def get_person_name(one_person: Person):
    return one_person.name

Ve sonra, yine tüm editör desteğini alırsınız:

Bunun "one_person, Person sınıfının bir instance'ıdır" anlamına geldiğine dikkat edin.

"one_person, Person adlı class'tır" anlamına gelmez.

Pydantic modelleri

Pydantic, data validation yapmak için bir Python kütüphanesidir.

Verinin "shape"'ini attribute'lara sahip sınıflar olarak tanımlarsınız.

Ve her attribute'un bir tipi vardır.

Ardından o sınıfın bir instance'ını bazı değerlerle oluşturursunuz; bu değerleri doğrular, uygun tipe dönüştürür (gerekliyse) ve size tüm veriyi içeren bir nesne verir.

Ve bu ortaya çıkan nesne ile tüm editör desteğini alırsınız.

Resmî Pydantic dokümanlarından bir örnek:

from datetime import datetime

from pydantic import BaseModel


class User(BaseModel):
    id: int
    name: str = "John Doe"
    signup_ts: datetime | None = None
    friends: list[int] = []


external_data = {
    "id": "123",
    "signup_ts": "2017-06-01 12:22",
    "friends": [1, "2", b"3"],
}
user = User(**external_data)
print(user)
# > User id=123 name='John Doe' signup_ts=datetime.datetime(2017, 6, 1, 12, 22) friends=[1, 2, 3]
print(user.id)
# > 123

Bilgi

Daha fazlasını öğrenmek için Pydantic'in dokümanlarına bakın.

FastAPI tamamen Pydantic üzerine kuruludur.

Bunların pratikte nasıl çalıştığını Eğitim - Kullanım Kılavuzu içinde çok daha fazla göreceksiniz.

Metadata Annotations ile Type Hints

Python'da ayrıca, Annotated kullanarak bu type hints içine ek üstveri koymayı sağlayan bir özellik de vardır.

Annotatedtyping içinden import edebilirsiniz.

from typing import Annotated


def say_hello(name: Annotated[str, "this is just metadata"]) -> str:
    return f"Hello {name}"

Python'un kendisi bu Annotated ile bir şey yapmaz. Editörler ve diğer araçlar için tip hâlâ str'dir.

Ama FastAPI'ye uygulamanızın nasıl davranmasını istediğinize dair ek metadata sağlamak için Annotated içindeki bu alanı kullanabilirsiniz.

Hatırlanması gereken önemli nokta: Annotated'a verdiğiniz ilk type parameter, gerçek tiptir. Geri kalanı ise diğer araçlar için metadatadır.

Şimdilik, sadece Annotated'ın var olduğunu ve bunun standart Python olduğunu bilmeniz yeterli. 😎

İleride bunun ne kadar güçlü olabildiğini göreceksiniz.

İpucu

Bunun standart Python olması, editörünüzde mümkün olan en iyi developer experience'ı almaya devam edeceğiniz anlamına gelir; kodu analiz etmek ve refactor etmek için kullandığınız araçlarla da, vb. ✨

Ayrıca kodunuzun pek çok başka Python aracı ve kütüphanesiyle çok uyumlu olacağı anlamına gelir. 🚀

FastAPI'de type hints

FastAPI, birkaç şey yapmak için bu type hints'ten faydalanır.

FastAPI ile type hints kullanarak parametreleri bildirirsiniz ve şunları elde edersiniz:

  • Editör desteği.
  • Tip kontrolleri.

...ve FastAPI aynı bildirimleri şunlar için de kullanır:

  • Gereksinimleri tanımlamak: request path parameters, query parameters, headers, bodies, bağımlılıklar (dependencies), vb.
  • Veriyi dönüştürmek: request'ten gerekli tipe.
  • Veriyi doğrulamak: her request'ten gelen veriyi:
    • Veri geçersiz olduğunda client'a dönen otomatik hatalar üretmek.
  • OpenAPI kullanarak API'yi dokümante etmek:
    • bu, daha sonra otomatik etkileşimli dokümantasyon kullanıcı arayüzleri tarafından kullanılır.

Bunların hepsi kulağa soyut gelebilir. Merak etmeyin. Tüm bunları Eğitim - Kullanım Kılavuzu içinde çalışırken göreceksiniz.

Önemli olan, standart Python tiplerini tek bir yerde kullanarak (daha fazla sınıf, decorator vb. eklemek yerine), FastAPI'nin sizin için işin büyük kısmını yapmasıdır.

Bilgi

Tüm tutorial'ı zaten bitirdiyseniz ve tipler hakkında daha fazlasını görmek için geri döndüyseniz, iyi bir kaynak: mypy'nin "cheat sheet"i.