Python - Etkileşimli Program Kullanmak

Merhaba,

Otomatik olarak çalışan python programlarım var. Bu programlar döngüler ile çalışıyor. Fakat program çalışırken durmasını istersem programı kapatmam gerekiyor. Kapatmak yerine döngünün durmasını ve tekrar başlamak için seçim yapmamı beklemesini istiyorum.

Bunu nasıl yapabiliriz?

bu dediğinin kodunu yaz, olmayan yerlere ekleme yaparız.

for i in range(10):
    print(i)
    if i == 5: 
        x = input("E/h")
        if x=="E" and x== "e":
            print(i)

        else:
            break

programın kodu yazılı

bahsettiğim mevzu bu değil. program 1 dakika içerisinde 29 farklı işlemi gerçekleştiriyor ve bu sonsuza kadar sürüyor. Yani her döngü de bana devam edeyim mi? diye sormaması gerekiyor. örn END tuşuna bastığım zaman programın küt diye durması lazım. Döngüyü bitirmesi lazım

öncelikle kodu görmeden dediğini anlamak çok zor. kodu görsem bile senin ne istediğini gene anlayamayabilirim. eğer kod 50 klasör içinde 50 dosya içinde classlar, database vs falan varsa. yani kodun çok uzun ise kodun hepsini at demiyorum. kodun sadece sorunlu olan kısmını sadeleştirip atabilirsin. 29 döngü var demek ile kimse bişey anlamaz. en basiti for döngüsümü while mı yada bu for senkron mu asenkron mu neye göre cevap verelim ki ? tuşa bastığım zaman küt diye durması lazım diyosun ya. class kullanıyosan kodu farklı yazılır. class yok sadece fonksiyonlar varsa kodu farklı yazılır. asenkron olarak tuşa basıldığında kod duracaksa, thread veya multiprocessing kütüphanelerini kullanmak gerekir. yukarıda örnek bi kod attım. bu tarz bi kod istediğini düşündüm ama öle değil dedin. yani işi gücü bırakıp senin ne düşündüğünü tahmin etmeye çalışıp, kod örnekleri atalım ozaman sende aradan seç beğendiğini kullan.

Değerli üye,

Açılan konu başlığında yapılan iç açıklamaya baktığınız takdirde görmeniz gereken şey bizzat yazdığım kodlara özel olarak tasarlanacak bir çözüm algoritması değildir.

Forum üyeliğinizden bu zamana ve etkinlik gösterdiğiniz süreler doğrultusunda diğer üyeler tarafından açılan konularda belirtilmeyen temel eksiklikler üzerine çok fazla bağlı kalıp açılan her konu ve yazılan her soruna karşılık aynı fikir sistemi ile yaklaşıyor olmanız sizi çözüme giden yola açılan kapının anahtarının bulunduğu yere bile götürmeyecektir.

Son tahlilde forumda açılan konular için daha detaylı yardımcı olabilmek adına konu sahiplerinden olabildiğince detaylı açıklamalar, kod paylaşımları, hata paylaşımları ve gerek duyulursa görsel desteklemeler talep ediyoruz. Ancak bu açılan konu içeriğinde her kod yazılmadığı zaman talep edilecek ilk şey bu değildir.

Bahsi geçen ve yukarıda görebileceğiniz üzere talep edilen çözüm için yazılan sorun açıklaması belirli bir kodu belirten ama belirli bir kod için talep edilen bir çözüm içeriği değildir. İlgili konu sahiplerinin taleplerini anlamak için daha doğru okumak şart. Elbette istisnalar mevcuttur ancak üstte yer alan açıklamada talep edilen tam detaylı olarak tarif edilmiştir.

Genel forum kullanım ve diğer konular için yapılan etkileşimlerinizde kullanmakta olduğunuz dil ve üslubun uygunluğu konusunda şahsi olarak olumsuz düşünmekle birlikte konunun geri kalanında sahip olduğunuz bilgi birikimin kullanmanıza gerek kalmadığını daha değerli vakitlerde ve konularda kendinizi değerlendirmenizi rica ederim.

