Class icinde islem yapma

Class içinde direkt işlem yaptığımda hata alıyorum, ama aynı işlemi __init__ fonksiyonunun altında yaptığımda çalışıyor. Bunun sebebi nedir?

Direkt yaptığımda:

>>> class Deneme:
	bosliste = []
	def ekle():
		bosliste.append('a')
	ekle()

	
Traceback (most recent call last):
  File "<pyshell#98>", line 1, in <module>
    class Deneme:
  File "<pyshell#98>", line 5, in Deneme
    ekle()
  File "<pyshell#98>", line 4, in ekle
    bosliste.append('a')
NameError: name 'bosliste' is not defined

init fonksiyonunun gövdesinde yaptığımda:

>>> class Deneme2:
	bosliste2 = []
	def __init__(self):
		self.ekle()
	def ekle(self):
		self.bosliste2.append(1)

		
>>> Deneme2()
<__main__.Deneme2 object at 0x00000243150483C8>
>>> Deneme2.bosliste2
[1]

Scope (gorunum?) kurallariyla alakali. bosliste degiskeni ekle fonksiyonuna ait degil, fonksiyonunun gorebilecegi baska herhangi bir yerde (global/modul scope’u gibi) de degil. Deneme.bosliste seklinde erisirsen calisir.

Scope derken alan adını (name space) kastettiniz sanırım. Zamanınız varsa shellde deneyip paylaşa bilir misiniz? Ben yine yapamadım.

Hayir, scope’u kastettim. Python namespace’lerinin tam olarak ne olduklarini bilmiyorum; resmi bir tanimlarina denk gelmedim. Scope ile tam ters noktalardan ayni seyi anlatiyor olabilirler.

Yapamamakta hakliymissin, olmuyor; class tanimi icinde fonksiyon cagirdigini gormemisim. Sirf ilginclik olsun diye becermeye calisacagim, ama neden boyle alisilagelemis bir sey yapmaya calisiyorsun?

Ilki mumkun degilmis:

The scope of names defined in a class block is limited to the class block; it does not extend to the code blocks of methods – this includes comprehensions and generator expressions since they are implemented using a function scope.

Ikincisinin calisma sebebi ise Deneme2 instance’inin Deneme2’nin tanimlarina erisebilmesi—Deneme2().bosliste, Deneme2.bosliste ile ayni seye refere ediyor. Instance methodunu cagirdiginda (self.ekle()) ise, ekle, Deneme2 instance’ini ilk parametre olarak aliyor.

Fonksiyonu bir classmethod'a dönüştürseniz bu sorun ortadan kalkar.

class Deneme:
    bos_liste = []

    @classmethod
    def ekle(cls):
        cls.bos_liste.append(1)


Deneme.ekle()
print(Deneme.bos_liste)

Bir sınıf özelliği olan bos_liste'yi kullanmayacaksanız istediğiniz gibi bir fonksiyon oluşturulabilir:

class Deneme:
    
    def say_hello():
        print("hello")

    say_hello()

Ayrıca sınıfın içindeki bir özelliği kullanmak için başında ya cls ya da self ifadesi olmak zorunda. Sınıf blokunun içinde cls tanımsızdır. Yani şöyle yapamayız.

class Deneme:
    bos_liste = []

    @classmethod
    def ekle(cls):
        cls.bos_liste.append(1)

    cls.ekle()

Bu yukarıdaki kodlar bize NameError hatası yükseltir.

Özetle bir sınıfın şöyle bir özelliği varsa.

class X:
    x = 1

Buradaki x niteliği sınıf metotlarında cls.x şeklinde kullanılır yok eğer örnek metodu oluşturmak istiyorsanız da self.x şeklinde kullanılır.

Sınıf niteliğinin isminin başında cls veya self olmadan, niteliğin tanımlandığı blok altında local bir alana geçmediğiniz müddetçe işlem yapabilirsiniz:

class Deneme:
    bos = []
    bos.append(1)

Ancak bos ile işlem yapan bir fonksiyon tanımlarsanız, bu bos değişkeni cls.bos veya self.bos şeklinde kullanılmazsa bos değişkeni tanımsız olur.

Bu arada bos_listeyi doğrudan değil ama argüman olarak kullanabilirsiniz:

class Deneme:
    bos = []

    def ekle(arg):
        arg.append(1)


Deneme.ekle(Deneme.bos)
print(Deneme.bos)

veya şöyle:

class Deneme:
    bos = []

    def ekle(arg):
        arg.append(1)

    ekle(bos)

Bu arada python’da bir sınıf içerisindeki metot, sınıfa ait bir özelliği kullanmayacaksa fonksiyonun üstüne @staticmethod bezeyicisi yazılır. Eğer bir sınıf niteliği veya metodu ile işlem yapan bir fonksiyon tanımlanacaksa da @classmethod yazılır.

2 Beğeni

Ne demek istediğinizi anladım sanırım. Yani sınıf içinde yazdığım fonksiyonlar kendi lokal alanlarına ve globale baktığı için sınıf içindeki niteliği görmüyor. Ama ek işlemler yaparak görmesini sağlayabiliyoruz. Fonksiyonu anladım da, peki alt sınıf yazdığımda nasıl ana sınıfın niteliğini kullanabilirim? Mesela şöyle:

>>> class AnaSinif():
	a = 5
	class AltSinif():
		b = a + 3

		
Traceback (most recent call last):
  File "<pyshell#72>", line 1, in <module>
    class AnaSinif():
  File "<pyshell#72>", line 3, in AnaSinif
    class AltSinif():
  File "<pyshell#72>", line 4, in AltSinif
    b = a + 3
NameError: name 'a' is not defined

Alışılagelmemiş demek istiyorsan şöyle diyeyim, öğrenme aşamasında aldığın hata gelecekte program yazdığında alacağın hatadan daha çabuk çözülür

Gösterdiğiniz gibi bir şey yapamayız. Zaten böyle bir duruma ihtiyaç duyacağınızı pek sanmıyorum. Sınıfın içinde sınıf tanımlarken alt sınıf, dışarıdaki sınıfa hizmet etsin diye tanımlanır, dışarıdaki sınıf içerideki sınıfa değil. Çünkü alt sınıfı yazarken aslında hala kapsayıcı sınıfın içindesinizdir bu yüzden henüz daha tanımlanmış bir sınıf yoktur ortada. Ayrıca bir sınıfın içerisi de artık local bir alandır.

Genelde sınıf içinde sınıf şu şekilde kullanılır:

>>> class A:
...     a = 5
...     class B:
...             b = 3
...     c = a + B.b

Ki yukarıdaki gibi bir kod yapısına çok fazla ihtiyaç duymazsınız diye tahmin ediyorum.

Anladım. Çok teşekkürler :smiley:

Anladim. Ama gelecekte de alma ihtimalinin zor olacagi, veya olmasi gerektigi bir hata bu, o yuzden sordum. (Fonksiyon disinda kod bulunmasi anti-pattern.)

Ama tabi ki ogrenmenin ve ugrunda sacma kodlar yazmanin karsisinda duracak degilim; tam tersi. Bu baglamda resmi dokumentasyondan bulup cikarttigim kisimlar yardimci olacaktir diye umuyorum. Dokumentasyonun okumasi biraz zor, dil standartlarina benzemiyor.