Oluşturulan Thread'den Global Bir Objede Değişiklik Yapmak

from tkinter import Tk, Label
from threading import Thread


class Window(Tk):
    def __init__(self):
        super().__init__()
        self.text = Label(text="0")
        self.text.pack(fill="both", expand=True)

# GLOBAL OLARAK TANIMLANMIŞ BİR WINDOW OBJESİ
root = Window()

# PENCERENİN ANA DÖNGÜSÜ
def window():
    root.mainloop()

# PENCEREDEKİ LABEL'IN YAZISINI DEĞİŞTİRME
def increase():
    i = 0
    while True:
        root.text.config(text=str(i))
        i += 1

# AYNI AYNA ÇALIŞMALARI İÇİN THREADLER
t1 = Thread(target=increase)
t2 = Thread(target=window)

t1.start()
t2.start()

Koddaki hatayı nasıl giderebilirim?

Kodlarınızı şöyle düzenledim.

#!/usr/bin/python3
# -*- coding: utf-8 -*-

from time import sleep
from tkinter import Tk, Label
from threading import Thread


class App(Label):
    def __init__(
            self,
            lower_limit: float = .0,
            upper_limit: float = .0,
            step: float = .0,
            sleep_time: float = .0,
            mode: str = "",
            *args, **kwargs
    ):
        super().__init__(*args, **kwargs)
        self.pack(side="left", fill="both", expand=True)
        self.lower = lower_limit
        self._lower = lower_limit
        self.upper = upper_limit
        self._upper = upper_limit
        self.step = step
        self.sleep = sleep_time
        if mode == "increase":
            Thread(target=self.increase, daemon=True).start()
        elif mode == "decrease":
            Thread(target=self.decrease, daemon=True).start()

    def increase(self):
        while self.lower < self.upper:
            self.lower += self.step
            self.config(text=str(self.lower))
            self.update()
            sleep(self.sleep)
        else:
            self.lower = self._lower
            self.decrease()

    def decrease(self):
        while self.lower < self.upper:
            self.upper -= self.step
            self.config(text=str(self.upper))
            self.update()
            sleep(self.sleep)
        else:
            self.upper = self._upper
            self.increase()


def main():
    root = Tk()
    App(
        master=root,
        lower_limit=0,
        upper_limit=100,
        step=1,
        sleep_time=.1,
        mode="increase"
    )
    App(
        master=root,
        lower_limit=0,
        upper_limit=100,
        step=1,
        sleep_time=.01,
        mode="decrease"
    )
    Thread(target=root.mainloop).run()


if __name__ == "__main__":
    main()

Bu hatayi mi?

Traceback (most recent call last):
  File "/usr/lib/python3.7/threading.py", line 926, in _bootstrap_inner
    self.run()
  File "/usr/lib/python3.7/threading.py", line 870, in run
    self._target(*self._args, **self._kwargs)
  File "a.py", line 22, in increase
    root.text.config(text=str(i))
  File "/usr/lib/python3.7/tkinter/__init__.py", line 1485, in configure
    return self._configure('configure', cnf, kw)
  File "/usr/lib/python3.7/tkinter/__init__.py", line 1476, in _configure
    self.tk.call(_flatten((self._w, cmd)) + self._options(cnf))
RuntimeError: main thread is not in main loop

mainloop'u ana thread’e alarak:

window()

while...else ne yapiyor bilmiyorum ama bir sekilde increase'in decrease ve decrease'in de increase'i cagirdigini varsayiyorum. Bu sonsuz recursion; tail call optimization olmayan dillerde stack yetmezligi nedeniyle patlayacaktir.

Kendi sistemimde 35 dakika gibi bir sure hesapladim ama update ve sleep cagrilari cikartilarak hemen olmasi saglanabilir.

Cozum de sonsuz loop icinde iki state arasinda gidip gelmek.

Burada niçin thread kullandık, root.mainloop() ile eşdeğer değil mi bu?
https://docs.python.org/3/library/threading.html#threading.Thread.run

Burada bir şey yapmıyor, çünkü döngünün içinde break yok.

Kullanmasak da olur.

Eninde sonunda bir RecursionError hatası yükseltilecek. Yükseltme zamanı upper_limit ve lower_limit aralığının uzunluğuna da bağlı.

Katılıyorum.

Bir şey yapmıyor değil, else durumlarında self.upper ve self.lower değişkenleri sıfırlanıyor, yani ilk konumlarına geri getiriliyorlar ve daha sonra decrease increase'i, increase de decrease'i çağırıyor. while döngüsü koşul sağlanmadığı zaman otomatik olarak duruyor ve bu kez diğer fonksiyondaki while döngüsüne geçiliyor.

1 Beğeni

