Python “özelliği” ve “özellik” arasındaki fark nedir?


147

Genelde bir "özellik" ile bir "öznitelik" arasındaki fark konusunda kafam karıştı ve farkları kısaca detaylandırmak için harika bir kaynak bulamıyorum.

Yanıtlar:


184

Özellikler özel bir niteliktir. Temel olarak, Python aşağıdaki kodla karşılaştığında:

spam = SomeObject()
print(spam.eggs)

yukarıyı eggsiçinde spamve sonra inceler eggsbir olup olmadığını görmek için __get__, __set__ya da __delete__yöntemi - eğer olursa, bu bir özelliktir. O takdirde ise bir özellik yerine sadece döndükten sonra eggsnesneyi çağıracağı (başka herhangi bir özelliğe için olduğu gibi) __get__yöntem ve getiri ne olursa olsun bu yöntem döndürür (biz arama yaptıklarını beri).

Python'un veri modeli ve tanımlayıcıları hakkında daha fazla bilgi .


Özelliklerin hedef değere erişmek için ek işleme gerektirdiği anlaşılıyor ... ne kadar önemli / çok daha yavaş olduğunu biliyor musunuz?
martineau

@martineau: Eh, ekstra bir işlev çağrısı var, ancak büyük olasılıkla ekstra çalışma ve zaman, mülkün ne kadar yaptığına bağlı olacaktır (genel tavsiye: G / Ç'yi gizlemek için özellikleri yapma / kullanma / kullanma).
Ethan Furman

56

Bir özellik ile, bir özellik ile (uyarılar kullanmıyorsanız) sahip olmadığınız alıcı, ayarlayıcı ve silme yöntemleri üzerinde tam kontrole sahip olursunuz.

class A(object):
    _x = 0
    '''A._x is an attribute'''

    @property
    def x(self):
        '''
        A.x is a property
        This is the getter method
        '''
        return self._x

    @x.setter
    def x(self, value):
        """
        This is the setter method
        where I can check it's not assigned a value < 0
        """
        if value < 0:
            raise ValueError("Must be >= 0")
        self._x = value

>>> a = A()
>>> a._x = -1
>>> a.x = -1
Traceback (most recent call last):
  File "ex.py", line 15, in <module>
    a.x = -1
  File "ex.py", line 9, in x
    raise ValueError("Must be >= 0")
ValueError: Must be >= 0

Bu ("tam kontrol") "mülk dışı" niteliklerle de yapılabilir, ancak böyle basit dekoratörler olmadan.

8
Bu cevabın gerçekçi ve kullanışlı bir örnek vermesini seviyorum. Bu sitede çok fazla cevabın, kullanıcının onlarla nasıl etkileşime girmesi gerektiğini netleştirmeden işlerin arka uçta nasıl çalıştığını gereksiz yere açıkladığını hissediyorum. Bazı işlevlerin neden / ne zaman kullanılacağını anlamadıysa, sahne arkasında nasıl çalıştığını bilmenin bir anlamı yoktur.
Tom

Bu cevap "Python Zen'i - Bunu yapmanın bir - ve tercihen sadece bir - açık yolu" olmalı. X değerini ayarlamanın 2 yolu vardır.
Tin Luu

@TinLuu - x değerini ayarlamanın yalnızca bir yolu vardır. _X değerini ayarlamanın yalnızca bir yolu vardır. Aynı şey olmaları bir uygulama detayıdır. Bu sınıfın bilge kullanıcısı _x kullanmaz.
yaktı

1
@TinLuu - Sanırım ikimiz de aynı şeyi perspektifin karşıt uçlarından söylüyoruz. Sınıfın kullanıcısı yalnızca görmelidir x. Tek yön. Sınıfın kullanıcısı _x hakkında bilgi bulursa, riski kendi sorumluluğunda kullanır.
yaktı

19

Genel olarak konuşursak, bir özellik ve nitelik aynı şeydir. Bununla birlikte, Python'da bir özniteliğe (veya diğer verilere) alıcı / ayarlayıcı erişimi sağlayan bir özellik dekoratörü vardır.

class MyObject(object):
    # This is a normal attribute
    foo = 1

    @property
    def bar(self):
        return self.foo

    @bar.setter
    def bar(self, value):
        self.foo = value


obj = MyObject()
assert obj.foo == 1
assert obj.bar == obj.foo
obj.bar = 2
assert obj.foo == 2
assert obj.bar == obj.foo

1
Lütfen bu kodun beklenen sonucundan da bahseder misiniz?
Hasan Iqbal

2
Ne demek istiyorsun? Bu kodun altında değil mi?
six8

12

Özellik, normal nitelikler gibi değerler almanıza ve ayarlamanıza izin verir, ancak altında sizin için bir alıcıya ve ayarlayıcıya çeviri olarak adlandırılan bir yöntem vardır. Arayanların ve ayarlayıcıların ortak plakasını kesmek gerçekten kolaylık.

Diyelim ki, ihtiyacınız olan bir şey için bazı x ve y koordinatlarına sahip bir sınıfınız var. Bunları ayarlamak için aşağıdaki gibi bir şey yapmak isteyebilirsiniz:

myObj.x = 5
myObj.y = 10

Bakmak ve düşünmek yazmaktan çok daha kolay:

myObj.setX(5)
myObj.setY(10)

Sorun şu ki, eğer bir gün sınıfınız x ve y değerlerinizi bir değerle dengelemeniz gerekecek şekilde değişirse? Şimdi girmeniz ve sınıf tanımınızı ve onu çağıran tüm kodu değiştirmeniz gerekir, bu gerçekten zaman alıcı ve hataya eğilimli olabilir. Özellik, önceki sözdizimini kullanmanıza izin verirken, ikincisini değiştirme esnekliği sağlar.

Python'da, özellik işleviyle alıcıları, ayarlayıcıları ve silme yöntemlerini tanımlayabilirsiniz. Sadece read özelliğini istiyorsanız, yönteminizin üzerine ekleyebileceğiniz bir @property dekoratör de vardır.

http://docs.python.org/library/functions.html#property


Sadece pratik mantıklı cevap!
Dostum156

8

Bernd Klein sitesinden 2 fark öğrendim :

1. Mülkiyet, veri kapsülleme yapmak için daha uygun bir yoldur.

ör .: Nesnenin genel bir öznitelik uzunluğunuz varsa, daha sonra projeniz onu kapsüllemenizi gerektirir, yani: özel olarak değiştirin ve getter ve setter => sağlayın => daha önce yazdığınız kodların çoğunu değiştirmeniz gerekir:

#Old codes
obj1.length=obj1.length+obj2.length
#New codes(Using private attibutes and getter and setter)
obj1.set_lenght(obj1.get_length()+obj2.get_length()) #=> this is ugly

@Property ve @ lenght.setter => kullanıyorsanız, bu eski kodları değiştirmeniz gerekmez

2. Bir özellik birden çok özelliği kapsayabilir

class Person:
  def __init__(self, name, physic_health, mental_health):
    self.name=name
    self.__physic_health=physic_health #physic_health is real value in range [0, 5.0]
    self.__mental_health=mental_health #mental_health is real value in range [0, 5.0]
  @property
  def condition(self):
    health=self.__physic_health+self.__mental_health
    if(health<5.0):
      return "I feel bad!"
    elif health<8.0:
      return "I am ok!"
    else:
      return "Great!"

Bu örnekte __physic_healthve __mental_healthözeldir ve doğrudan dışarıdan erişilemez, sınıfın dışında onlarla etkileşim kurmanın tek yolu throught mülkiyetidir.condition


8

Ayrıca verileri önbelleğe almak veya yenilemek için kullandığım belirgin bir fark yok, genellikle sınıf özniteliğine bağlı bir fonksiyonumuz var. Örneğin ben bir kez dosyayı okumak ve değer önbelleğe alınır böylece özniteliğe atanan içeriği tutmak gerekir:

class Misc():
        def __init__(self):
            self.test = self.test_func()

        def test_func(self):
            print 'func running'
            return 'func value'

cl = Misc()
print cl.test
print cl.test

Çıktı:

func running
func value
func value

Özniteliğe iki kez eriştik ancak işlevimiz yalnızca bir kez tetiklendi. Özellik kullanmak için yukarıdaki örneğin değiştirilmesi, her eriştiğinizde özniteliğin değer yenilemesine neden olur:

class Misc():

    @property
    def test(self):
        print 'func running'
        return 'func value'

cl = Misc()
print cl.test
print cl.test

Çıktı:

func running
func value
func running
func value
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.