Aynı fonksiyonun tkinter ve normalde farklı çalışması

Merhabalar, Tkinter ile yazdığım ufak bir bir arayüzüm var. Entry ve butonlardan değerleri alıp arkaplanda SOAP WebService ile veri aktarmak istiyorum. Zeep modülü ile Python Console üzerindeki denemelerimde veriyi aktarmayı başardım ancak dosya üzerinde bazı sıkıntılar yaşıyorum.

Öncelikle, arayüzden buton veya entry üzerindeki değeri alıyorum burda bir sıkıntı yok. Ancak işlemeye çalıştığımda (farklı bir dosya üzerinden işlemeye ve geri döndürmeye çalışıyorum) Python Console üzerinden doğru çalışan fonksiyon dosya üzerinden None döndürüyor

dosya üzerinden, şöyle gönderiyorum

urun_karti.Kategoriler = kategoriIDS.int.append(
            get_category_id(kwargs['category'])
        )

Burada amacım get_category_id üzerinden verdiğim değerin ID numarasını almak ve servisin metoduna eklemek

Fonksiyon ise şu şekilde; ayrıca başka bir dosyada kayıtlı ancak fonksiyonu düzgün şekilde çağırdığından import konusunda problem olduğunu sanmıyorum


def get_category_id(category, categories=categories):
    for key, value in categories.items():
        if (key == category):
            return value['ID']
        elif ('AltKategori' in value):
            get_category_id(category, value['AltKategori'])

bu fonksiyonla aynı dosyada bulununan ve kategorileri yüklememi sağlayan fonksiyon şu;

def load_categories():
    with open("assets/categories.json", encoding = "utf-8") as file:
        data = file.read()

    return json.loads(data)

categories = load_categories()

kategorilerin olduğu json dosyası çok uzun ama biraz kısaltıp eklersem;

{
    "Ön Siparişteki Yayınlar": {
        "ID": 7
    },
    "Hukuk Kitapları": {
        "ID": 2,
        "AltKategori": {
            "Anayasa Hukuku": {
                "ID": 9,
                "AltKategori": {
                    "AİHM": {
                        "ID": 32
                    },
                    "Bireysel Başvuru": {
                        "ID": 33
                    },
                    "Devlet ve Hükümet Sistemleri": {
                        "ID": 34
                    },
                    "İnsan Hakları": {
                        "ID": 35
                    },
                    "Siyasi Partiler ve Seçim": {
                        "ID": 36
                    },
                    "Temel Hak ve Özgürlükler": {
                        "ID": 37
                    }
                }
            }
        }
    }
}

Sorun şurda oluşuyor. Örn. butondan ‘Hukuk Kitapları’ gelmiş olsun, o zaman bu değerin ID olan 2’yi düzgün şekilde döndürüyor. ‘AİHM’ gelmiş olsun, o zaman “None” döndürüyor ama Python Console üzerinden çalıştırsam düzgün şekilde çalışıyor ve 32 değerini döndürüyor.

Ayrıca == yerine “is” ile de denedim sonuş alamadım. type ile türlerini kontrol ettim hem “key” hem gönderdiğim değer “str” yani tür uyuşmazlığı da yok

Not: iç içe sözlük kullanmamın sebebi arayüzde iç içe menüler oluşturmak

Merhaba,

None değerini alıyor olmanızın nedeni ,elif durumunda fonksiyonun kendisini return etmemeniz ile ilgili.

return get_category_id(category, value['AltKategori'])

Yine None değeri alıyorum

categories = {
    "Ön Siparişteki Yayınlar": {
        "ID": 7
    },
    "Hukuk Kitapları": {
        "ID": 2,
        "AltKategori": {
            "Anayasa Hukuku": {
                "ID": 9,
                "AltKategori": {
                    "AİHM": {
                        "ID": 32
                    },
                    "Bireysel Başvuru": {
                        "ID": 33
                    },
                }
            }
        }
    }
}


def get_category_id(category, categories=categories):
    for key, value in categories.items():
        if (key == category):
            return value['ID']
        elif ('AltKategori' in value):
            get_category_id(category, value['AltKategori'])



print(get_category_id("Hukuk Kitapları"))
print(get_category_id("AİHM"))

Yukardaki fonksiyona göre print(get_category_id("AİHM")) ifadesi, None döndürür.

Fonksiyonu şöyle değiştirirsek:

def get_category_id(category, categories=categories):
    for key, value in categories.items():
        if (key == category):
            return value['ID']
        elif ('AltKategori' in value):
            return get_category_id(category, value['AltKategori'])

