Berk Akademi
Ana Sayfa
ÖZEL KODLAMA DERSLERİ
Yazılım Özel Ders
Tüm birebir programlara genel bakış
Python Yazılım Kursu
Sıfırdan ileri seviyeye birebir Python
Java Yazılım Kursu
OOP odaklı birebir Java eğitimi
AP Computer Science Principles
AP CSP sınav hazırlığı
GRUP DERSLERİ
Python & Django Masterclass
SINIRLI KONTENJAN
Java & Spring Boot Masterclass
SINIRLI KONTENJAN
C# .NET Masterclass
SINIRLI KONTENJAN
VİDEO DERSLER
Sıfırdan Temel Python Kursu
Kendi Hızında Öğren
ÜCRETSİZ
Seviye Testi
Ücretsiz — Python, Java, algoritma seviye testleri
Kariyerini Keşfet
Sertifika Doğrula
Belge numarası ve soyad ile doğrulama

Python'da Circular Import (Dairesel İçe Aktarma) Hatası: Nedeni ve Kalıcı Çözümü

Yazar: Berk Keskin 29.08.2026 ~11 dk okuma 2 Okunma
python-circular-import-hatasi-cozumu

Python'da circular import (dairesel içe aktarma) hatası, iki veya daha fazla modülün birbirini doğrudan ya da dolaylı olarak import etmeye çalışması sonucu ortaya çıkar ve genellikle ImportError: cannot import name ya da AttributeError şeklinde karşımıza çıkar. Bunun temel nedeni, Python'un modülleri baştan sona sırayla çalıştırması ve bir modül tam olarak yüklenmeden önce içindeki isimlerin dışarıdan erişilebilir olmamasıdır. Yani hata, kodun mantığından değil, modüllerin yüklenme sırasından kaynaklanır. Bu yazıda hem hatanın neden oluştuğunu hem de duruma göre uygulanabilecek çözüm yollarını adım adım ele alacağız.

Circular Import Hatası Nedir ve Neden Ortaya Çıkar?

Python bir dosyayı çalıştırırken ya da import ederken, dosyanın içeriğini yukarıdan aşağıya doğru, satır satır işler. Bir import ifadesine geldiğinde, hedef modül daha önce yüklenmemişse önce o modülün tamamını (ya da import edilen kısmına kadar olan bölümünü) çalıştırır, sonra kaldığı yerden devam eder. Bu mantık tek başına sorun çıkarmaz; sorun, iki modül birbirini import etmeye çalıştığında ortaya çıkar.

Şöyle düşünün: a.py çalışmaya başlar, ilk satırlarında b.py'yi import eder. Python, b.py'nin yüklenmesine geçer. Ancak b.py da içinde a.py'yi import ediyorsa, Python "bu modül zaten yükleniyor" der ve elindeki yarım kalmış (henüz tüm fonksiyon ve sınıfları tanımlanmamış) a.py nesnesini geri döndürür. Eğer b.py, a.py'den henüz tanımlanmamış bir isme erişmeye çalışırsa, işte tam bu noktada hata patlar. Hata mesajı genellikle kafa karıştırıcı görünse de aslında oldukça mantıklı bir sıralama sorununu anlatır.

Bu davranış, Python'un modül sisteminin bir kusuru değil, tasarım gereğidir: her modül yalnızca bir kez ve sırayla çalıştırılır, tekrar import edildiğinde belleğe alınmış hâli kullanılır. Dairesel bağımlılık, bu tek seferlik yükleme mantığıyla iki modülün eşzamanlı olarak birbirine ihtiyaç duymasının çakışmasından doğar. Konuyu daha görsel örneklerle ve alıştırmalarla pekiştirmek isteyenler, Python modül sistemi üzerine hazırlanan yazılar arasında benzer senaryoları adım adım inceleyebilir. Bir sonraki bölümde bu durumu somut bir kod örneğiyle canlandıracağız.

Hatayı Üreten Somut Örnek: a.py ve b.py

Hatayı Üreten Somut Örnek: a.py ve b.py

Circular import'u en net şekilde görmenin yolu, hatayı bilerek üretmektir. Aşağıdaki senaryoda iki dosya var: a.py, b.py'den bir fonksiyon çağırıyor; b.py ise a.py'den bir değişkene ihtiyaç duyuyor. İkisi de birbirini modül seviyesinde, yani dosyanın en üstünde import ediyor.

