Menu
Coddy logo textTech

Gizli Öznitelikler

Coddy'nin Python Journey'sinin Object Oriented Programming bölümünün bir parçası — ders 15 / 64.

Özel öznitelikler, belirli verilere sınıf dışından doğrudan erişilmemesi gerektiğini belirtmek için alt çizgiler kullanır.

Neden özel özniteliklere ihtiyacımız var? Bir banka hesabınız olduğunu hayal edin. Kimsenin bakiyenizi doğrudan değiştirmesini istemezsiniz; bankanın işlemi doğrulayabilmesi, dolandırıcılık kontrolü yapabilmesi, kayıt tutabilmesi vb. için uygun kanallardan (para yatırma/çekme metotları) geçmeleri gerekir. Özel öznitelikler de aynı şekilde çalışır; verilerinizin yanlış bir şekilde değiştirilmesini önlerler.

İşte tek alt çizgi ("dahili kullanım" geleneği) kullanan bir örnek:

class Person:
    def __init__(self, name, age):
        self._name = name    # "korumalı" - dahili kullanım
        self._age = age      # "korumalı" - dahili kullanım

Tek alt çizgili özniteliklere hala erişilebilir, ancak bu erişilmemesi gerektiğine dair bir işarettir:

person = Person("Alice", 30)
print(person._name)  # Çalışır, ancak önerilmez

Daha güçlü gizlilik (ad karıştırma - name mangling) için çift alt çizgi kullanın:

class Person:
    def __init__(self, name, age):
        self.__name = name   # "private" - ad karıştırmaya (name mangling) uğrar
        self.__age = age     # "private" - ad karıştırmaya (name mangling) uğrar
    
    def get_name(self):
        return self.__name
    
    def set_age(self, age):
        if age >= 0:
            self.__age = age
        else:
            print("Age must be positive!")

Neden getter ve setter metotları kullanılır? Bunlar kapı bekçileri gibidir. Herhangi birinin __age değerini doğrudan değiştirmesine izin vermek yerine (ki bu negatif yaşlara veya diğer geçersiz verilere neden olabilir), onları önce girişi doğrulayan set_age() metodunu kullanmaya zorlarız. Bu, hataları önler ve veri bütünlüğünü sağlar.

"Ekstra kodun" bir amacı vardır:

  • get_name() - İsmi okumak için kontrollü erişim
  • set_age(age) - Değişikliklere izin vermeden önce yaşı doğrular (negatif yaş yok!)
  • Bu metotlar olmadan, birisi age = -100 olarak ayarlayabilir ve programınızı bozabilir

Özel (private) özniteliklerle etkileşim kurmak için erişimci (accessor) yöntemlerini kullanın:

person = Person("Bob", 25)
print(person.get_name())  # Bob

person.set_age(30)        # Geçerli: yaş 30 olur
person.set_age(-5)        # Geçersiz: Yaş pozitif olmalıdır! (yaş 30 kalır)

Avantajı görüyor musunuz? set_age() yöntemi geçersiz verileri engeller. O olmasaydı, yanlışlıkla yaşı -5 olan bir kişi oluşturabilirdiniz, ki bu hiç mantıklı değil!

Çift alt çizgi öznitelikleri "ad karıştırma" (name mangling) işlemine uğrar ancak yine de bunlara erişilebilir:

person = Person("Charlie", 35)
# Bu çalışmaz:
# print(person.__name)  # AttributeError

# Ancak bu çalışır (önerilmez):
print(person._Person__name)  # Charlie

Gerçek dünya örneği - Neden tüm bu kodlar?

class BankAccount:
    def __init__(self, balance):
        self.__balance = balance  # Gizli: doğrudan değiştirilemez
    
    def deposit(self, amount):
        if amount > 0:
            self.__balance += amount
            return True
        return False
    
    def get_balance(self):
        return self.__balance

# Gizli öznitelikler olmadan:
# account.__balance = -1000000  # Felaket! Negatif bakiyeye izin verildi

# Gizli özniteliklerle:
account = BankAccount(100)
account.deposit(50)           # Güvenli: doğrulandı
print(account.get_balance())  # 150

"Ekstra kod" (metotlar) verilerinizi geçersiz değişikliklerden korur. Bu, değerli eşyalarınızı korumasız bırakmak yerine güvenlik görevlilerine sahip olmak gibidir.

Çıktı:

Alice
Bob
Age must be positive!
Charlie
150

Tek alt çizgi _attribute geleneksel olarak "yalnızca dahili kullanım" anlamına gelir. Çift alt çizgi __attribute daha güçlü gizlilik için ad karıştırmayı (name mangling) tetikler. Özel verilerle düzgün bir şekilde etkileşime girmek ve doğrulama eklemek için getter/setter metotlarını (erişimci metotlar) kullanın. "Ekstra kod", verilerin her zaman geçerli olmasını sağlayarak hataları önler.

challenge icon

Görev

Kolay

user.py dosyasındaki User sınıfını özel parola işlevselliği ile tamamlayın, ardından bunu driver.py dosyasında kullanın. Parola kontrol etme ve değiştirme metotlarını uygulamak için TODO yorumlarını takip edin.

Kopya kağıdı

Özel (private) öznitelikler, verilere sınıf dışından doğrudan erişilmemesi gerektiğini belirtmek için alt çizgi kullanır.

Tek alt çizgi (_attribute) - "dahili kullanım" için bir kuraldır:

class Person:
    def __init__(self, name, age):
        self._name = name    # "protected" - dahili kullanım
        self._age = age      # "protected" - dahili kullanım

