optparse, argümanları yönetebilmemize olanak tanıyan bir arkadaşımızdır. sys modülündeki 'sys.argv' ifadesinden daha kapsamlı ve güzeldir. Ancak anlaması, akılda tutması ve uygulaması gerçekten zordur. Bu yüzden sakin bir kafayla okuyup uygulamalarınızı yapın; tekrar tekrar okumaktan ve denemekten çekinmeyin.
Bu blogu Linux üzerinden götüreceğim. Başlamadan önce yine import optparse as opt olarak tanımlıyorum.

Burada yapmamız gereken ilk şey bir optparse objesi oluşturmak. Oluşturacağımız bu obje sayesinde optparse içerisindeki metotlara erişebileceğiz.

Bu, bildiğiniz değişken tanımlaması gibidir. Objemin adı 'parseObject' şeklinde. Bunun obje olmasını sağlayan şey ise karşısındaki 'opt.OptionParser()' ifadesidir. Bu sayede artık sadece değişken ismini kullanarak fonksiyonlara erişim sağlayabilirim.
Elbette, bunu aşağıdaki gibi de kullanabilirsiniz.

Başında '#' bulunan yeşil satır Python tarafından okunmayacak. Aşağı baktığınızda direkt olarak opt.OptionParser. dediğimizi ve bu şekilde bir kullanımla beraber de fonksiyonlara erişebildiğimizi görüyorsunuz. Ancak; aşağı bakalım.

Burada, bir sürü obje oluşturabileceğimiz birden fazla seçenek mevcut. Her seferinde örneğin;
opt.OptionParser.
opt.OptionContainer.
opt.OptionValueError.
gibi yazmak yerine bu değerleri bir değişkene atıyoruz ve sadece değişkeni kullanarak fonksiyonlara erişiyoruz. Bu sayede objeleri gruplandırdığımız için daha okunabilir bir kod yazmış oluyoruz. Bahsettiğim gruplama olayı da şu şekilde oluyor:

Devam edelim.

Oluşturduğumuz objenin içinde 'add_option()' şeklinde bir fonksiyon var. Bu fonksiyon, program çalıştırılırken girilen parametreleri/argümanları belirlememize olanak tanıyor. Argüman ne peki?
Örneğin Linux'ta bir araç veya bir fonksiyon hakkında <araç ismi> --help şeklinde bir ifadede bulunuyoruz.

Bu, yukarıdaki örnekte 'date --help'. İşte, buradaki --help bizim argümanımız oluyor. Normal şartlarda sadece date yazmış olsaydınız bugünün tarihini alırdınız. Ancak date fonksiyona --help ifadesini verdiğiniz zaman ona uygun sonuçlar elde ediyorsunuz.
Biraz önceki add_option() fonksiyonu bunu yapıyor. add_option(), temelde iki parametre alıyor. Hemen örnek verelim.

İlk önce '--help' gibi, '--age' şeklinde bir şey yazdık ve bir virgül koyduk. Buradaki '--age' bizim parametremiz oluyor. Eğer python deneme.py derken yanına --age koymazsak program çalışmayacaktır.
Hemen yanındaki dest="my_age" ise, biraz sonra tanımlayacağımız değişken oluyor. Zaten 'dest (destination)' kelimesinin anlamı 'hedef, varış yeri' şeklindedir.
Normalde my_age = 23 dediğimiz zaman aslında python deneme.py --age 23 demiş oluyoruz. Buradaki --age parametre iken dest= kısmı, o parametrenin tutulduğu yerdir.
Bunu birazdan daha iyi anlayacaksınız.

Eğer "--age" ifadesi bir parametre ise ve dest="my_age" bir değişken ise bunlara sırasıyla value yani değer ve key yani anahtar diyemez miyiz? İşte tam bu yüzden oraya bir Tuple tanımladım ve içerisine (value, key) değerlerini verdim. Eşitliğin diğer tarafında ise, parseObject isimli objemin parse_args() isimli fonksiyonuna eriştim. Bu durumda optparse yapısı, value ve key değerlerinin ne olduğunu artık biliyor.

Sakin olalım ve ilk önce kırmızı kutucuklara odaklanalım; diğer kısımları görmeyin.
dest="my_age" dediğimiz zaman aslında, hedefimizin my_age değişkeni olduğunu söylemiştik; biliyorsunuz. Şimdi yeşil kutulara bakalım.
Oradaki '--age' parametresinin aslında value olduğundan söz ettim. O zaman ben, my_age = value.my_age dersem (fonksiyonlardaki nokta ile çağırma işlemi gibi) bunları birbirine bağlamış olmaz mıyım?
Yani my_age = value.my_age derken aslında şunu demiş oluyorum: "Benim my_age değişkenim, --age parametresine verilen değerdir." O zaman ben, python deneme.py --age 23 şeklinde çalıştırırsam ve my_age aslında --age parametresine verilen değer ise my_age değişkeni 23 olur.

