- Modül, paket,
sys.pathvesys.moduleskavramlarını açıklamak - Bir dosyanın hem modül hem betik olarak çalışması için
if __name__ == '__main__'kullanmak venvile sanal ortam oluşturmak,pipile paket kurmak ve bağımlılıkları kaydetmekrequirements.txtvepyproject.tomldosyalarını okumak ve sürüm belirteçlerini anlamak
Projelerinden biri Django 4, diğeri Django 5 istiyor; paketi tüm bilgisayara kurarsan projelerden biri mutlaka bozulur. Bir takım arkadaşın kodunu çalıştırır ve ModuleNotFoundError alır, çünkü senin kurduğun kütüphaneler onun bilgisayarında yoktur. Gerçek projeler üç kurala uyar: kod modüllere ve paketlere bölünür, her projenin kendi sanal ortamı olur ve bağımlılıklar sürümleriyle birlikte bir dosyaya kaydedilir.
Modüller ve paketler
Modül, herhangi bir .py dosyasıdır. import pricing yazdığında Python dosyayı sys.path listesindeki klasörlerde arar, dosyanın en üst düzeydeki kodunu bir kez çalıştırır ve modül nesnesini sys.modules içinde saklar; sonraki içe aktarmalar hazır nesneyi kullanır. Paket, modüllerden oluşan bir klasördür; sıradan bir pakette __init__.py dosyası bulunur ve paket ilk kez içe aktarıldığında çalışır. Adlar noktalı yazılır: shop.pricing, shop paketindeki pricing modülüdür. Tipik bir proje şöyle görünür:
shop/
├── pyproject.toml
├── requirements.txt
├── .venv/ (not in git)
├── src/
│ └── shop/
│ ├── __init__.py
│ ├── pricing.py
│ └── cli.py
└── tests/
└── test_pricing.pysrc/ içinde, testler ise ayrıca tests/ içinde durur.Aşağıdaki örnek geçici bir klasörde küçük bir paket oluşturur ve onu üç farklı yolla içe aktarır (sys.modules.pop satırları yalnızca örneğin yeniden çalıştırılabilmesi içindir):
import importlib
import sys
import tempfile
from pathlib import Path
root = Path(tempfile.mkdtemp())
(root / 'shop').mkdir()
(root / 'shop' / '__init__.py').write_text('from .pricing import final_price\n')
(root / 'shop' / 'pricing.py').write_text(
'VAT = 0.18\n'
'print("running pricing.py as", __name__)\n'
'def final_price(net):\n'
' return round(net * (1 + VAT), 2)\n'
)
sys.path.insert(0, str(root))
sys.modules.pop('shop', None)
sys.modules.pop('shop.pricing', None)
importlib.invalidate_caches()
import shop
import shop.pricing
from shop import final_price
print(final_price(100), shop.pricing.VAT)
print(__name__)▸ Beklenen çıktı
running pricing.py as shop.pricing 118.0 0.18 __main__
pricing.py, üç içe aktarmaya rağmen yalnızca bir kez çalıştı. Modülün içinde __name__ onun tam adıdır (shop.pricing); doğrudan başlatılan dosyada ise '__main__''dir. __init__.py içindeki from .pricing import final_price bir göreli içe aktarmadır: nokta “bu paket” demektir. Bu satır sayesinde kullanıcılar iç yapıyı bilmeden from shop import final_price yazabilir.
if __name__ == '__main__': betik mi, modül mü
Bir dosya hem içe aktarılabilir bir modül hem de çalıştırılabilir bir betik olabilir. if __name__ == '__main__': koşulu, betik kodunu yalnızca dosya doğrudan başlatıldığında çalıştırır, içe aktarıldığında değil. python -m shop.cli komutu modülü paketinin bir parçası olarak bulur ve betik olarak çalıştırır; bu yüzden paket içindeki içe aktarmalar çalışmaya devam eder:
import sys
from shop.pricing import final_price
def main() -> int:
for arg in sys.argv[1:]:
print(f'{arg} -> {final_price(float(arg))}')
return 0
if __name__ == '__main__':
sys.exit(main())src/shop/cli.py dosyası$ python -m shop.cli 10 25.5
10 -> 11.8
25.5 -> 30.09Sanal ortamlar: venv ve pip
Sanal ortam olmadan tüm projeler tek bir site-packages klasörünü paylaşır ve paket sürümleri çakışır. Sanal ortam, projenin içinde kendi Python yorumlayıcısı ve kendi paketleri olan bir klasördür (genellikle .venv). Onu standart venv modülü oluşturur, paketleri ise pip kurar:
- 1Oluştur
Proje klasöründe:
python -m venv .venv. - 2Etkinleştir
Windows:
.venv\Scripts\activate; macOS ve Linux:source .venv/bin/activate. Komut isteminin başında(.venv)görünür. - 3Kur
python -m pip install requests— paket yalnızca bu ortama kurulur. - 4Kaydet
python -m pip freeze > requirements.txt, kurulu paketlerin tam sürümlerini bir dosyaya yazar. - 5Yeniden kur
Takım arkadaşın kendi ortamını oluşturur ve
python -m pip install -r requirements.txtçalıştırır. - 6Çık
deactivatekomutu seni normal komut istemine döndürür.
$ python -m venv .venv
$ source .venv/bin/activate
(.venv) $ python -m pip list
Package Version
------- -------
pip 25.2
(.venv) $ python -m pip install requests
Collecting requests
...
Installing collected packages: urllib3, idna, charset-normalizer, certifi, requests
Successfully installed certifi-2024.8.30 charset-normalizer-3.4.0 idna-3.10 requests-2.32.3 urllib3-2.2.3
(.venv) $ python -m pip freeze
certifi==2024.8.30
charset-normalizer==3.4.0
idna==3.10
requests==2.32.3
urllib3==2.2.3requests kendi bağımlılıklarını da getirir. Sürüm numaraları kurulum gününe göre farklı olacaktır.requirements.txt ve pyproject.toml
requirements.txt basit bir listedir: her satırda bir paket, isteğe bağlı olarak bir sürüm belirteciyle. Uygulamalarda tam sürümleri (==) sabitlemek yaygındır; böylece program her bilgisayarda aynı kütüphanelerle çalışır:
# requirements.txt
requests==2.32.3
fastapi>=0.110,<1.0
python-dotenv~=1.0| Belirteç | Anlamı |
|---|---|
==2.32.3 | tam olarak bu sürüm |
>=0.110,<1.0 | aralık: 0.110 ya da daha yeni, ama 1.0'dan eski |
~=1.4 | uyumlu sürüm: >=1.4 ve <2.0 |
| (yok) | herhangi bir sürüm — riskli |
Modern bir projenin ana dosyası **pyproject.toml**'dur: ad, sürüm, desteklenen Python sürümleri, bağımlılıklar, yalnızca geliştirme için gereken araçlar ve komut satırı betikleri burada yazılır. Proje klasöründe python -m pip install -e . komutu paketi “düzenlenebilir” kipte kurar: kod değiştikçe yeniden kurmak gerekmez ve [project.scripts] bölümündeki shop komutu hemen çalışır.
[build-system]
requires = ["setuptools>=68"]
build-backend = "setuptools.build_meta"
[project]
name = "shop"
version = "0.1.0"
requires-python = ">=3.10"
dependencies = ["requests>=2.31"]
[project.optional-dependencies]
dev = ["pytest>=8"]
[project.scripts]
shop = "shop.cli:main"pyproject.toml dosyası (TOML biçimi). Geliştirme araçları python -m pip install -e ".[dev]" ile kurulur.parse_requirements(text) fonksiyonunu yaz: bir requirements.txt metninden {paket: belirteç} sözlüğü döndürsün. Boş satırları ve # ile başlayan yorumları atla; belirteç yoksa değer 'any version' olsun.
import re
requirements = '''
# web
requests==2.32.3
fastapi>=0.110,<1.0
python-dotenv~=1.0
numpy
'''
def parse_requirements(text):
result = {}
# go through the lines, skip blanks and comments,
# split each line into the package name and the specifier
return result
for name, spec in parse_requirements(requirements).items():
print(f'{name}: {spec}')▸ Beklenen çıktı
requests: ==2.32.3 fastapi: >=0.110,<1.0 python-dotenv: ~=1.0 numpy: any version
Sürümleri karakter dizisi olarak sıralamak yanlıştır: '0.10.0', '0.9.3''ten önce gelir. Sürümlerin doğru sıralanması ve en yenisinin yazdırılması için version_key fonksiyonunu yaz.
versions = ['0.10.0', '0.9.3', '1.0.0', '0.1.0', '0.9.12']
def version_key(v):
# turn '0.10.0' into something that compares correctly
return v
print(sorted(versions))
print(sorted(versions, key=version_key))
print('latest:', max(versions, key=version_key))▸ Beklenen çıktı
['0.1.0', '0.10.0', '0.9.12', '0.9.3', '1.0.0'] ['0.1.0', '0.9.3', '0.9.12', '0.10.0', '1.0.0'] latest: 1.0.0
Önemli noktalar
- Modül bir
.pydosyası, paket ise modüllerden oluşan bir klasördür; modülün kodu ilk içe aktarmada bir kez çalışır vesys.modules'ta saklanır. __name__, doğrudan çalıştırılan dosyada'__main__''dir;if __name__ == '__main__':betik kodunun içe aktarmada çalışmasını engeller.- Her projeye kendi sanal ortamını ver:
python -m venv .venv, etkinleştir,python -m pip install .... - Bağımlılıklar
requirements.txtya dapyproject.toml'a kaydedilir;==,>=,<ve~=sürümleri sınırlar. .venvgit'e girmez: ortam her zaman bağımlılık dosyasından yeniden oluşturulur.
Kendini test et
10 soru. Her doğru cevap XP kazandırır.
python -m venv .venv komutu ne yapar?