Skip to content

İlk Python Script'in: hello.py'den python -m'e Komut Satırının İncelikleri

İlk gerçek .py dosyanı yazıyorsun. Modül 1'in capstone'u: shebang, encoding declaration, if __name__ == '__main__', python -m flag'i, sys.argv, exit code'lar, .pyc cache, ve her gün karşılaşacağın komut satırı pratikleri. 4 hands-on script ile bitiyoruz.

Şükrü Yusuf KAYA
22 min read
Beginner
İlk Python Script'in: hello.py'den python -m'e Komut Satırının İncelikleri
🎉 Modül 1 finali — sonunda 'gerçek' kod yazıyoruz
13 ders boyunca kurulum, sürüm, IDE, REPL — hepsi 'altyapı' idi. Bu derste tüm bu altyapıyı kullanıp ilk gerçek Python script'ini yazıyorsun. Sonra Modül 2'de söz dizimi derinleşir. Tebrikler — bir programcı olma yolculuğunun ilk yarıyılını tamamladın!

Adım 1: hello.py#

Editörünü aç (VS Code önerim), yeni dosya oluştur:
hello.py
. İçine:
print("Merhaba, Python!")
Tek satır. Kaydet. Şimdi terminal'i aç ve dosyanın olduğu klasöre git:
cd ~/Desktop # ya da nereye kaydettiysen python hello.py
Çıktı:
Merhaba, Python!
🎉 Tebrikler — ilk script çalıştı. Bu kadar basit.

"python" mu "python3" mu?#

Sistemine göre değişir. Eğer pyenv kullanıyorsan veya PATH'te Python varsa
python
çalışır. Bazı Linux sistemlerinde sadece
python3
var. Eşit alternatifler:
python hello.py python3 hello.py python3.13 hello.py py hello.py # Windows py -3.13 hello.py # Windows, belirli sürüm
Profesyonel script'lerde
python3
veya tam sürüm kullanmak hatadan korur.

Shebang line — Linux/macOS'ta script'i çalıştırılabilir yapmak#

Linux/macOS'ta script'leri direkt çalıştırılabilir hale getirebilirsin. Bunun için iki şey gerekli:

1. Shebang line#

Dosyanın ilk satırı
#!
ile başlamalı. Python script'i için:
#!/usr/bin/env python3 print("Merhaba, Python!")
#!/usr/bin/env python3
ne demek? Linux/macOS'a şunu söylüyor: "Bu script'i
/usr/bin/env
ile çalıştır; o da PATH'te bulduğu
python3
'ü kullansın".
Alternatifler:
#!/usr/bin/python3 # Direkt path — port edebilirliği azaltır #!/usr/bin/env python3 # PATH-based — taşınabilir, önerilen #!/usr/bin/env python # python3 yoksa fallback

2. Executable izni#

chmod +x hello.py
Şimdi:
./hello.py # Merhaba, Python!
./
önemli — shell, mevcut klasördeki executable'ı çağırırken bunu istiyor.

Windows'ta shebang?#

Windows shebang'i göz ardı eder; gerek yok. Sadece
py
launcher veya
python
ile çalıştırılır. Ama shebang yazmak zarar vermez — Linux'ta da çalışan bir script yazıyorsan koymalısın.

Encoding declaration — Türkçe karakter#

Eski Python kodlarında şuna benzeyen 2. satır görürsün:
#!/usr/bin/env python3 # -*- coding: utf-8 -*- print("İstanbul'da yağmur var.")
# -*- coding: utf-8 -*-
Python 2 zamanında gerekliydi — çünkü default encoding ASCII'ydi, Türkçe karakter koymaya çalışınca:
SyntaxError: Non-ASCII character '\xc4'
Python 3'te default encoding zaten UTF-8. Yani bu satıra gerek yok. Modern Python kodu temiz:
#!/usr/bin/env python3 print("İstanbul'da yağmur var.") # ✅ Sorun yok
Eski legacy kodda görürsen şaşırma — tarihsel artık.