# a.py
import b

deger = "a modulunden gelen deger"

def a_fonksiyonu():
    return b.b_fonksiyonu()

print(a_fonksiyonu())
# b.py
import a

def b_fonksiyonu():
    return a.deger

a.py çalıştırıldığında sırasıyla şunlar olur: Python a.py'yi işlemeye başlar, ilk satırda import b görür ve b.py'ye geçer. b.py'nin ilk satırında import a vardır, ancak a.py zaten yükleniyor olduğu için Python onu tekrar baştan çalıştırmaz; o an elinde ne varsa (henüz deger tanımlanmadan önceki hâli) ile devam eder. b.py'nin geri kalanı sorunsuz yüklenir çünkü b_fonksiyonu henüz çağrılmamıştır, sadece tanımlanmıştır. Kontrol tekrar a.py'ye döner, deger tanımlanır, a_fonksiyonu tanımlanır ve çağrılır. Bu çağrı b.b_fonksiyonu()'nu tetikler, o da a.deger'e erişmeye çalışır. Bu noktada a modülü artık tam yüklendiği için genellikle sorun çıkmaz; ama fonksiyon çağrısı yerine modül seviyesinde doğrudan a.deger kullanılsaydı ya da import sırası tersine dönseydi, AttributeError: module 'a' has no attribute 'deger' ya da ImportError: cannot import name 'deger' from partially initialized module 'a' hatasıyla karşılaşılırdı. Hatanın ortaya çıkıp çıkmayacağı, tam olarak hangi satırın hangi anda çağrıldığına bağlıdır; bu da circular import'u bazen fark edilmeden duran, bazen aniden patlayan bir hata hâline getirir.

Hatayı Teşhis Etme Adımları

Circular import hatasıyla karşılaşıldığında panik yapmadan, hatanın verdiği izleri sistematik biçimde okumak sorunu genellikle birkaç dakika içinde ortaya çıkarır. Traceback mesajı rastgele değildir; modüllerin yüklenme sırasını adım adım gösterir.

  1. Traceback'in en altındaki hata satırını okuyun: cannot import name 'x' from partially initialized module 'y' ifadesi, hangi ismin hangi modülden alınamadığını doğrudan söyler.
  2. Traceback'i yukarı doğru takip ederek import zincirini çıkarın: hangi dosya, hangi satırda, hangi modülü import etmeye çalışırken bu noktaya gelmiş, sırayla listeleyin.
  3. Zincirdeki modüllerin dosyalarını açıp import ifadelerinin dosyanın en üstünde mi yoksa bir fonksiyon içinde mi olduğuna bakın; modül seviyesindeki import'lar döngüye daha çok girer.
  4. Hangi modülün önce, hangisinin sonra yüklendiğini anlamak için her iki dosyanın da import satırlarına geçici olarak print(__name__) ekleyip çalıştırmayı deneyin; çıktı sırası yükleme sırasını gösterir.
  5. Sorunlu ismin (değişken, fonksiyon veya sınıf) modül içinde import satırından önce mi sonra mı tanımlandığını kontrol edin; genellikle asıl kırılma noktası burasıdır.

Bu adımları uyguladıktan sonra elinizde net bir tablo olur: hangi iki modülün birbirine bağımlı olduğu ve bağımlılığın tam olarak hangi isim üzerinden kurulduğu. Bir sonraki bölümde bu bilgiyi kullanarak duruma göre uygulanabilecek çözüm yollarını ele alacağız.

Çözüm 1 ve 2: Import'u Fonksiyona Taşıma ve Ortak Modül Çıkarma

Dairesel içe aktarma sorununu ortadan kaldırmanın en hızlı yollarından biri, modül seviyesindeki import satırını fonksiyonun içine taşımaktır. Python bir modülü yalnızca ilk çağrıldığı anda içe aktarır; eğer import ifadesi dosyanın en üstünde değil de bir fonksiyonun gövdesinde duruyorsa, o satır fonksiyon gerçekten çalıştırılana kadar hiç işletilmez. İki modülün birbirini dosya yüklenirken değil, ihtiyaç anında çağırması gerektiği durumlarda bu yaklaşım işe yarar.

# a.py
def kullanici_olustur():
    from b import loglama_yap
    loglama_yap("kullanici olusturuldu")

