Python Funksiyalarının İşləmə Məntiqi və __code__ Atributu
Bir python faylı işlənərkən aşagıdakı kimi icra olunur :
Bir python faylı işlənərkən aşagıdakı kimi icra olunur :
Your Python Code (.py file)
↓
[Parser]
↓
Abstract Syntax Tree (AST)
↓
[Compiler]
↓
Bytecode (.pyc file)
↓
[Python Virtual Machine]
↓
CPython Interpreter (C code)
↓
System Calls
↓
Operating System Kernel
↓
CPU ExecutionBu mərhələlərin birindən bytecode -dan bəhs edəcəm.
Python funksiyalarının işləmə məntiqi iki səviyyədə baş verir:
- Stack səviyyəsi(variable səviyyəsi)
- Funksiyanın öz səviyyəsi (call səviyyəsi)
Yəni, bir funksiya başqa funksiyanı çağırırsa, həmin funksiya işə düşür, sonra çağıran funksiya davam edir.
Modul və Stack Frame
Proqram başladıqda birinci olaraq modul işə düşür. Modul Python-da ən yüksək frame-dir. Python bunu avtomatik yaradır. Modul özü funksiya deyil, amma öz stack frame-i var.Hər bir xarici modulu import etdikdə python avtomatik ona global dəyişən kimi verir.
Call funksiyaları və stack frame-lər Python virtual maşınında (Python bytecode) yaranır və onları proqram daxilində praktik olaraq görə bilərik. Call stack funksiyanın səviyyəsində baş verir və hesablana bilir.
Funksiya Misalı: add
def add(a, b):
return a + b- Bu funksiya iki integer
avəbqəbul edir və onların cəmini qaytarır. - Funksiyanı işə salanda əvvəlcə modul səviyyəsi başlayır.
- Daha sonra
addfunksiyası çağırılır. - Əgər funksiya başqa funksiyanı çağırsa, onlar zəncirvari işə düşür və nəticə qaytarılır.
—
Recursion Misalı: Factorial
def factorial(n):
if n == 1:
return 1
else:
return n * factorial(n - 1)
factorial(5)factorial(5)çağıranda əvvəlcəfactorial(1)icra olunur, sonrafactorial(2),3,4,5- Yəni funksiya daxilində çağırılan funksiya öncə ,sonra isə özü tamamlanır və bu ardıcıl olaraq gedir .
- Stack frame-lər LEGB qaydasına görə izolə olunur: Local, Enclosing, Global, Built-in.
LEGB Qaydası və Dəyişənlər
x = "global"
def alter():
x = "enclosing"
def inner():
x = "local"
print(x)
inner()
print(x)
alter()
print(x)- inner() funksiyasını çağıranda x local qaydada “local” olacaq.
- alter() daxilində x inclusion qaydasında “enclosing” olacaq.
- Modul səviyyəsində x isə global olaraq “global” qalır.
in və is Operatorları
A = [1, 3, 3]
x = 3
y = 3
x in A # True
x == y # True
x is y # True, çünki referans eynidiriniterable-də bərabərliyi yoxlayır.==dəyərlərin bərabərliyini yoxlayır.isreferansın eyniliyini yoxlayır (id).
Əgər iki eyni ədədi fərqli dəyişənlərdə saxlasanız:
invə==bərabərliyini göstərəcəkisisə fərqli olduğunu göstərəcək
Stack Frame və Traceback
import sys
sys._getframe() # hazırda işləyən frame-i qaytarır
import inspect
inspect.stack() # call stack-i qaytarırStack trees-lərini print ilə göstərə bilərsiniz.
Cold və Hot Code (Python 3.11+)
- Cold code: universal bytecode istifadə edir, yavaşdır.
- Hot code: tez-tez istifadə olunan kod optimizasiya olunur, inline caching ilə 60% daha sürətlidir.
Call stack və stack frame hər çağırışda yaranır, amma hot code-da əməliyyatlar daha sürətlidir.
Bytecode Misalı: String Concatenation
def string_concat(name):
return "hello " + name + "!"load_const–"hello "string stəkə qoyulurload_fast–namedəyişəni stəkə qoyulurBINARY_ADD– toplama əməliyyatıload_const–"!"stəkə qoyulurBINARY_ADD– yenidən toplamaRETURN_VALUE– nəticə qaytarılır
Alternativ və daha optimal yanaşma:
def string_concat(name):
return f"hello {name}!"load_const–"hello "stəkə qoyulurload_fast–namestəkə qoyulurFORMAT_VALUE+BUILD_STRING– string birləşdirilirRETURN_VALUE– nəticə qaytarılır
Bu üsul aralıq obyekt yaratmır və daha səmərəlidir.
__code__ Atributu və Code Object
Hər bir Python funksiyası bir code object ilə əlaqəlidir.
__code__ atributu funksiyanın icra edilən bytecode və onun atributlarını göstərir.
code = greet.__code__- Burada
greet(hər hansısa funksiyadır) funksiyasının code obyektinicodedəyişəninə atırıq.
print(f" - Argument count: {code.co_argcount}")co_argcount→ funksiyaya verilən argumentlərin sayı- Məsələn,
def greet(name, age)funksiyasındaco_argcount = 2
print(f" - Local variables: {code.co_nlocals}")co_nlocals→ funksiyanın içində təqdim edilmiş lokal dəyişənlərin sayı.- Məsələn,
x = 5vəy = 10varsa,co_nlocals = 2.
print(f" - Stack size needed: {code.co_stacksize}")co_stacksize→ Python virtual maşını üçün funksiyanın işləməsi zamanı lazım olan maksimum stack hündürlüyü.
print(f" - Variable names: {code.co_varnames}")co_varnames→ funksiyada istifadə olunan lokal dəyişənlərin və argumentlərin adları tuple şəklində.Məsələn:('name', 'age', 'x', 'y')
print(f" - Constants used: {code.co_consts}")co_consts→ funksiyada istifadə olunan sabitlər (constants).- Məsələn,
return 5 + 10olarsa, burada5və10constants kimi görünəcək. - Funksiyada stringlər və
Noneda constants siyahısına daxildir.
print(f" - Bytecode size: {len(code.co_code)} bytes")co_code→ funksiyanın compiled bytecode-nu saxlayır.len(code.co_code)→ bytecode-un bayt ölçüsü.- Bu, funksiyanın Python virtual maşın üçün neçə baytlıq əmrlərdən ibarət olduğunu göstərir.
Pythonda dis kitabxanası ilə bunu asanlıqla yoxlamaq olar .dis kitabxanası python kodlarını bytecode formatında oxunaqlı şəklə çevirir.