if __name__ == "__main__":
— efsane satır#

Belki Stack Overflow'da görmüşündür:
def greet(name): print(f"Merhaba, {name}!") if __name__ == "__main__": greet("Dünya")
Bu satır ne yapıyor? Anlaması için Python'un import sistemini bilmen gerek.
Python'da bir
.py
dosyası iki şekilde çalıştırılabilir:
  1. Doğrudan:
    python hello.py
    — script olarak.
  2. Import edilerek: Başka bir dosyada
    import hello
    — modül olarak.
__name__
özel bir değişken. Python'un her dosyasında otomatik tanımlı:
  • Doğrudan çalıştırıldığında:
    __name__ == "__main__"
  • Import edildiğinde:
    __name__ == "hello"
    (dosya adı)
# greeter.py def greet(name): print(f"Merhaba, {name}!") print(f"__name__ = {__name__}") if __name__ == "__main__": print("Doğrudan çalıştırılıyor") greet("Dünya")
$ python greeter.py __name__ = __main__ Doğrudan çalıştırılıyor Merhaba, Dünya!
# main.py import greeter
$ python main.py __name__ = greeter
Görüyorsun — import edildiğinde
if __name__ == "__main__":
bloğu çalışmıyor. Bu ne işine yarıyor?
İşine yarayan senaryo: Modülünü hem import-edilebilir hem direkt-çalıştırılabilir yapmak.
# calculator.py def add(a, b): return a + b def multiply(a, b): return a * b # Bu satırlar sadece doğrudan çalıştırınca işler if __name__ == "__main__": print("Test:") print(f"2 + 3 = {add(2, 3)}") print(f"4 * 5 = {multiply(4, 5)}")
Şimdi
python calculator.py
test çıktısı verir. Ama
from calculator import add
ile başka dosyada kullanırken test çıktıları gösterilmez.
Bu pattern Python'da o kadar yaygın ki hemen her ciddi script'te göreceksin. Senin yazdığın script'lere de eklemen tavsiye edilir.

python -m
flag'i — modül olarak çalıştırma#

python script.py
ile
python -m script
arasında ne fark var?
# Yöntem 1: dosya yolu olarak python /path/to/script.py # Yöntem 2: modül adı olarak python -m script
-m
flag'i Python'a "bu argüman bir modül adı, sys.path'te ara ve çalıştır" diyor. Avantajları:

1. Standard kütüphane modüllerini doğrudan çağırma#

# HTTP server (standart kütüphanede gelir) python -m http.server 8000 # Şimdi http://localhost:8000 ile mevcut klasörü serve # JSON validate / format python -m json.tool < data.json # Pip kendisi bir modül python -m pip install requests # Venv yarat python -m venv myenv # Cprofile ile profile et python -m cProfile -s cumulative myscript.py # Test runner python -m unittest # Compile python -m py_compile myscript.py

2. Paket içinde main entry point#

Bir paketin (
__init__.py
olan klasör) içinde
__main__.py
dosyası olduğunda:
mypackage/ ├── __init__.py ├── __main__.py # python -m mypackage çağrılınca bu çalışır └── core.py
# mypackage/__main__.py from mypackage.core import run if __name__ == "__main__": run()
python -m mypackage
Bu pattern modern Python projelerinde standart.
pip install
ettiğin paketler de bu yaklaşımla CLI'larını sağlıyor.

3. pip'i her zaman
python -m pip
ile çağır#

Bu önerimi çok ciddiye al:
# Kötü pip install paket # İyi python -m pip install paket
Neden?
pip
global PATH'te olabilir; hangi Python'a kurduğunu bilmezsin (özellikle birden fazla Python varsa).
python -m pip
her zaman mevcut python'a kurar — kafa karışıklığı yok.

Komut satırı argümanları —
sys.argv
#