Not: Bahsedilen husus Thread modülü ile çözüme ulaştırılmıştır.

İyi forumlar dilerim.

1 Beğeni

POSIX’te SIGSTOP ve SIGCONT signal(7)'lerini kullanarak programi duraklatip yeniden baslatabilirsiniz.

Onun disinda durma/baslama mantigini kodun icine yazmak gerekiyor.

Windows’ta Ctrl-C, Linux’ta SIGINT ile gelen KeyboardInterrupt da yakalanabilir (except bloguyla) bu arada.

5 Beğeni

Üstadım bildiğiniz üzere tkinter ile yapılan bir programda çalıştırılan buton fonksiyonları tamamlanana kadar pencereyi kilitliyor. Bu yüzden fonksiyon çalışırken durdurmak istediğim de programı kapatmak gerekiyor. Bu mevzunun çözülmesi şart. Sonuçta bir sürü masaüstü program kullanıyoruz ve çalışan bir modülü durdurup yeniden başlatmak için kapatmaya gerek kalmıyor.

Anlamadım. Programların otomatik çalışması ne demek? Programlar normalde nasıl çalışıyor?

Evet bazı programlar döngülerle çalışır. Ama burada ne kastettiniz? Otomatik çalışan programlarınız sıra ile bir döngü şeklinde mi çalışıyor? Yoksa otomatik çalışan programlarınızın içinde for, while vs gibi döngüler mi var?

Program çalışırken durmasını istersem programı kapatmam gerekiyor ne demek? İşletm sistemleri hiç bir programı, program sonuna kadar asla durdurmaz.

Belki sistem servisleri durdurulabilir ama bu farklı bir konu. Bir program bir iş yapar ve durması için bir neden yoksa program sonuan kadar gider. Hiç bir iş yapmayan windows programları bile bir sistem boşta işlemi çevirir asla durmaz. Çünkü callback fonskiyonlar içerir ve gider ara ara mesaj kuyruğunu kontrol eder. Etmezse varsayımsal durdursanız dahi geri çalıştıramazsınız.

Döngünün içinde bir status/durm alıp eğer durum size göre durma ise bir boşta döngüsü içinde döndürmeniz bu arada mesaj kuyruğunu kontrol ettirmeniz ve tekrar başlama isteğiniz durumunda bir önceki döngünüzü yeniden çağırmasını sağlamalısınız.

Bunu bir çok şekilde yapabiliriz.

Ama belirgin bir tasarım olursa daha özel çözüm üretilebilir. Aksi halde teorik bir öneride bulunabiliriz.

Bu kadar bilinmeze rağmen tahmini teorik öneride bulunalım.

Elimizde otomatik programlarımız ve bunların içinde de döngülerimiz var.

Hiç bir döngü koşul sağlanana kadar kodun ilgili kısmını bırakmaz. İçerisinde çalışmaya devam eder.

Bu durumda o döngü içinde bir dışına çıkış koşulu koymak ve her döngüde kontrol etmek gerekir.

Döngü içindek kod işletilirken koşul değişirse döngünün dışına çıkış verilir.

Thread 'i durdurdunuz. Program durdurmaktan farkı ne oldu? Bu tartışmaya açık. Çünkü devam ettirdiğinizde kaldığı yerden devam edecektir, döngünün başına gelmeyecektir. Tabi bunu bir kod üzerinde detaylıca konuşmak gerekir.

Ben olsam, döngüsünün içinden çıkmak istediğim noktalarda bir hotkey tanımlar o hot key ile boş bir döngüye çeker o döngü de hiç bir işlem yapmadan sadece mesaj kuyruğunu dinler yeniden talep gelirse tekrar ilgili döngüyü çağırırdım.

Yani run terimi programlama için boşa söylenmemiştir. Programlar işletim sistemleri üzerinde koşturulur.