# b.py
def loglama_yap(mesaj):
    from a import kullanici_olustur  # sadece gerektiğinde
    print(mesaj)

Burada her iki dosya da açılırken birbirini beklemek zorunda kalmaz; import işlemi fonksiyon çağrıldığında devreye girer ve o noktada ilgili modül zaten tamamen yüklenmiş durumdadır. Bu çözüm özellikle küçük veya orta ölçekli dosyalarda, iki fonksiyon arasında nadiren tetiklenen bir bağımlılık varsa mantıklı bir seçenektir.

İkinci yaklaşım ise sorunun kökenine iner: iki modülün ortak olarak ihtiyaç duyduğu kodu üçüncü bir modüle taşımaktır. a.py ve b.py'nin birbirini çağırma sebebi genelde ortak bir sabit, yardımcı fonksiyon veya veri yapısıdır. Bu ortak parça ayrı bir dosyaya (örneğin ortak.py) alındığında, a.py ve b.py artık birbirine değil, üçüncü modüle bağımlı hale gelir ve döngü kırılır.

# ortak.py
def loglama_yap(mesaj):
    print(mesaj)

# a.py
from ortak import loglama_yap

def kullanici_olustur():
    loglama_yap("kullanici olusturuldu")

# b.py
from ortak import loglama_yap

def siparis_olustur():
    loglama_yap("siparis olusturuldu")

Bu yöntem yalnızca hatayı gidermekle kalmaz, aynı zamanda kodun okunabilirliğini de artırır; çünkü hangi fonksiyonun nerede tanımlı olduğu artık tek bir mantıksal yerden takip edilebilir. Proje büyüdükçe bu tür ortak modüller genellikle utils, common veya core gibi adlarla toplanır ve ekip içinde nereye ne yazılacağı konusunda ortak bir anlayış oluşur.

Çözüm 3: Lazy Import ve Üç Yöntemin Karşılaştırması

Çözüm 3: Lazy Import ve Üç Yöntemin Karşılaştırması

Lazy import (tembel içe aktarma), fonksiyon içine taşıma yönteminin biraz daha bilinçli uygulanmış hâlidir: burada amaç sadece hatayı susturmak değil, gerçekten ihtiyaç olmayan bir bağımlılığı programın başlangıcında yüklememektir. Özellikle bir modülün nadiren kullanılan, ağır veya opsiyonel bir bağımlılığı varsa, bu bağımlılığı yalnızca ilgili fonksiyon çağrıldığında içe aktarmak hem döngüyü kırar hem de programın açılış süresini gereksiz yere uzatmaz.

# raporlama.py
def detayli_rapor_olustur(veri):
    # bu fonksiyon nadiren cagrilir, bagimliligi da nadiren gerekir
    from analiz import istatistik_hesapla
    sonuc = istatistik_hesapla(veri)
    return sonuc

Buradaki fark şudur: fonksiyon içine taşıma çoğunlukla "hata veriyor, böylece düzeliyor" mantığıyla yapılırken, lazy import bilinçli bir mimari tercihtir ve genellikle hangi bağımlılığın ne zaman gerçekten gerekli olduğu düşünülerek uygulanır. Üç yöntemi bir arada değerlendirmek, hangi durumda hangisinin daha uygun olduğunu görmeyi kolaylaştırır.

Yöntem Ne Zaman Uygun Esneklik
Fonksiyon içine taşıma Hızlı, geçici bir çözüm gerektiğinde; iki modül arasında sınırlı sayıda çağrı varken Orta — sorunu çözer ama mimariyi değiştirmez
Ortak modül çıkarma Bağımlılık kalıcı ve iki taraftan da sık kullanılıyorsa; proje büyüdükçe tekrar sorun çıkmasın isteniyorsa Yüksek — kod tekrar kullanılabilir ve okunaklı hale gelir
Lazy import Bağımlılık ağır, nadiren kullanılan veya opsiyonel bir modülse; başlangıç süresi önemliyse Yüksek — hem döngüyü kırar hem performansa katkı sağlar