print(get_category_id("AİHM")) ifadesi 32 sayısını döndürür.

Yukardaki öneri işe yaramadıysa, kodunuzun tkinter ile ilgili olan kısımlarını da paylaşın, bir bakalım.

Kodları mümkün olabildiğince kısalttım ve Gitlab üzerinde yükledim.

Çalıştırmak için;

git clone https://gitlab.com/kulac/gui
python main.py # windows
python3 main.py # mac

helper içinde hata aldığım kod

Fonksiyonu şöyle değiştirelim:

def get_category_id(category, categories, result=0):
    if category in categories and not result:
        result += categories[category]["ID"]
    for k, v in categories.items():
        if "AltKategori" in v and not result:
            result += get_category_id(category, v["AltKategori"], result)
    return result
print(get_category_id("Hukuk Kitapları", categories))  # 2
print(get_category_id("Aile Hukuku", categories))  # 77
print(get_category_id("AİHM", categories))  # 32

Evet şuan çalıştı teşekkür ederim, ancak hatanın neden kaynaklandığını anlayabilmiş değilim. Ayrıca neden bir result değeri kullandık? Yazdığım ilk koddaki return nedeniyle mi sıkıntı yaşadım

Şöyle anlatayım:

def get_category_id(category, categories=categories):
    for key, value in categories.items():
        if (key == category):
            return value['ID']
        elif ('AltKategori' in value):
            get_category_id(category, value['AltKategori'])

Burada get_category_id fonksiyonuna categories sözlüğü sürekli değiştirilerek argüman olarak veriliyor değil mi? Her bir çağrımda -koşula uysun veya uymasın- fonksiyondan bir değer dönüyor aslında. Ama sorun şu ki, bu dönen değerleri tutan bir değişken yok. En sonunda categories öyle bir değer alıyor ki, içinde ne category’ye eşit ne de "AltKategori" gibi bir anahtar yer alıyor, bu durumda da None değeri geri döndürülüyor, çünkü başka bir şey dönmesi gerektiğine işaret eden bir ifade yok. Her bir key için özyineleme çalışır, dolayısıyla son sözlükte eğer category ve "AltKategori" key olarak mevcut değilse, None döner. result’ı da tanımlama sebebimiz bu. Yani bir kez ID’yi bulduktan sonra onu kaybetmemek için result isminde bir değişken kullandık. Fonksiyon çalışmasını durdurduğunda da döngünün bir aşamasında bulunan ve result isminde bir değişkene atanan ID değeri geri döndürülür.

Sanırım anladım gibi, dediğinize göre Python fonksiyonlarda bir dönüş değeri return kullansakta kullanmasakta oluyor galiba.
If koşulu sağlandıktan sonra fonksiyon devam edttiğinden değeri unutuyor ve devamında istediğim değer olmadığından None ifadesi dönüyor.

Ancak bu durumda bir özyinelemeli fonksiyon kullanmanın bir anlamı kalmıyor sanki, yada ben yanlış kurguladım. Biraz daha üstünde düşündükten sonra biraz daha iyi optimizasyon sağlayabilir miyim diye inceleyeceğim. Teşekkür ederim

Öyle, bir fonksiyon bir şey döndürmüyorsa None döndürüyordur.

Öyle.

Yo, gayet anlamlı. Kodu şu şekilde de kısaltabiliriz bu arada:

def get_category_id(category, categories):
    if category in categories:
        return categories[category]["ID"]
    for v in categories.values():
        if "AltKategori" in v and (result := get_category_id(category, v["AltKategori"])):
            return result

Karşılaştırma yapalım:

import timeit


def get_category_id_1(category, categories, result=0):
    if category in categories and not result:
        result += categories[category]["ID"]
    for k, v in categories.items():
        if "AltKategori" in v and not result:
            result += get_category_id_1(category, v["AltKategori"], result)
    return result


def get_category_id_2(category, categories):
    if category in categories:
        return categories[category]["ID"]
    for v in categories.values():
        if "AltKategori" in v and (result := get_category_id_2(category, v["AltKategori"])):
            return result


t1 = timeit.timeit(stmt=lambda: get_category_id_1("Tahkim Hukuku", categories), number=pow(10, 6))
t2 = timeit.timeit(stmt=lambda: get_category_id_2("Tahkim Hukuku", categories), number=pow(10, 6))
print(t1, t2)
5.557518300003721 3.940489200002048