Koşturulan bir şey kolay kolay durdurulmaz. İstisnası, debug tooları üzerinde geçici olarak yapılır.

Ki o ayrı bir yaklaşım gerektirir.

Kesme/interrupt yaklaşımı ile de bir yere kadar;

Interrupt the Main Thread in Python (superfastpython.com)

Yani teori üzerinde her yöne gidebiliriz.

Burada asıl hedefi yakalayamadım.

Hedefi yakalarsak daha net çözüm önerilebilir?

Neden bir programı durdurmak istiyoruz?

Kaynak tüketimini sınırlamak için mi?

Çalışma koşullarını değiştirmek için mi?

Çalışma adımlarını gözlemlemek için mi?

Ne tür bir seçim?

Seçimi durdurmadan da yapabilir miyiz?

Mesela seçimlerimiz bir tamponda dursa, döngü tamponu çektiğinde yeni duruma göre devam edebilse mesela.

Evet haklısınız size göre detaylı ama bana göre detaylı değil.

Nedeni de şu, yukarıdaki sorularım nedeniyle açık noktalar var ve açık noktalar netleşmezse onlarca farklı varyasyonda çözümler oluşuyor.

Ama basit bir mantık hatası görüyorum. Programlar durdurulmak için koşturulmaz. Koşullar değişirse yeni duruma göre karar alabilir şekilde kodlanır. Kod bir şey yapmadan bekleme kararı almışsa aslında durmaz bir sistem boşta döngüsünde döner.

Bu da kimsenin suçu değil, işletim sisteminin tasarımından kaynaklıdır.

Yani asıl yapmak istediğinizi, yada neden yapamadığınızı, yada sizi neden durmaya zorlayacak bir karar aldırıyorsa iyi bir şekilde belirtirseniz alternatif çözümler azalır ve seçenekler daha da netleşir.

Sorunuzdaki mantıksızlığı (bu hakaret değil mantık hatasını belirginleştrime olarak düşünün.) şöyle anlatayım. Bir progamınız var. Programınız çalışıyor, durdurana kadar, işletim sistemi ile callback fonksiyonlarla sizin kodlarınız hariç haberleşir. Siz bir programı durdurursanız, bu haberleşmeyi de durdurursunuz. Peki duran bir program, nasıl olup da işletim sisteminden gelen devam et, çalış gibi komutları işleyecek?

Durdu işleyemez.

Artık onu haricen çalıştırmanız gerekir. Haricen çalıştırmak demek programın başlatılırken kontrolünü bir debuger a bırakmak ve sonra durduğundan onun adına mesajları dinlemesini ve tekrar çalıştırmasını istemek gibi bir yöntemdir ki bu sizin istediğiniz şey değildir diye düşünüyorum.

Yani tekrar söyleyim. Hiç bir program durmaz. Verilen fonksiyonlar dışında sadece sistem mesajlarını dinleyeceği bir döngüye çekilir.

Tabi bu döngü ile sizin döngüler arasındaki koordinasyonu da sizin main fonksiyonunuz sağlar.

Thread ile çözümde ise mekanizme programı durdurmaz, thread’i durdurur.

Yani üzerinde düşündükçe her yanında soru işaretleri oluşuyor.

Sıkıntı nedir? Neyi yapamadınız? Neyi hedeflediniz?

Bunları belirterek kodu durdurmaya iten yaklaşımınıza alternatfler üretebiliriz.

Aksi halde debuger kodu vermeye başlayacağım.

2 Beğeni

Duygularıma tercüman oldunuz .

Şimdi Tkinter nereden çıktı? Sorunuzda Tkinter yoktu.

Programı durdurmak istediğiniz belirmiştiniz, ama alttakinde, butonun tkinter altında uzun bir döngü çağırdığında ekranın kilitlenmesinden bahsediyorsunuz.

Bu ikisi aynı şey değil.

Konu tkinter ve butonları serbest bırakmak isterseniz yapmanız gereken şey butondan kodu thread ile çağırmak. Hepsi bu.

