Örnek ile umarım daha rahat anlaşılır. Oluşabilecek en büyük sorun identifier’ın inşaası ile (construction), çalışması arasında (execution) bağlantının kurulamaması sorunudur.
Mesela aşağıdaki program sorunsuz bir şekilde çalışıyor.
def create_func(n):
str1 = ", ".join([f"arg{i}" for i in range(n)])
str2 = f"func{len(str1.split(', ')) - 1}({', '.join(str1.split(', ')[:-1])})"
return f"lambda {str1}: list(map(lambda i: list({str2}), range({str1.split(', ')[-1]})))"
def create_globals(n):
global func1
func1 = lambda x: list(map(lambda j: 0, range(x)))
for i in range(2, n + 1):
globals()[f"func{i}"] = eval(create_func(i))
print("func =", create_func(i))
create_globals(3)
print(func3(3, 2, 4))
Bu programı çalıştırırsanız, ekrana şöyle bir çıktının yazdırılması gerekir:
func = lambda arg0, arg1: list(map(lambda i: list(func1(arg0)), range(arg1)))
func = lambda arg0, arg1, arg2: list(map(lambda i: list(func2(arg0, arg1)), range(arg2)))
[[[0, 0, 0], [0, 0, 0]], [[0, 0, 0], [0, 0, 0]], [[0, 0, 0], [0, 0, 0]], [[0, 0, 0], [0, 0, 0]]]
Çıktıya bakarsanız, aslında döngünün her bir aşamasında, bir fonksiyon inşa edildiğini ve o inşa edilen fonksiyon bir sonraki fonksiyonun inşasında kullanıldığını görürsünüz. Ve en sonunda da 3 * 2 * 4 boyutlarına sahip 3 boyutlu bir matris oluşturabiliyoruz.
Peki, ben func1
, func2
şeklinde, her bir fonksiyonun bilgisini ayrı bir identifier’da tutmak istemeyip, tek bir identifier ismi kullanarak bu işlemi yapmak istiyorum diyelim. Yani sürekli func()
'u kullanarak sonunda 3 boyutlu bir dizi elde etmeye çalışıyorum, bakalım başarılı olabilecek miyim.
def create_func(n):
str1 = ", ".join([f"arg{i}" for i in range(n)])
str2 = f"func({', '.join(str1.split(', ')[:-1])})"
return f"lambda {str1}: list(map(lambda i: list({str2}), range({str1.split(', ')[-1]})))"
def create_globals(n):
global func
func = lambda x: list(map(lambda j: 0, range(x)))
for i in range(2, n + 1):
globals()["func"] = eval(create_func(i))
print("func =", create_func(i))
create_globals(3)
func(3, 2, 4)
Bu kodları çalıştırdığım zaman aldığım çıktı da aşağıdaki gibi oluyor:
func = lambda arg0, arg1: list(map(lambda i: list(func(arg0)), range(arg1)))
func = lambda arg0, arg1, arg2: list(map(lambda i: list(func(arg0, arg1)), range(arg2)))
Traceback (most recent call last):
File "C:\Users\tanberk\Desktop\Python\test.py", line 18, in <module>
print(func(3, 2, 4))
^^^^^^^^^^^^^
File "<string>", line 1, in <lambda>
File "<string>", line 1, in <lambda>
TypeError: <lambda>() missing 1 required positional argument: 'arg2'
arg2
yazdığım halde arg2
'yi yazmadığımı belirten bir hata ile karşılaşıyorum. Neden böyle oluyor? Çünkü, tek isim altında oluşturduğum her bir fonksiyon çağrıldığında önceki inşaatlara değil, son inşaata atıfta bulunuyor.
Üretilen fonksiyonları karşılaştırın:
- programın ürettiği fonksiyonlar:
func = lambda arg0, arg1: list(map(lambda i: list(func1(arg0)), range(arg1)))
func = lambda arg0, arg1, arg2: list(map(lambda i: list(func2(arg0, arg1)), range(arg2)))
- programın ürettiği fonksiyonlar:
func = lambda arg0, arg1: list(map(lambda i: list(func(arg0)), range(arg1)))
func = lambda arg0, arg1, arg2: list(map(lambda i: list(func(arg0, arg1)), range(arg2)))
Fonksiyonlar benzer ancak dediğim gibi, fonksiyonun inşaası ile çalıştırılması arasında bağlantı sağlamak ikinci örnekte mümkün olmadı.
Değişkenleri, birden çok değişkeni tutabilen veri tiplerinde tutmak varken identifier üretmek ile uğraşmak daha zahmetli ve bug üretmeye daha müsait. Ki globals()
'e bakarsanız aslında onun da bir dict
olduğunu görürsünüz. Duruma göre list
, set
, dict
, tuple
, verilerinizi tutacağınız veri tipleri olacaktır.
Eğer amacım ilk programın ürettiği n boyutlu diziler üretmekse, daha güvenilir algoritmalar bulmam gerekir.