Script'in komut satırından gelen argümanları okuyabilir:
# greet.py import sys print(f"Toplam argüman sayısı: {len(sys.argv)}") print(f"Argüman listesi: {sys.argv}") if len(sys.argv) < 2: print("Kullanım: python greet.py <isim>") sys.exit(1) name = sys.argv[1] print(f"Merhaba, {name}!")
$ python greet.py Toplam argüman sayısı: 1 Argüman listesi: ['greet.py'] Kullanım: python greet.py <isim> $ python greet.py Şükrü Toplam argüman sayısı: 2 Argüman listesi: ['greet.py', 'Şükrü'] Merhaba, Şükrü! $ python greet.py Şükrü Yusuf Toplam argüman sayısı: 3 Argüman listesi: ['greet.py', 'Şükrü', 'Yusuf'] Merhaba, Şükrü!
sys.argv[0]
her zaman script adı.
sys.argv[1:]
argümanlar.

sys.exit()
ve exit code#

sys.exit(0) # başarılı sys.exit(1) # hata sys.exit("Hata mesajı") # mesaj stderr'e yazıp 1 ile çıkar
Shell script'lerinden Python script'i çağırırken exit code önemli — başarılı/başarısız ayrımını shell yapıyor:
python greet.py Şükrü && echo "Başardı" || echo "Başarısız"

argparse — büyük script'ler için#