Hadi geçtik, thread’e bile gerek yok, çok meşgul etmeyen bir kod ise;

python - How to break a while loop with a tkinter button without freezeing the executable - Stack Overflow

Buradaki basit yöntem de kullanılabilir.

How to stop a loop with a stop button in Tkinter (tutorialspoint.com)

İlk soru ile ilgili ve ikinci soru ile ilgili hala kafamda soru işaretleri var ama neyse.

1 Beğeni

Aynen öyle bu kadar laf kalabalıığı yapacağına “tkinter donuyor” diye konu açsaydı. Zaten thread olacağı belliydi.

hocam @BandoLero ya biraz pasif agresif bir yorum yazmışsınız fakat en başta tkinter kullandığınızı söyleseydiniz direkt threading diyip geçebilirdik. maalesef ben de en başta ne istediğinizi anlayamadım.
Program çalışırken durmasını istersem kapatmam gerekiyor ne demek mesela ne yazık ki anlayamadım. Arkadaşlar sizden kod istediğinde atmış olsaydınız tkinter kullandığınızı anlayıp direkt çözümü sunabilirdik. “Kusura bakmayın benim hatam” diyip geçmeniz gereken yerde de hâlâ haklı çıkmaya çalışmanız bize bir zarar vermez fakat sizin egonuza ciddi manada mağlup olduğunuzu gösterir. Ego özellikle bu alanda öğrenmenin çok önüne geçiyor. Buradaki basit bir “Kodunu atarsan anlayabiliriz” cevabına (ki size yardım için istenen bir şey) öfkeleniyorsanız bence gözden geçirmeniz gereken bir ego sorununuz var demektir.
Yazdıklarımı ofansif algılamayın lütfen. Gelişim ve öğrenme önünde büyük bir engeli fark ettirmeye çalıştım. Kolay gelsin.

3 Beğeni

Merhaba,

Bildiğiniz gibi tkinter ana penceresi, widgetlerden herhangi birinin mainloop fonksiyonu çağrıldığında görünür hale geliyor. mainloop fonksiyonunu çağırmak bir döngünün oluşmasına neden oluyor. Ve bu döngüden çıkmadan başka bir döngünün çalışmasına geçmek mümkün olmuyor.

Döngüleri eşzamanlı çalıştırmanın birden çok yöntemi var;

Örneğin, eşzamanlı iş parçacıkları oluşturmak için threading kütüphanesini kullanabilirsiniz.

Veya asenkron görevler oluşturmak için asyncio kütüphanesini de kullanabilirsiniz.

Ama eşzamanlı görevler yazabilmek için özellikle bir kütüphane kullanmanıza gerek yok aslında.

Gelin, sizle herhangi bir kütüphane kullanmadan, nasıl tkinter ana penceresini eşzamanlı çalışacak bir şekilde programlarız, buna odaklanmaya çalışalım.

Eşzamanlı programlar yazabilmek için generator (üreteç) ve coroutine (eşyordam) kavramlarını iyi anlamak gerekiyor. Bir generator, yinelendiğinde bir dizi değer üreten bir fonksiyondur ve boyutu görece büyük olan verilerde oldukça da kullanışlıdır çünkü verinin tamamı hafızaya alınmaz, bunun yerine yineleme ile elde edilen değer hafızaya alınır.

Bir coroutine ise istendiği zaman durdurulabilen ve sonra da kaldığı yerden devam ettirilebilen ve eşzamanlı görevlerde kullanılmaya oldukça müsait bir fonksiyon tipidir.

Python’da her coroutine bir generator’dür de aynı zamanda, ama her generator bir coroutine değildir. Coroutine’lerin yield ifadeleri değer kabul ederler, yani send ile argüman alabilirler. Generator’lerde ise, yield edilecek değerler fonksiyonun içinde üretilirler.

Aşağıdaki başlıkta konuyla alakalı bazı yazılar var, bakın isterseniz:

Şimdi burada anlattıklarıma göre eşzamanlı çalışan bir tkinter penceresi oluşturmaya çalışalım. Ama önce bir husustan bahsetmeme izin verin. Normalde, tkinter ana penceresini şöyle görünür hale getiriyoruz:

import tkinter as tk

root = tk.Tk()
root.mainloop()

Bu yönteme alternatif olarak, aşağıdaki gibi bir yöntem de kullanabilirsiniz:

import tkinter as tk

root = tk.Tk()
while True:
    root.update()

Tabi bu ikinci yaklaşımda bazı protokolleri elle tanımlamanız da gerekir. Örneğin programın kapanma protokolü nasıl olacak gibi…

Şimdi, ister mainloop’u kullanın, ister kendi mainloop’unuzu yazın fark etmiyor gerçekten. Her iki durumda da uzun süre aktif olacak birden çok görevi aynı anda çalıştırmak için coroutineler oluşturmamız lazım.

Aşağıdaki örnekte kaç tane coroutine varsa o kadar coroutine eşzamanlı olarak çalıştırılır. Örnekte iki tane coroutine var. Bunlardan ilki tkinter’in ana penceresini güncelliyor, güncelleme işleminden sonra görev sırası diğer coroutine’e geçiyor. Bir coroutine, kendisine send ile gönderilen ve yield edilen değer ile bir görevi tamamladıktan sonra (bu değeri işlemde kullanmak zorunda değil elbette) durur ve sırasını başka bir coroutine’e devreder, sırayı devralan coroutine kendisine send ile gönderilen ve yield edilen değer ile bir görev yapar ve durur, bu kez başka bir coroutine devreye girer…

Aşağıdaki kodları inceleyin lütfen:

import tkinter as tk


# async_mainloop bir coroutinedir.
def async_mainloop(r):
    # Sonsuz bir döngü oluşturalım.
    while True:
        try:
            # Tkinter ana penceresini X düğmesine basarak
            # kapatmaya çalıştığımızda aşağıdaki ifade hata yükseltecek.
            r.winfo_exists()
            # Tkinter ana penceresini görünür hale getirelim.
            r.update()
            # send ile gönderilen None değerini alalım.
            yield
        # Beklediğimiz hatayı yakalayalım.
        except tk.TclError:
            # Döngüden çıkalım.
            break


# async_loop bir coroutinedir.
def async_loop():
    # x isminde bir tane dummy variable tanımladık. 
    x = 0
    # Sonsuz döngümüzü tanımlayalım.
    while True:
        # dummy değişkenimizi değiştirelim.
        x += 1
        # Değeri değişen değişkeni ekrana yazdıralım.
        print(x)
        # send ile gönderilen None değerini alalım.
        yield


# multiloop bir coroutine değil, sıradan bir fonksiyondur.
def multiloop(*coroutines):
    # coroutineleri sırayla ziyaret etmek için
    # x isminde bir değişken tanımlıyoruz.
    x = 0
    # Sonsuz bir döngü oluşturalım.
    while True:
        try:
            # her bir coroutine'e None değerini gönderelim.
            # Bu örnekte gönderdiğimiz değer ile bir işlem
            # yapılmadığı için, değeri None olarak gönderdik.
            # Eğer gönderilecek değer ile bir işimiz olsaydı,
            # None yerine o değeri gönderirdik.
            coroutines[x].send(None)
            # İndisi 1 birim artıralım.
            x += 1
            # Eğer indis, coroutines'in uzunluğuna eşitse;
            if x == len(coroutines):
                # Sıfırıncı indise tekrar dönelim.
                x = 0
        # Tkinter ana penceresini yok ettiğimizde, async_mainloop
        # fonksiyonu duracak ve StopIteration hatası yükseltecek.
        # Bu hatayı yakalayalım.
        except StopIteration:
            # Döngüden çıkalım.
            break


# Eşzamanlı döngülerimizi çalıştıralım.
multiloop(async_mainloop(tk.Tk()), async_loop())