Çift alt çizgi (__attribute) - daha güçlü gizlilik için isim karıştırmayı (name mangling) tetikler:

class Person:
    def __init__(self, name, age):
        self.__name = name   # "private" - isim karıştırmaya uğrar
        self.__age = age     # "private" - isim karıştırmaya uğrar
    
    def get_name(self):
        return self.__name
    
    def set_age(self, age):
        if age >= 0:
            self.__age = age
        else:
            print("Age must be positive!")

Özel özniteliklerle etkileşim kurmak için erişimci (accessor) yöntemlerini kullanın:

person = Person("Bob", 25)
print(person.get_name())  # Bob
person.set_age(30)
person.set_age(-5)        # Age must be positive!

Çift alt çizgili öznitelikler isim karıştırmaya uğrar ancak yine de erişilebilirler (önerilmez):

# Bu çalışmaz:
# print(person.__name)  # AttributeError

# Ancak bu çalışır (önerilmez):
print(person._Person__name)  # Charlie

Kendin dene

# YAPILACAK: user modülünden User sınıfını içe aktarın

# YAPILACAK: Girdiden test durumunu alın
test_case = input()

if test_case == "constructor_test":
    # YAPILACAK: "secure123" başlangıç şifresiyle bir User nesnesi oluşturun
    user = User("secure123")
    print("User created successfully")
    print("Initial password set")

elif test_case == "correct_password_test":
    # YAPILACAK: "secure123" başlangıç şifresiyle bir User nesnesi oluşturun
    user = User("secure123")
    # YAPILACAK: check_password metodunu doğru şifre ile test edin
    #           Eğer True dönerse "Password check successful!" yazdırın
    #           Eğer False dönerse "Password check failed!" yazdırın
    result = user.check_password("secure123")
    if result:
        print("Password check successful!")
    else:
        print("Password check failed!")

elif test_case == "incorrect_password_test":
    # YAPILACAK: "secure123" başlangıç şifresiyle bir User nesnesi oluşturun
    user = User("secure123")
    # YAPILACAK: check_password metodunu yanlış şifre "wrong" ile test edin
    #           Eğer False dönerse "Incorrect password rejected!" yazdırın
    #           Eğer True dönerse "Security issue: incorrect password accepted!" yazdırın
    result = user.check_password("wrong")
    if not result:
        print("Incorrect password rejected!")
    else:
        print("Security issue: incorrect password accepted!")

elif test_case == "change_password_test":
    # YAPILACAK: "secure123" başlangıç şifresiyle bir User nesnesi oluşturun
    user = User("secure123")
    # YAPILACAK: Şifreyi "secure123"ten "newpass456"ya değiştirmeyi test edin
    #           Eğer True dönerse "Password changed successfully!" yazdırın
    #           Eğer False dönerse "Password change failed!" yazdırın
    result = user.change_password("secure123", "newpass456")
    if result:
        print("Password changed successfully!")
    else:
        print("Password change failed!")
    
    # YAPILACAK: "newpass456" şifresini kontrol ederek yeni şifrenin çalıştığını doğrulayın
    #           Eğer True dönerse "New password works!" yazdırın
    #           Eğer False dönerse "New password doesn't work!" yazdırın
    if user.check_password("newpass456"):
        print("New password works!")
    else:
        print("New password doesn't work!")

elif test_case == "change_password_wrong_old_test":
    # YAPILACAK: "secure123" başlangıç şifresiyle bir User nesnesi oluşturun
    user = User("secure123")
    # YAPILACAK: Yanlış eski şifre ile şifre değiştirmeyi deneyin
    #           Eğer False dönerse "Security working: incorrect old password rejected!" yazdırın
    #           Eğer True dönerse "Security issue: password changed with wrong old password!" yazdırın
    result = user.change_password("wrong", "hackerpw")
    if not result:
        print("Security working: incorrect old password rejected!")
    else:
        print("Security issue: password changed with wrong old password!")

elif test_case == "comprehensive_test":
    # YAPILACAK: "secure123" başlangıç şifresiyle bir User nesnesi oluşturun
    user = User("secure123")
    print("User created with initial password")
    
    # YAPILACAK: check_password metodunu doğru şifre ile test edin
    if user.check_password("secure123"):
        print("Initial password verification successful")
    
    # YAPILACAK: check_password metodunu yanlış şifre ile test edin
    if not user.check_password("wrongpass"):
        print("Incorrect password properly rejected")
    
    # YAPILACAK: Şifreyi "secure123"ten "newpass456"ya değiştirmeyi test edin
    if user.change_password("secure123", "newpass456"):
        print("Password successfully changed")
    
    # YAPILACAK: Eski şifrenin artık çalışmadığını doğrulayın
    if not user.check_password("secure123"):
        print("Old password no longer works")
    
    # YAPILACAK: Yeni şifrenin çalıştığını doğrulayın
    if user.check_password("newpass456"):
        print("New password works correctly")
    
    # YAPILACAK: Yanlış eski şifre ile şifre değiştirmeyi deneyin
    if not user.change_password("wrongold", "hackerpw"):
        print("Security maintained: wrong old password rejected")
    
    # YAPILACAK: Başarısız değiştirme denemesinden sonra şifrenin hala güvenli olduğunu doğrulayın
    if user.check_password("newpass456"):
        print("Password remains secure after failed change attempt")

else:
    print("Unknown test case")
quiz iconKendini test et

Bu ders kısa bir quiz içerir. Soruları yanıtlamak ve ilerlemeni kaydetmek için derse başla.

Object Oriented Programming bölümündeki tüm dersler