Artık Python'da `elif` yazmak zorunda değilsiniz!
Twitterda gezinirken şöyle bir şey gördüm.
Python yüzünden dünya bi data engineer kaybetti pic.twitter.com/t1W8392Nrz
— Ilter (@koseilteer) November 20, 2021
İlgili Tweet (opens in a new tab)
Insanların bir keyword yüzünden Pythonu bırakmasına gönlüm razı olmadı (!)
Bu yüzden bu elif
keywordunu Python da elseif
ile değişmeye karar verdim.
Neden?
Makalenin amacı troll olsa da Python'u kaynak kodu üzerinden derleyip içeride ne döndüğüne bakmak, bu build aşamalarının ne olduğunu görmek yapmak istediğim bir şeydi. Bir frontend dev olarak bu işler nasıl oluyor bakmak istedim.
CPython'ı Derlemek
Şimdi şunu belirtmekte fayda var, terminalinize gelip python
yazdığınızda çalışan şey %90 ihtimalle CPython. Peki ne bu CPython?
En kısa tanımı ile, Pythonun bir implementasyonu. Şöyle ki Python interpreteri de Python kodlarını çalıştıran bir program. CPython ise
bu programın C ile yazılmış versiyonu. Pek çok version yazılmış tabii ki ama en çok kullanılan bu version. CPythonun kaynak kodları
burada (opens in a new tab) bulunuyor. Buradan kendinize bir fork çakıp o forku bilgisayarınıza klonlayın. Ben kendi adıma
klonlamıştım.
git clone https://github.com/bufgix/cpython
cd cpython
Mac bir cihaz kullandığım için yapmam gereken şu
brew install openssl xz gdbm
sonrasında configure
scriptini çalıştıralım
./configure --with-pydebug --with-openssl=$(brew --prefix openssl)
daha sonra build almaya geçebiliriz.
make -s -j2
-j2
flagı make
in aynı anda 2 işi yapmabilmesini sağlar. Eğer 4 çekirdeğiniz varsa -j4
diyebilirsiniz.
Bu noktadan itibaren bilgisayarınızın fan seslerini ve tkinter
gibi paketlerinden çıkan hataları görmezden gelebilirsiniz.
İşlem bittiğinde tertemiz Python 3.11 binary si çıkmış olacak. Hemen test edelim
~/cpython on main
❯ ./python.exe
Python 3.11.0a2+ (heads/main-dirty:253b7a0a9f, Nov 26 2021, 15:26:42) [Clang 12.0.5 (clang-1205.0.22.11)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>>
Nice!
Dile keyword eklemek
Aslında yapacağımız şey dile yep yeni bir keyword eklemek değil. Var olan bir keywordün ismini değiştirmek. Dolayısıyla işimiz çok daha kolay.
Python dilin syntaxını belirtmek için Grammar/python.gram
dosyasını kullanıyor. Dil ile ilgili bir yazımı değiştirmek istediğimizde
bu dosyayı değiştirmek gerekiyor.
Dokümantasyona bakmadan ilk aklıma gelen IDE de elif
keywordunu bulup bunu elseif
değiştirmekti. 354. satırın oraları şöyle değiştirdim.
if_stmt[stmt_ty]:
| invalid_if_stmt
| 'if' a=named_expression ':' b=block c=elif_stmt {
_PyAST_If(a, b, CHECK(asdl_stmt_seq*, _PyPegen_singleton_seq(p, c)), EXTRA) }
| 'if' a=named_expression ':' b=block c=[else_block] { _PyAST_If(a, b, c, EXTRA) }
elif_stmt[stmt_ty]:
| invalid_elif_stmt
| 'elif' a=named_expression ':' b=block c=elif_stmt {
_PyAST_If(a, b, CHECK(asdl_stmt_seq*, _PyPegen_singleton_seq(p, c)), EXTRA) }
| 'elif' a=named_expression ':' b=block c=[else_block] { _PyAST_If(a, b, c, EXTRA) }
else_block[asdl_stmt_seq*]:
| invalid_else_stmt
| 'else' &&':' b=block { b }
if_stmt[stmt_ty]:
| invalid_if_stmt
| 'if' a=named_expression ':' b=block c=elif_stmt {
_PyAST_If(a, b, CHECK(asdl_stmt_seq*, _PyPegen_singleton_seq(p, c)), EXTRA) }
| 'if' a=named_expression ':' b=block c=[else_block] { _PyAST_If(a, b, c, EXTRA) }
elif_stmt[stmt_ty]:
| invalid_elif_stmt
| 'elseif' a=named_expression ':' b=block c=elif_stmt {
_PyAST_If(a, b, CHECK(asdl_stmt_seq*, _PyPegen_singleton_seq(p, c)), EXTRA) }
| 'elseif' a=named_expression ':' b=block c=[else_block] { _PyAST_If(a, b, c, EXTRA) }
else_block[asdl_stmt_seq*]:
| invalid_else_stmt
| 'else' &&':' b=block { b }
# 1220 li satırlara doğru ise
invalid_elif_stmt:
| 'elseif' named_expression NEWLINE { RAISE_SYNTAX_ERROR("expected ':'") }
| a='elseif' named_expression ':' NEWLINE !INDENT {
RAISE_INDENTATION_ERROR("expected an indented block after 'elif' statement on line %d", a->lineno) }
Bu dosyayı her değiştiriğimzde make regen-pegen
komutu ile parser.c
dosyasının bu grammar file ile
yeniden generate edilmesini sağlamalıyız.
~/cpython on main
❯ make regen-pegen
PYTHONPATH=./Tools/peg_generator python3.9 -m pegen -q c \
./Grammar/python.gram \
./Grammar/Tokens \
-o ./Parser/parser.new.c
python3.9 ./Tools/scripts/update_file.py ./Parser/parser.c ./Parser/parser.new.c
Güzel şimdi tekrar build alalım.
make -s -j8
Ve o da ne
~/cpython on main ⇡1 !2
❯ make -j8 -s
ld: warning: directory not found for option '-L/usr/local/opt/zlib/lib'
File "<frozen importlib._bootstrap_external>", line 108
elif new_root.endswith(':'):
^^^^
SyntaxError: invalid syntax
make: *** [Python/frozen_modules/importlib._bootstrap_external.h] Error 1
make: *** Waiting for unfinished jobs....
File "<frozen importlib._bootstrap>", line 299
elif hasattr(loader, 'module_repr'):
^^^^
SyntaxError: invalid syntax
make: *** [Python/frozen_modules/importlib._bootstrap.h] Error 1
File "<frozen ntpath>", line 99
elif p_drive and p_drive != result_drive:
^^^^
SyntaxError: invalid syntax
File "<frozen _collections_abc>", line 435
elif not _is_param_expr(t_args):
^^^^
SyntaxError: invalid syntax
make: *** [Python/frozen_modules/ntpath.h] Error 1
File "<frozen posixpath>", line 85
elif not path or path.endswith(sep):
^^^^
SyntaxError: invalid syntax
make: *** [Python/frozen_modules/_collections_abc.h] Error 1
make: *** [Python/frozen_modules/posixpath.h] Error 1
File "<frozen genericpath>", line 149
elif isinstance(s, bytes):
^^^^
SyntaxError: invalid syntax
make: *** [Python/frozen_modules/genericpath.h] Error 1
200 IQ hareket . elif
i değiştik ama Python internal modullerinde hala elif
kullanıyor. Dolayısıyla parser hata çıkartıyor.
Bunun çözmek için elif
keywordunu tamamen değişmek yerine elseif
i de kullanılabilir yapmak gerekiyor. Dokümantasyonda biraz gezindikten sonra
|
operatoru ile bunu yapabileceğimi anlıyorum. Aynı yerlerdeki 'elseif'
stringlerini ('elif' | 'elseif')
bununla değiştiriyorum. make regen-pegen
ve make -s -j8
komutunu çalıştırdığımızada.
~/cpython on main ⇡1 !2
❯ ./python.exe
Python 3.11.0a2+ (heads/main-dirty:36e1a69ba8, Nov 26 2021, 19:37:05) [Clang 12.0.5 (clang-1205.0.22.11)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> if True:
... pass
... elseif False:
... pass
...
>>>
Bingo!!
Artık rahatlıkla Python kullanabilirsiniz.
Kaynaklar
- https://devguide.python.org/grammar/ (opens in a new tab)
- https://realpython.com/cpython-source-code-guide/ (opens in a new tab)
- https://isidentical-archive.github.io/cpython-yeni-operator.html (opens in a new tab)
2024 © Faruk