Yukardaki koddaki async_loop fonksiyonundaki döngüyü çalıştıran bir start düğmesi ve durduran bir stop düğmesi tanımlanabilirdi ve bu durumda fonksiyon içinde bir takım değişiklikler yapmak gerekebilirdi.

Mesela şöyle:

import tkinter as tk


# async_mainloop bir coroutinedir.
def async_mainloop(r):
    # Ana döngümüzü tanımlayalım.
    while mainloop:
        # Tkinter ana penceresini görünür hale getirelim.
        r.update()
        # send ile gönderilen None değerini alalım.
        yield


# async_loop bir coroutinedir.
def async_loop():
    # x isminde bir tane dummy variable tanımlayalım.
    x = 0
    # Ana döngümüzü tanımlayalım.
    while mainloop:
        # Start ve Stop düğmelerine duyarlı alt döngümüzü tanımlayalım.
        while subroutine:
            # dummy değişkenimizi değiştirelim.
            x += 1
            # Değeri değişen değişkeni ekrana yazdıralım.
            print(x)
            # send ile gönderilen None değerini alalım.
            yield
        # send ile gönderilen None değerini alalım.
        yield


# multiloop bir coroutine değil, sıradan bir fonksiyondur.
def multiloop(*coroutines):
    # coroutineleri sırayla ziyaret etmek için
    # x isminde bir değişken tanımlıyoruz.
    x = 0
    # Coroutineler arasında geçiş yapabilmek için
    # ana döngümüzü tanımlayalım.
    while mainloop:
        # her bir coroutine'e None değerini gönderelim.
        # Bu örnekte gönderdiğimiz değer ile bir işlem
        # yapılmadığı için, değeri None olarak gönderdik.
        # Eğer gönderilecek değer ile bir işimiz olsaydı,
        # None yerine o değeri gönderirdik.
        coroutines[x].send(None)
        # İndisi 1 birim artıralım.
        x += 1
        # Eğer indis, coroutines'in uzunluğuna eşitse;
        if x == len(coroutines):
            # Sıfırıncı indise tekrar dönelim.
            x = 0


# start bir coroutine değil, sıradan bir fonksiyondur.
def start():
    # Alt döngüyü kontrol edecek global değişkeni dahil edelim.
    global subroutine
    # Döngüyü başlatalım.
    subroutine = True


# stop bir coroutine değil, sıradan bir fonksiyondur.
def stop():
    # Alt döngüyü kontrol edecek global değişkeni dahil edelim.
    global subroutine
    # Döngüyü sonlandıralım.
    subroutine = False


# close bir coroutine değil, sıradan bir fonksiyondur.
def close():
    # Ana döngülerimizi kontrol edecek global değişkeni dahil edelim.
    global mainloop
    # Döngüyü sonlandıralım.
    mainloop = False


# Ana döngülerimizi kontrol edecek global değişkeni tanımlayalım.
mainloop = True
# Alt döngüyü başlatacak ve durduracak değişkeni tanımlayalım.
subroutine = False
# Tkinter ana penceresini tanımlayalım.
root = tk.Tk()
# Ana pencereyi kapatma protokolünü yeniden tanımlayalım.
root.protocol("WM_DELETE_WINDOW", close)
# Buttonlarımızı tanımlayalım.
start_button = tk.Button(root, text="Start", command=start)
start_button.pack()
stop_button = tk.Button(root, text="Stop", command=stop)
stop_button.pack()
# Eşzamanlı döngülerimizi çalıştıralım.
multiloop(async_mainloop(root), async_loop())

Sorununuzu threading veya asyncio ile de çözebilirsiniz elbette, ama bu yaklaşımı da görmenizi ve anlamaya çalışmanızı isterim. Konuyla alakalı sorularınız olursa elimden geldiğince cevaplamaya çalışırım.

Tekrar görüşmek üzere, kendinize iyi bakın.

4 Beğeni