Genel bir özet yapalım bence.
İlk önce bir obje oluşturduk. Bu objeyi, fonksiyonlara kolayca erişebilmek için oluşturduk. Sonrasında add_option() fonksiyonuyla opsiyonlar ekledik. Bu opsiyonlardan ilki (--age) value, ikincisi ise (dest=) key değeri oldu. Bunların value ve key olduğunu optparse'a anlatmak için de (value, key) şeklinde bir Tuple oluşturduk ve parse_args() fonksiyonu yardımıyla bunu optparse'a tanıttık.
Sonra, my_age = value.my_age şeklinde bir denklem verdim. Bu denklemin anlattığı şey şuydu: "'dest' yani hedef olan my_age değişkenimin değeri, value olan --age parametresi ne ise o olsun". Sonrasında programı çalıştırırken --age 23 yazdım yani aslında --age parametresine 23 değerini verdim. Bu da otomatik olarak my_age konumuna düştü.
value dediğimiz parametreleri çoğaltabiliyoruz:

Gördüğünüz gibi önceden yazılmış araçların parametreleri genelde hem tek haneli hem de birkaç haneli oluyor. Mesela -h ile --help aynı işi yapacaktır; -m ile --mac aynı şeyi yapacaktır. Biz de bundan yapabiliriz.

add_option() kısmına bakın. "-a", "--age" şeklinde tanımlamalar yapabiliyoruz. Çıktı kısmına baktığınızda ikisinin de çalıştığını göreceksinizdir. Ayrıca eksik veya yanlış parametrelerin hata verdiğini / doğru sonuç vermediğini de görüyoruz.
Peki, diyelim ki kullanıcı gerçekten de programı nasıl çalıştıracağını bilmiyor ve python deneme.py --help yaptı. O zaman ne yapabiliriz? Örneğin bir uyarı değişkeni tanımlayıp onu, sys.argv[1]'in --help olması koşulunda print ettirebiliriz. Ancak bunu yaptığımızda birden fazla olasılığı değerlendirmek zorunda kalırız ve her hata türü için ayrı kodlar yazmamız gerekir. optparse bunu da düşünmüş.

dest=... ifadesinin yanına bir virgül koyup help menüsü oluşturabiliyoruz. Buradaki help, sadece -a veya --age için geçerlidir. Mesela bir opsiyon daha oluşturalım.

Gördüğünüz gibi bir opsiyon daha oluşturdum. Ancak tekrardan (value, key) = parseObject.parse_args() yazmadım. Çünkü o satır, bütün opsiyonlar için geçerli; sonuçta tüm opsiyonlarda bir adet value, bir adet key mevcut.
my_job = value.my_job satırı ile dest= kısmını yerine getirdim ve my_job değişkenini -j veya --job parametresine girilen değer olarak atadım.
Son olarak bunu yazdırdım ve çıktı ekranında iki türün de çalıştığını görüyorsunuz.

Yaptığımız help menüsü de bence güzel oldu :).
Normal şartlarda kullanıcı için bir kullanım kılavuzu hazırlayacağınız zaman şöyle bir şey yaparsınız:

Aslında bir sorun yoktur; oldukça kullanışlıdır da. Ancak optparse kullanıyorsanız bunu, help= kısmında belirleriz ve kullanıcı --help dediğinde ona bu menü gösterilir. Peki, optparse ile bunu yapmanın daha tatlı bir yolu olduğunu söylesem?
Önce yazdığım basit kodu size göstereyim; inceleyin, sonra devam edin.

Buradaki parser değişkeni, geçmişte gösterdiğim parseObject ile aynıdır yalnızca ismi farklıdır. Bunun 'parser' olarak tanımlanması daha yaygın bir kullanımdır. Geri kalan her şey bildiğiniz yapılar.
Şimdi, bir usage kurmak istiyorum. İyi izleyin.

parser = opt.OptionParser() diyerek bir obje oluşturuyorduk. Aslında boş bıraktığımız bu parantezler arasına bir kullanım kılavuzu veya istediğiniz başka bir şeyi yerleştirebilirsiniz. Ancak bunu çağırırken print(usage) değil, print(parser.usage) olarak çağırmanız lazım. Artık parser objesinin başlı başına bir kullanım kılavuzu (usage) mevcut oluyor. Yani buradaki parser objesi artık bir string de tutuyor. O yüzden bunu 'parser.usage' olarak çağırmamız gerekiyor.
Bunu;
parser = """
***USAGE***
"""
şeklinde normal bir değişkenmiş gibi algılayabilirsiniz. Arka planda olan şey tam olarak bu; sadece optparse yapısı burada bize biraz daha esneklik sağlıyor.
Peki, bunu nerede ve nasıl kullanabiliriz?