Peki hangi durumlarda else durumu gerçekleşiyor? Döngü bittiğinde. else'yi kaldırıp kodu olduğu gibi yazmanın da aynı işi yapacağını düşünüyorum.

self.increase fonksiyonunda self.upper > self.lower koşulu sağlanmadığında else durumuna geçilir, self.lower while döngüsü aktif olduğu sürece self.step kadar arttırılır.

self.decrease fonksiyonunda da self.upper > self.lower koşulu sağlanmadığında else durumuna geçilir, self.upper while döngüsü aktif olduğu sürece self.step kadar azaltılır.

Aşağıda paylaştığım kod sizin dediğiniz gibi çalışıyor. Ben sadece fantezi yapıp ifadeyi o şekilde yazdım ve recursion kullanmak istemiştim. Hepsi bu :slight_smile:

@aib’in bahsettiği RecurssionError fırlatma ihtimallerini kaldırmak için kodları şöyle değiştirdim.

#!/usr/bin/python3
# -*- coding: utf-8 -*-

from time import sleep
from tkinter import Tk, Label
from threading import Thread


class App(Label):
    def __init__(
            self,
            lower_limit: float = .0,
            upper_limit: float = .0,
            step: float = .0,
            sleep_time: float = .0,
            mode: str = "",
            *args, **kwargs
    ):
        super().__init__(*args, **kwargs)
        self.pack(side="left", fill="both", expand=True)
        self.lower = lower_limit
        self._lower = lower_limit
        self.upper = upper_limit
        self._upper = upper_limit
        self.step = step
        self.sleep = sleep_time
        self.mode = mode
        Thread(target=self.start, daemon=True).start()

    def increase(self):
        self.upper = self._upper
        while self.lower < self.upper:
            self.lower += self.step
            self.config(text=str(self.lower))
            self.update()
            sleep(self.sleep)

    def decrease(self):
        self.lower = self._lower
        while self.lower < self.upper:
            self.upper -= self.step
            self.config(text=str(self.upper))
            self.update()
            sleep(self.sleep)

    def start(self):
        while True:
            if self.mode == "increase":
                self.increase()
                self.decrease()
            elif self.mode == "decrease":
                self.decrease()
                self.increase()


def main():
    root = Tk()
    App(
        master=root,
        lower_limit=0,
        upper_limit=10,
        step=1,
        sleep_time=0.001,
        mode="increase"
    )
    App(
        master=root,
        lower_limit=0,
        upper_limit=100,
        step=1,
        sleep_time=0.001,
        mode="decrease"
    )
    root.mainloop()


if __name__ == "__main__":
    main()
1 Beğeni

Ben de demek istiyorum ki bu koşul sağlanmadığında zaten döngü bitecek, else yazmasak da döngüden sonraki kodlar çalışacak. Fazladan bir etkisi mi var ki elsenin bu şekilde kullanılıyor?

Fazladan bir etkisi yok evet, sadece hoşuma gittiği için koyuyorum. :slight_smile:

1 Beğeni

^^^ Iste tam olarak bu yukardakine sebep oldugu icin sevmiyorum ve nasil calistigini anlamayi reddediyorum. Python mainstream oldu artik, bu tur “acaba C’yi iyilestirebilir miyiz” deneylerine gerek yok. Giderken caldiginiz dogru sirali if expression’ini da yerine koyun lutfen. Tesekkurler.

Bari caldigi keyword’le uzaktan-yakindan alakali bir is yapsa… while'a girilmediginde calissa belki zerre saygi gosterebilirdim.

O konuda çok fikir var:

Ne demek istediğinizi anlamadım. Python geliştiricilerine söylüyorsunuz sanırım bu sözü. :slight_smile:

for döngüsünde daha çok ihtiyaç duyuluyor.

def prime_numbers(n):
    for i in range(2, n + 1):
        for j in range(2, i):
            if i % j == 0:
                break
        else:
            print(i, end=" ")

@aib’in takıldığı konu daha çok keywordun ismiymiş gibi geldi bana.

Evet :slight_smile:

nobreak diye adlandirilmasi gereken durumdan bahsediyoruz, degil mi? for...else cunku hala “loop’a girilmezse” gibi okunuyor.

Sebepsiz yere catch'i except, throw'u raise yapan dilden nobreak keyword’u eklemekten korkmasini beklemezdim. (“Fazla keyword kullanmayalim” diye kotu bir savunma vardi, ama resmi miydi hatirlamiyorum)

Ah evet, “bu dil sacmaliklarina ragmen ogrenmeye deger mi” degerlendirmesi yaparken okumustum. Profosyonel Python’cularin sevmeyip kullanmamasi icime su serpmisti.

1 Beğeni

Bunu ben de tam anlamadım Orhan Bey.

Aynen öyle…