Hangi yöntemin seçileceği projenin büyüklüğüne, modüller arası ilişkinin sıklığına ve ekip alışkanlıklarına göre değişir; tek bir doğru cevap yoktur. Bu tür mimari kararları alırken import mekanizmasının nasıl çalıştığını gerçekten kavramak, kod yazarken karşılaşılan pek çok belirsizliği ortadan kaldırır. birebir Python dersleri kapsamında bu tarz proje yapısı ve modül tasarımı konuları, öğrencinin kendi projeleri üzerinden adım adım işlenir.

Büyük Projelerde Circular Import Neden Daha Sık Görülür?

Küçük bir betikte circular import nadiren karşılaşılan bir durumdur; ama proje büyüdükçe, özellikle katmanlı bir mimariye (örneğin veri erişim katmanı, iş mantığı katmanı, sunum katmanı gibi ayrımlara) geçildikçe bu hata çok daha sık ortaya çıkar. Bunun nedeni basittir: modül sayısı arttıkça, hangi modülün hangisine bağımlı olduğunu takip etmek zorlaşır ve iki katman birbirinin sorumluluğuna girecek şekilde tasarlandığında döngüsel bir bağımlılık oluşması kolaylaşır.

Sorumlulukların net ayrılmadığı projelerde bu durum daha da belirginleşir. Bir modülün hem veri işleme hem de iş kuralı barındırması, o modülün başka birçok modülle iki yönlü ilişki kurmasına yol açabilir. Sorumluluk ayrımı ilkesine sadık kalınan projelerde ise her modülün ne yaptığı ve neye bağımlı olduğu daha öngörülebilir olur, bu da circular import riskini azaltır.

Burada dikkat edilmesi gereken bir nokta daha var: circular import her zaman ImportError: cannot import name şeklinde açık bir hata olarak görünmeyebilir. Bazı durumlarda program hiç hata vermeden çalışmaya başlar, ancak belirli bir fonksiyon çağrıldığında modülün henüz tam yüklenmemiş olması nedeniyle AttributeError ile karşılaşılır. Bu, geliştiricinin ilk bakışta sorunu import mekanizmasıyla ilişkilendirmesini zorlaştırabilir; çünkü hata mesajı doğrudan "import" kelimesini içermez, bir nesnenin beklenen özelliğe veya fonksiyona sahip olmadığını söyler.

Büyük ölçekli projelerde çalışmayı hedefleyen biri için bu tür yapısal sorunları önceden tanımak, sonradan büyük bir yeniden yapılandırma yapmaktan çok daha az maliyetlidir. Yazılım kariyerinde hangi alanın veya hangi proje ölçeğinin kişiye daha uygun olduğunu görmek isteyenler için ücretsiz kariyer testi bu konuda genel bir yönlendirme sunabilir. Sonuç olarak, modül mimarisini baştan düşünmek, hatayı sonradan avlamaktan her zaman daha az yorucudur.

Bilginizi Test Edin ve Derinleşin

Circular import hatasını bir kez elle çözdükten sonra akılda kalıcı hâle gelmesi için üzerinde biraz daha durmak faydalıdır. Bu tür sorunlar genellikle "neden çalışıyor, neden çalışmıyor" sorusuna net bir cevap bulamadığınız anlarda tekrar karşınıza çıkar; dolayısıyla modül sistemi, isim alanı (namespace) ve import sırası gibi kavramları sadece hatayı düzeltmek için değil, gelecekteki tasarım kararlarınızı şekillendirmek için de anlamak değer katar.

Bu noktada nerede durduğunuzu görmek isteyenler için Python bilgi testi kısa ve pratik bir öz değerlendirme imkânı sunar; modül yapısı, import mekanizması ve temel dil özellikleri üzerine sorularla mevcut seviyenizi görebilir, eksik kalan noktaları netleştirebilirsiniz.

Test sonucunda bazı konuların yüzeysel kaldığını fark etmek gayet normaldir; circular import gibi hatalar genellikle "syntax bilmek" ile "proje mimarisini okuyabilmek" arasındaki farkın en net görüldüğü yerlerdir. Kod satır satır doğru olabilir, ama modüller arasındaki ilişki yanlış kurulduğunda hata yine de ortaya çıkar. Bu ayrımı kendi başına, deneme-yanılma yoluyla kapatmak zaman alabilir; özellikle projeniz büyüdükçe hangi modülün nereye bağımlı olduğunu takip etmek zorlaşır.

