Python’daki nesne
kavramı ile sözlük
kavramı birbirine benzeyen kavramlardır. Python nesnelerinin nitelikleri ve metodları varken, Python’daki sözlüklerin anahtarları ve bu anahtarların değerleri vardır. Python nesnelerinin nitelik ve metodlarının isimlerini bir sözlüğün anahtarlarıymış gibi, nitelik ve metodların değerlerini de bu sözlüğün değerleri gibi düşünebilirsiniz.
Sözlük yapısının temelinde C
dilindeki struct
’lar yer alıyor aslında. C, object oriented bir dil olarak geçmez ama nesne tabanlı dillerde yer alan “nesne” kavramını, C’deki struct
yapısını kullanarak oluşturabiliriz. Yani struct
veri yapısı, yeni sınıflar oluşturmak için gerekli özellikleri sağlar. Benzer şekilde dict
veri tipi de bir sınıf ve o sınıfa ait nitelikleri ve metodları oluşturmak için yeterlidir. Python’da struct
’a en çok benzeyen veri tipi dict
veri tipidir dersek herhalde abartmış olmayız.
Şimdi gelin, bir Python sözlüğü tanımlayalım:
sozluk = {
"x": {
"x_x1": {
"x_x1_x1": 1,
"x_x1_x2": lambda x: print(x)
},
"x_x2": lambda x: print(x)
},
"y": 2
}
Bu sözlük, bir sınıfın niteliklerinin ve metodlarının nasıl bir düzende yer aldığını gösteren bir eşleştirme olarak da kabul edilebilir aslında. Şimdi bu sözlüğü nesneye çeviren bir fonksiyon yazalım ve bu fonksiyon da aşağıdaki işlemleri yapsın;
Sözlüğün anahtarlarının değerlerinin tipleri eğer dict
ise, o anahtarlar nesnelere işaret etsin. Aksi durumda, yani sözlüğün anahtarlarının değerlerinin tipleri dict
dışında başka bir veri tipiyse, o anahtarlar da nesnenin niteliği
veya metodu
haline gelsin. Sonuç olarak sözlük içinde sözlük, nesne içinde nesne olarak dönüştürülsün.
Fonksiyonu yazalım:
def from_dict_to_obj(d: dict) -> object:
obj = type("", (), {})
for key, value in d.items():
if isinstance(value, dict):
setattr(obj, key, from_dict_to_obj(value))
else:
setattr(obj, key, value)
return obj
Şimdi from_dict_to_obj
isimli fonksiyonu, sozluk
isimli sözlüğü argüman olarak yazarak çağıralım. Sonra da sözlükte anahtar
olarak yer alan x_x1_x2
ismini, bir metod ismi olarak kullanalım.
obj = from_dict_to_obj(sozluk)
obj.x.x_x1.x_x1_x2("hello")
Çıktı:
hello
dict
tipinden object
’e dönüştürme yapabiliyoruz, peki object
’ten dict
’e bir dönüşüm yapacak olsaydık, nasıl yapardık?
def from_obj_to_dict(o: object) -> dict:
dictionary = {}
for key, value in {k: getattr(o, k) for k in dir(o) if not k.startswith("_")}.items():
if isinstance(value, type):
dictionary[key] = from_obj_to_dict(value)
else:
dictionary[key] = value
return dictionary
Hemen bir örnek yapalım:
obj = from_dict_to_obj(sozluk)
print(from_obj_to_dict(obj))
Çıktı:
{'x': {'x_x1': {'x_x1_x1': 1, 'x_x1_x2': <function <lambda> at 0x000001B81B6A9760>}, 'x_x2': <function <lambda> at 0x000001B81B6A9C60>}, 'y': 2}
Başka bir örnek:
class Test:
def __init__(self, x):
self.x = x
class It:
y = 1
def print(self, a):
print(a)
test = Test(x=10)
print(from_obj_to_dict(test))
Çıktı:
{'It': {'print': <function Test.It.print at 0x000001F82DD65EE0>, 'y': 1}, 'x': 10}
Şöyle deneyelim:
test = Test(x=10)
_dict = from_obj_to_dict(test)
_dict["It"]["print"]("1", "hello")
Çıktı:
hello
Son paylaştığım kodlardaki son satırdaki ifade şöyle:
_dict["It"]["print"]("1", "hello")
Bu kısmı açıklayayım izninizle:
Test
sınıfı içinde yer alan It
sınıfında tanımlı print
metoduna dikkat ederseniz, metodun ilk argümanının self
olduğunu görürsünüz. Buradaki self
, sınıftan oluşturacağımız bir nesneyi işaret eder. Dolayısıyla print
metodu bir sınıf metodu değil, bir örnek metodudur.
İyi ama, biz yukardaki kodda It
sınıfından bir örnek oluşturmadan, print
fonksiyonunu kullanabildik? Bu nasıl oldu?
nesneyi
, sözlüğe dönüştürdükten sonra, print
metodunun ilk argümanı, herhangi bir sınıfın örneğini argüman olarak kabul eder, özellikle It
sınıfından oluşturulan bir örneğe ihtiyaç duyulmaz.
Yani, bu kod da aynı çıktıyı üretir:
_dict["It"]["print"]([1, 2, 3], "hello")
Bu kod da:
_dict["It"]["print"](1, "hello")
Peki, bundan nasıl kurtuluruz?
class Test:
def __init__(self, x):
self.x = x
class It:
y = 1
def print(a):
print(a)
print
fonksiyonunu, yukardaki gibi bir örnek
veya sınıf
metodu olmaktan çıkarırsak, artık _dict["It"]["print"](1, "hello")
ifadesi yerine, _dict["It"]["print"]("hello")
ifadesini kullanabiliriz.
Bu arada, metod, bir sınıf metodu olsaydı, yani, print
fonksiyonu şöyle olsaydı:
class Test:
def __init__(self, x):
self.x = x
class It:
y = 1
def print(cls, a):
print(a)
Bu sefer, print
fonksiyonunu çağırırken, ilk argüman olarak herhangi bir sınıfın kendisini argüman olarak verebilirdik:
_dict["It"]["print"](int, "hello")
Bu mesajda Python’daki nesneleri dinamik bir yolla oluşturmamızı sağlayan bir yaklaşımdan bahsetmeye çalıştım. Şimdilik anlatacaklarım bu kadar. Sorusu olan arkadaşların, sorularını yanıtlamaktan memnuniyet duyarım. Ayrıca katkı sağlamak isteyen arkadaşlara da şimdiden teşekkür ederim.
Konuyla bağlantılı olarak aşağıdaki başlığın da belki faydası olabilir.
Herkese iyi çalışmalar.