sys.argv
tek başına çıplak. Modern argüman parsing için
argparse
standart kütüphanesi var (Modül 26'da detaylı):
import argparse parser = argparse.ArgumentParser(description="Greet someone") parser.add_argument("name", help="İsim") parser.add_argument("--lang", default="tr", choices=["tr", "en"], help="Dil") parser.add_argument("--upper", action="store_true", help="Büyük harf") args = parser.parse_args() greeting = "Hello" if args.lang == "en" else "Merhaba" message = f"{greeting}, {args.name}!" if args.upper: message = message.upper() print(message)
$ python greet.py Şükrü --lang en --upper HELLO, ŞÜKRÜ! $ python greet.py --help usage: greet.py [-h] [--lang {tr,en}] [--upper] name Greet someone positional arguments: name İsim optional arguments: -h, --help show this help message and exit --lang {tr,en} Dil --upper Büyük harf
argparse otomatik
--help
üretir, validation yapar, type conversion. CLI yazacaksan
sys.argv
yerine bunu kullan.

__pycache__
ve .pyc dosyaları#

Bir Python dosyasını import ettiğinde Python onu bytecode'a derler ve cache'ler. Sonraki çalıştırmada bu cache'i kullanır — daha hızlı.
$ ls -la hello.py $ python -c "import hello" $ ls -la hello.py __pycache__/ hello.cpython-313.pyc
__pycache__
klasörü oluştu. İçinde:
  • hello.cpython-313.pyc
    — Python 3.13 için bytecode.
Birden fazla Python sürümünde aynı dosyayı kullanırsan
hello.cpython-310.pyc
ve
hello.cpython-313.pyc
gibi farklı cache'ler oluşur.

.pyc dosyaları nedir?#

CPython, kaynak kodu doğrudan çalıştırmaz; önce bytecode'a derler:
# Bytecode'u görmek için import dis def add(a, b): return a + b dis.dis(add)
2 0 LOAD_FAST 0 (a) 2 LOAD_FAST 1 (b) 4 BINARY_ADD 6 RETURN_VALUE
Bu bytecode
.pyc
'de saklanıyor. Bir sonraki import'ta direkt bytecode'tan çalıştırır — kaynak kodu tekrar parse etmez.

__pycache__
git'e koymalı mıyım?#

Hayır.
.gitignore
'a ekle:
# .gitignore __pycache__/ *.pyc *.pyo *.pyd
Cache dosyaları Python sürümüne özel; başkasının makinesinde çalışmayabilir. Her makine kendi cache'ini üretir.

Cache'i devre dışı bırakmak#

# Bytecode cache'ini yazma python -B script.py # Veya environment variable export PYTHONDONTWRITEBYTECODE=1
Bunu sadece özel durumlarda yapman gerekir; default cache iyi.

stdin, stdout, stderr — UNIX dünyasıyla buluşma#

Python script'leri Unix-style I/O'yu doğal kullanır:
  • stdin: Standart girdi (klavye veya pipe)
  • stdout: Standart çıktı (terminal veya pipe)
  • stderr: Standart hata (terminal veya pipe, ayrı)
import sys # stdout (default print buraya yazar) print("Bu stdout'a") sys.stdout.write("Bu da stdout'a\n") # stderr (uyarı, hata, log için) print("Bu stderr'e", file=sys.stderr) sys.stderr.write("Bu da stderr'e\n") # stdin data = sys.stdin.read() print(f"Stdin'den {len(data)} karakter okudum") # Satır satır for line in sys.stdin: print(f"Aldım: {line.strip()}")

Pipe örnekleri#

# stdin'den oku echo "Merhaba" | python script.py # stdout'u dosyaya yönlendir python script.py > output.txt # stderr'i ayır python script.py 2> errors.txt # İkisini birden ama ayrı python script.py > output.txt 2> errors.txt # stdout + stderr aynı yere python script.py > combined.txt 2>&1 # stderr'i discard python script.py 2> /dev/null
Profesyonel script'ler:
  • Bilgi mesajları: stderr'e (logging modülü)
  • Asıl veri çıktısı: stdout'a (machine-readable, pipe edilebilir)
import sys import logging logging.basicConfig(stream=sys.stderr, level=logging.INFO) logging.info("İşlem başladı") # → stderr print("output_data") # → stdout
Bu sayede başkası senin script'inin output'unu pipe edebilir, log mesajları karışmaz.

Pratik script'ler — gerçek örnekler#

Modül 1'in kapanışında 4 küçük gerçek script ile pratik yap.

Script 1: Çevre değişkeni okuyan basit util#

#!/usr/bin/env python3 """Çevre değişkenini güvenli şekilde okuyup yazdırır.""" import os import sys def main(): if len(sys.argv) != 2: print("Kullanım: getenv.py <DEĞİŞKEN_ADI>", file=sys.stderr) sys.exit(1) var_name = sys.argv[1] value = os.environ.get(var_name) if value is None: print(f"'{var_name}' tanımlı değil.", file=sys.stderr) sys.exit(2) print(value) sys.exit(0) if __name__ == "__main__": main()
$ python getenv.py HOME /Users/me $ python getenv.py NOT_EXISTS 'NOT_EXISTS' tanımlı değil.

Script 2: Klasördeki dosyaları sayan + tipe göre gruplayan#

#!/usr/bin/env python3 """Verilen klasördeki dosyaları uzantıya göre grupla ve say.""" import os import sys from collections import Counter from pathlib import Path def main(): folder = sys.argv[1] if len(sys.argv) > 1 else "." path = Path(folder) if not path.is_dir(): print(f"Klasör bulunamadı: {folder}", file=sys.stderr) sys.exit(1) counter = Counter() total_size = 0 for file in path.rglob("*"): if file.is_file(): ext = file.suffix.lower() or "(no extension)" counter[ext] += 1 total_size += file.stat().st_size print(f"Klasör: {path.absolute()}") print(f"Toplam dosya: {sum(counter.values())}") print(f"Toplam boyut: {total_size / 1024 / 1024:.2f} MB") print() print("Uzantıya göre dağılım:") for ext, count in counter.most_common(20): print(f" {ext:20s}: {count:5d}") if __name__ == "__main__": main()
$ python file_stats.py ~/Downloads Klasör: /Users/me/Downloads Toplam dosya: 142 Toplam boyut: 256.34 MB Uzantıya göre dağılım: .pdf : 34 .png : 27 .zip : 18 ...

Script 3: HTTP fetch + JSON parse#

#!/usr/bin/env python3 """GitHub kullanıcı bilgilerini API'den çek.""" import json import sys import urllib.request import urllib.error def main(): if len(sys.argv) != 2: print("Kullanım: github_user.py <username>", file=sys.stderr) sys.exit(1) username = sys.argv[1] url = f"https://api.github.com/users/{username}" try: with urllib.request.urlopen(url, timeout=10) as response: data = json.load(response) except urllib.error.HTTPError as e: print(f"HTTP hata: {e.code} {e.reason}", file=sys.stderr) sys.exit(2) except urllib.error.URLError as e: print(f"Network hata: {e.reason}", file=sys.stderr) sys.exit(3) print(f"Kullanıcı: {data['login']}") print(f"İsim: {data.get('name', '(belirtilmemiş)')}") print(f"Şirket: {data.get('company', '(belirtilmemiş)')}") print(f"Bio: {data.get('bio', '(belirtilmemiş)')}") print(f"Repo: {data['public_repos']}") print(f"Takipçi: {data['followers']}") print(f"Takip: {data['following']}") print(f"Profil: {data['html_url']}") if __name__ == "__main__": main()
$ python github_user.py torvalds Kullanıcı: torvalds İsim: Linus Torvalds Şirket: Linux Foundation Bio: (belirtilmemiş) Repo: 8 Takipçi: 245789 Takip: 0 Profil: https://github.com/torvalds

Script 4: Mini CLI — hesap makinesi#

#!/usr/bin/env python3 """Komut satırı hesap makinesi.""" import argparse import sys def main(): parser = argparse.ArgumentParser(description="Basit hesap makinesi") parser.add_argument("a", type=float, help="İlk sayı") parser.add_argument("op", choices=["+", "-", "*", "/", "**", "%"], help="Operatör") parser.add_argument("b", type=float, help="İkinci sayı") parser.add_argument("--precision", type=int, default=4, help="Ondalık hassasiyet (default 4)") args = parser.parse_args() operations = { "+": lambda a, b: a + b, "-": lambda a, b: a - b, "*": lambda a, b: a * b, "/": lambda a, b: a / b if b != 0 else float("nan"), "**": lambda a, b: a ** b, "%": lambda a, b: a % b if b != 0 else float("nan"), } result = operations[args.op](args.a, args.b) print(f"{args.a} {args.op} {args.b} = {result:.{args.precision}f}") if __name__ == "__main__": main()
$ python calc.py 10 + 5 10.0 + 5.0 = 15.0000 $ python calc.py 7 / 3 --precision 2 7.0 / 3.0 = 2.33 $ python calc.py 2 ** 10 2.0 ** 10.0 = 1024.0000 $ python calc.py 5 + a calc.py: error: argument b: invalid float value: 'a'
Bu 4 script kombinasyonunda modül 1'de öğrendiklerinin pratik kullanımı var: shebang, encoding (otomatik),
__name__ == "__main__"
, sys.argv, sys.exit, argparse, stderr, exit code, modül kullanımı.
Şimdi bu script'leri kendi makinende çalıştır. Modify et, oynat. Bu egzersiz Modül 1'in capstone'u.

"Python yorumlanan dil" derken — pratikte ne demek?#

Aslında saf yorumlanan değil, hibrit. Çalışma akışı:
  1. Source code (
    hello.py
    ) →
  2. Lexer/Parser: Token'lara böl, AST (Abstract Syntax Tree) yarat →
  3. Compile: AST'ten bytecode üret (
    .pyc
    ) →
  4. Bytecode VM: Python'un içsel yorumlayıcısı bytecode'u çalıştırır.