Böyle durumlarda bire bir ilerleyen bir çalışma biçimi, kişinin kendi projesi üzerinden mimari hataları görmesini hızlandırabilir. Kendi kodunuzdaki bağımlılık zincirini bir eğitmenle birlikte inceleyip nerede kopardığınızı, nerede birleştirdiğinizi tartışmak, genel anlatımlarla geçiştirilemeyecek türde bir netlik sağlar. Bu, herkes için tek doğru yol anlamına gelmez; bazı öğrenciler için grup dersinde tartışılan örnekler yeterli olurken, bazıları için kendi projesine özel bire bir geri bildirim daha hızlı sonuç verir. Önemli olan, hangi yöntemin sizin öğrenme biçiminize uyduğunu fark etmektir.

Sık Sorulan Sorular

Circular import hatası her zaman ImportError olarak mı görünür?

Hayır. Duruma göre ImportError: cannot import name şeklinde net bir mesaj alabileceğiniz gibi, bazen modül yarım yüklendiği için AttributeError ile de karşılaşabilirsiniz; ikinci durumda hata mesajı doğrudan "circular import" demez, bu yüzden kaynağı ilk bakışta anlamak daha zordur.

İki modül birbirini import etmek zorundaysa ne yapmalıyım?

Önce gerçekten zorunlu mu diye sorgulamak gerekir; çoğu zaman iki modülün ortak ihtiyaç duyduğu sınıf veya fonksiyon üçüncü bir dosyaya taşınabilir. Eğer ilişki gerçekten karşılıklıysa, ihtiyaç anına kadar import'u erteleyen bir yaklaşım (fonksiyon içi import gibi) durumu çalışır hâle getirebilir; hangisinin daha uygun olduğu projenin yapısına bağlıdır.

Fonksiyon içine import taşımak performansı etkiler mi?

Python zaten yüklenmiş bir modülü tekrar diskten okumaz, önbellekten getirir; bu yüzden fonksiyon çağrıldıkça oluşan ek yük genellikle ihmal edilebilir düzeydedir. Asıl dikkat edilmesi gereken nokta performans değil, bu tekniğin kalıcı bir mimari çözüm mü yoksa geçici bir kurtarma mı olduğudur.

Ortak modül oluşturmak ne zaman gereksiz karmaşıklık yaratır?

İki modül arasında tek seferlik, küçük bir bağımlılık varsa, sadece bunun için ayrı bir dosya açmak projeye gereksiz bir katman ekleyebilir. Ortak modül çıkarmak genellikle birden fazla dosyanın aynı sınıf veya sabitlere ihtiyaç duyduğu, tekrarlayan durumlarda anlamlı hâle gelir; tek seferlik durumlarda daha basit bir çözüm yeterli olabilir.

Circular import'u projenin başında nasıl önleyebilirim?

Kesin bir formülü olmasa da, modülleri katmanlar hâlinde düşünmek (örneğin veri modelleri, iş mantığı, arayüz gibi) ve alt katmanın üst katmanı import etmemesine dikkat etmek riski azaltır. Proje büyüdükçe bu düzeni korumak zorlaşabilir; bu yüzden zaman zaman modül bağımlılıklarını gözden geçirmek faydalı bir alışkanlıktır.

Circular import hataları çoğu zaman kötü yazılmış kodun değil, modüller arasındaki ilişkinin zamanla karmaşıklaşmasının bir sonucudur; bu yüzden hatayı fark ettiğinizde kendinizi suçlamak yerine mimariyi yeniden okumak daha verimli bir bakış açısıdır. Bu tür yapısal konularda kendi projeniz üzerinden ilerlemek isterseniz 1-1 özel Python dersleri bağımlılık yönetimini ve modül tasarımını somut örneklerle çalışma imkânı sunar.

Bu içeriğin üretilmesinde yapay zeka araçlarından destek alınmıştır.

İlgili Eğitimler

Berk Keskin — Yazılım Geliştirici ve Eğitmen
Yazar

Berk Keskin Kimdir?

Yazılıma 12 yaşında başladı; bugün öğrencinin seviyesine ve hedefine göre şekillenen sürdürülebilir öğrenme sistemleri tasarlıyor. 300'den fazla kişiye ezber değil, düşünerek kod yazmayı öğretti — Berk Akademi'de izlemeye değil üretmeye dayalı öğrenme kültürünü o kuruyor.

WhatsApp Hemen Ara