Madem bir usage'imiz var; o zaman help=parser.usage diyebiliriz, öyle değil mi? Bunu dedikten sonra --help parametresi ile bunu çalıştırırsanız, OptionParser içine verdiğiniz kullanım kılavuzunun gösterildiğini görürsünüz. Hem daha güzel hem de daha kullanışlı.
Ayrıca lütfen bakın;

Köşede yazan Usage: kelimesini ben eklemedim. Bunu, optparse ekledi. Bu da, parser.usage kullanımını açıklayan bir unsur.
Bunu başka yerlerde de kullanabilirsiniz. Mesela kullanıcı, -s ifadesini yazdı ama surname değişkeninin ihtiyaç duyduğu değeri vermedi; bu durumda bir hata ile karşılaşırız:

Aşağıda, "-s opsiyonu bir argümana ihtiyaç duyuyor" şeklinde bir hata mesajı görüyorsunuz. Hemen yukarı bakarsanız optparse arkadaşımız, kendiliğinden usage fonksiyonunu ortaya koyuyor ve kullanıcıyı uyarıyor; usage fonksiyonunu biz çağırmadık, kendisi çağırdı.
Peki, diyelim ki kullanıcı bir opsiyonu (-n veya -s) komple yazmadı. Bu durumda optparse, None sonucunu döndürür.

-n Cyber dedim ama -s Worm demedim. Çıktı ise 'Hi, I'm Cyber None.' şeklinde geldi. Dikkat ederseniz bu durumda usage fonksiyonu devreye girmedi. Yani kullanıcı bir opsiyon daha girmesi gerektiğini bilmiyorsa ve bu çıktıyla karşılaşıyorsa bu büyük bir sorundur. Herkes, bu durumları programı kodlayan kadar anlamak zorunda değil. O zaman bir kontrol yapalım.

Burada ne dedim?
Tuple içerisindeki 'value' değerimiz opsiyonlarla eşleşiyordu, öyle değil mi? O zaman ben value.opsiyon (value.name) diyebilir ve bunu kontrol edebilirim.
Burada dediğim şey şu: "Eğer name opsiyonunun value değeri None ise ya da surname opsiyonunun value değeri None ise kullanıcıyı uyar ve parser.usage fonksiyonunu göster. Değilse, ekrana çıktısını ver."
Çıktı kısmında gördüğünüz gibi kullanıcının kafasındaki soru işaretlerini resmen yok ediyoruz ve her şeyi ona anlatıyoruz.
parser.usage kullanımı bu şekilde idi.
Şimdi, Tuple hakkında biraz konuşalım.
(value, key) şeklinde klasik bir ifademiz söz konusuydu. Evet, bu sık kullanılan bir kullanım şeklidir. Ancak (options, args) şeklinde bir kullanım daha vardır ve bu da gerçekten sık kullanılır. Mantık tamamen aynıdır; değişen şey sadece isimleridir.
(options, args) derken aslında --age tarzındaki yapılar opsiyonlarımız, dest="my_age" şeklindeki yapılar ise argümanlarımız ya da opsiyon değerlerimiz oluyor. Başka bir yerde bu kullanımı görürseniz ya da ileriki zamanlarda (options, args) kullanımını ben yaparsam aklınız karışmasın.
Peki, diyelim ki kullanıcı --age opsiyonuna bir tam sayı girmesi gerekirsen string girdi; ne olur?

Gördüğünüz gibi bir sorun olmuyor. Ancak bazı durumlarda nasıl ki int tipinde girdi alırken int(input("")) diyor ve girilecek değerin tipini kesin olarak belirtiyorsak bunu optparse için de yapabiliriz.

Bunun için yapmanız gereken tek şey dest= ile help= arasında type= tanımlamak olmalıdır. type=str, type=int, type=float veya type=bool şeklinde tanımlamalar yapabilirsiniz.
Çıktı kısmında sağ olsun, optparse bizim yerimize kullanıcıyı uyarıyor: "-a invalid integer value" yani "geçersiz tam sayı değeri" şeklindeki bir uyarı sayesinde kullanıcı durumu anlayıp düzeltecektir.
Yayınlanma Tarihi: 2022-11-27 15:37:17
Son Düzenleme Tarihi: 2022-12-01 12:27:12