import dis def hello(): print("Hi") dis.dis(hello)
2 0 LOAD_GLOBAL 0 (print) 2 LOAD_CONST 1 ('Hi') 4 CALL_FUNCTION 1 6 POP_TOP 8 LOAD_CONST 0 (None) 10 RETURN_VALUE
Bu bytecode'u Python VM çalıştırır. CPython'un kalbi.
Bu detayı bilmek günlük programcılık için gerekmez ama:
  • "Python neden Java'dan yavaş?" sorusuna cevap (Java JIT'leniyor; CPython sadece bytecode-interpret).
  • PyPy ne yapıyor? Bytecode'u JIT ile makine koduna çeviriyor.
  • Cython ne yapıyor? Python'u doğrudan C'ye çeviriyor.
Bu cümleler artık daha anlamlı.

Modül 1 sonu — neler kazandın?#

✓ İlk Python script'in:
hello.py
ve
python
ile çalıştırma.
Shebang line (
#!/usr/bin/env python3
) ve
chmod +x
ile executable yapma.
Encoding declaration tarihi — Python 3'te artık gerek yok.
__name__ == "__main__"
deyiminin anlamı ve neden her ciddi script'te olduğu.
python -m
flag'i — modül olarak çalıştırma, http.server, json.tool, pip, venv gibi standart kullanımları.
sys.argv
ile komut satırı argümanları,
sys.exit
ve exit code'lar.
argparse
ile profesyonel CLI yapısı.
__pycache__
ve
.pyc
dosyaları — bytecode cache.
stdin/stdout/stderr — UNIX I/O ile uyum.
4 gerçek hands-on script ile tüm bu kavramları birlikte gördün.
CPython internals — kaynak kod → AST → bytecode → VM, Python'un kalp atışı.

Modül 1 capstone — kendine sor:#

Aşağıdaki sorulara verebileceğin cevaplar yoksa, ilgili dersi tekrar oku. Verebiliyorsan — Modül 2'ye hazırsın!
  1. CPython, PyPy, MicroPython, Pyodide arasındaki fark nedir? (Ders 3)
  2. Python 2 ile 3 arasındaki büyük ayrılık ne hakkındaydı? (Ders 2)
  3. Pythonic kod nedir, nasıl tanırsın? (Ders 4)
  4. Birden fazla Python sürümünü makinende nasıl yönetirsin? (Ders 7-8)
  5. REPL'de
    ?
    ve
    ??
    farkı nedir?
    (Ders 9-10)
  6. Jupyter Notebook'un git ile çalışmasında ne gibi sorunlar olur? (Ders 11)
  7. VS Code'da virtualenv'i nasıl seçip aktif edersin? (Ders 12)
  8. PyCharm Pro'da Community'de olmayan ne var? (Ders 13)
  9. if __name__ == "__main__":
    neden yazılır?
    (Ders 14)
  10. python -m pip
    neden
    pip
    direkt çağırmaktan iyidir?
    (Ders 14)
10/10 alıyorsan, Modül 1 ara quizi'ne girebilirsin → /learn/quiz/python-module-1-quiz

Sonraki adım#

Modül 2: Veri Tipleri ve Operatörler'le devam edeceğiz. Değişkenler, sayısal tipler (int/float/decimal/fractions), boolean ve None, operatörler (mantıksal/karşılaştırma/bit-level), type conversion, identity vs equality (
is
vs
==
)... 15 ders boyunca Python'un veri katmanını derinlemesine kazıyacağız.
Görüşmek üzere — gerçek programlama burada başlıyor. ☕

Frequently Asked Questions

Modern dünyada `python3` daha taşınabilir. Ama eğer pyenv kullanıyorsan ve `pyenv global 3.13.0` ile default ayarladıysan, `python` da çalışıyor (pyenv shim'leri sayesinde). Pratik tavsiye: profesyonel script'lerde `python3` veya `python3.13` (sürüm spesifik), kişisel REPL'inde `python` (kısa yazmak için).

Yorumlar & Soru-Cevap

(0)
Yorum yazmak için giriş yap.
Yorumlar yükleniyor...

Related Content