Yerleşik property
işlevinin nasıl çalıştığını anlamak istiyorum. Kafamı karıştıran şey, property
bir dekoratör olarak da kullanılabilir, ancak yalnızca yerleşik bir işlev olarak kullanıldığında argüman alır ve bir dekoratör olarak kullanıldığında değil.
Bu örnek dokümantasyon'den alınmıştır:
class C(object):
def __init__(self):
self._x = None
def getx(self):
return self._x
def setx(self, value):
self._x = value
def delx(self):
del self._x
x = property(getx, setx, delx, "I'm the 'x' property.")
property
'nin argümanları getx
, setx
, delx
ve bir doc dizesidir.
Aşağıdaki kodda property
dekoratör olarak kullanılmıştır. Bunun nesnesi x
fonksiyonudur, ancak yukarıdaki kodda argümanlarda bir nesne fonksiyonu için yer yoktur.
class C(object):
def __init__(self):
self._x = None
@property
def x(self):
"""I'm the 'x' property."""
return self._x
@x.setter
def x(self, value):
self._x = value
@x.deleter
def x(self):
del self._x
Ve x.setter
ve x.deleter
dekoratörleri nasıl oluşturulur?
Kafam karıştı.
özellik()` işlevi özel bir tanımlayıcı nesne döndürür:
>>> property()
<property object at 0x10ff07940>
Ekstra* yöntemlere sahip olan bu nesnedir:
>>> property().getter
<built-in method getter of property object at 0x10ff07998>
>>> property().setter
<built-in method setter of property object at 0x10ff07940>
>>> property().deleter
<built-in method deleter of property object at 0x10ff07998>
Bunlar da dekoratör görevi görür. Yeni bir özellik nesnesi döndürürler:
>>> property().getter(None)
<property object at 0x10ff079f0>
Bu, eski nesnenin bir kopyasıdır, ancak işlevlerden biri değiştirilmiştir.
Unutmayın, @decorator
sözdizimi sadece sözdizimsel şekerdir; sözdizimi:
@property
def foo(self): return self._foo
ile aynı anlama gelmektedir.
def foo(self): return self._foo
foo = property(foo)
Böylece foo
fonksiyonu, yukarıda özel bir nesne olduğunu gördüğümüz property(foo)
ile değiştirilir. Sonra @foo.setter()
kullandığınızda, yaptığınız şey yukarıda gösterdiğim property().setter
yöntemini çağırmaktır; bu yöntem özelliğin yeni bir kopyasını döndürür, ancak bu kez setter işlevi dekore edilmiş yöntemle değiştirilmiştir.
Aşağıdaki sekans da bu dekoratör yöntemlerini kullanarak tam kapsamlı bir özellik oluşturur.
İlk olarak bazı fonksiyonlar ve sadece bir getter ile bir property
nesnesi oluşturuyoruz:
>>> def getter(self): print('Get!')
...
>>> def setter(self, value): print('Set to {!r}!'.format(value))
...
>>> def deleter(self): print('Delete!')
...
>>> prop = property(getter)
>>> prop.fget is getter
True
>>> prop.fset is None
True
>>> prop.fdel is None
True
Daha sonra bir setter eklemek için .setter()
yöntemini kullanırız:
>>> prop = prop.setter(setter)
>>> prop.fget is getter
True
>>> prop.fset is setter
True
>>> prop.fdel is None
True
Son olarak .deleter()
metodu ile bir silici ekliyoruz:
>>> prop = prop.deleter(deleter)
>>> prop.fget is getter
True
>>> prop.fset is setter
True
>>> prop.fdel is deleter
True
Son olarak, property
nesnesi bir tanımlayıcı nesne gibi davranır, bu nedenle örnek niteliği alma, ayarlama ve silmeye bağlanmak için .__get__()
, .__set__()
ve .__delete__()
yöntemlerine sahiptir:
>>> class Foo: pass
...
>>> prop.__get__(Foo(), Foo)
Get!
>>> prop.__set__(Foo(), 'bar')
Set to 'bar'!
>>> prop.__delete__(Foo())
Delete!
Tanımlayıcı Howto property()
türünün bir saf Python örnek uygulamasını içerir:
class Property: "Objects/descrobject.c" içindeki PyProperty_Type() işlevini taklit edin;
def init(self, fget=None, fset=None, fdel=None, doc=None): self.fget = fget self.fset = fset self.fdel = fdel doc Yok ise ve fget Yok değil ise: doc = fget.doc self.doc = doc
def get(self, obj, objtype=None): eğer nesne None ise: return self self.fget None ise: raise AttributeError("unreadable attribute") return self.fget(obj)
def set(self, obj, value): if self.fset is None: raise AttributeError("can't set attribute") self.fset(nesne, değer)
def delete(self, obj): if self.fdel is None: raise AttributeError("can't delete attribute") self.fdel(obj)
def getter(self, fget): return type(self)(fget, self.fset, self.fdel, self.doc)
def setter(self, fset): return type(self)(self.fget, fset, self.fdel, self.doc)
def deleter(self, fdel): return type(self)(self.fget, self.fset, fdel, self.doc)
Belgeler diyor ki bu sadece salt okunur özellikler oluşturmak için bir kısayoldur. Yani
@property
def x(self):
return self._x
ile eşdeğerdir
def getx(self):
return self._x
x = property(getx)
İlk bölüm basittir:
@property
def x(self): ...
ile aynıdır
def x(self): ...
x = property(x)
property
oluşturmak için basitleştirilmiş sözdizimidir.Bir sonraki adım, bu özelliği bir setter ve bir deleter ile genişletmek olacaktır. Bu da uygun yöntemlerle gerçekleşir:
@x.setter
def x(self, value): ...
eski x
özelliğinden ve verilen ayarlayıcıdan her şeyi miras alan yeni bir özellik döndürür.
x.deleter` da aynı şekilde çalışır.