clsss myClass():
def __init__(self, a, b):
self.a = a
self.b = b
return
my = Class()
my.a =1
my.b=2
czysyt ładny kod, dojście jest a jeżeli chcemy to zakapsułkować to
zawsz możemy zmienne ustawić na
self.__a będzie to zmienna praywatna której nie zmodyfikujemy
z dyskryptorami będzie to wyglądało tak
class myClass(object):
def __init__(self, self, a, b):
self.a = a
self.b = b
def __get__(self, obj, objtype):
return self.a
def __set__(self, obj, val):
self.a = a
2 klasa nie wiem czy dobrze napisana bo nie rozumiem tego ale to koło
tego ma wyglądać.
Tak czy inaczej więcej pisania, zagmatwane, moim skromnym zdaniem nie
bardzo czytelne,
wytłumaczcie mi co w tym takiego dobrego iż jest to wprowadzane do
każdego języka programowania.
> class myClass(object):
> def __init__(self, self, a, b):
> self.a = a
> self.b = b
>
> def __get__(self, obj, objtype):
> return self.a
>
> def __set__(self, obj, val):
> self.a = a
>
> 2 klasa nie wiem czy dobrze napisana bo nie rozumiem tego ale to koło
> tego ma wyglądać.
> Tak czy inaczej więcej pisania, zagmatwane, moim skromnym zdaniem nie
> bardzo czytelne,
> wytłumaczcie mi co w tym takiego dobrego iż jest to wprowadzane do
> każdego języka programowania.
Nikt Ci nie każe używać __get__/__set__, możesz przypisywać/pobierać
wartości bez nich. Jeśli chcesz jednak np. dodać sprawdzanie typu (z rzucaniem
stosownego wyjątku), te metody pozwalają Ci na zrobienie tego niejawnie.
W ten sposób klasa sama się zatroszczy o siebie, a Ty nie będziesz musiał
używać javowych potworków typu:
obj.setA(value)
Oczywiście można je wykorzystać także do innych zabaw. Co Ci tylko
przyjdzie na myśl. Masz mechanizm, który *możesz* wykorzystać, ale
*nie musisz*.
Pozdrawiam
Beorn
--
Daniel 'Beorn' Mróz <be...@alpha.pl> http://127.0.0.1/beorn
[GIT d s:- a-@ C++++ UL++++$ P+ L++++ E--- W+ N+++ o? K- w---]
[O- M- V! PS+ PE++ Y+ PGP++ t- 5 X R !tv b+ DI D++ G++ e h*]
[ r++ y+ ]
Wszystkie te cztery problemy załatwiają metody __get__() i __set__().
Przy nadawaniu i odczycie wartości mogą dokonywać automatycznej
transformacji z/na wartość liczbową (jeśli potrzeba), pilnować żeby
zakres nie był odwrócony i dostarczać "wirtualnych" atrybutów znakowych,
których wartość będzie generowana w locie.
Dwie małe metody, masa problemów z głowy.
Jeśli chcesz nauczyć się używania deskryptorów to polecam:
http://users.rcn.com/python/download/Descriptor.htm
A ty przykład:
# tak dla uproszczenia
addr2int = int
int2addr = str
class IpFieldDescriptor(object):
""" klasa deskryptora """
def __init__(self, int_field_name):
self.int_field_name = int_field_name
def __get__(self, obj, cls):
""" konwersja ze string do int """
assert obj is not None,'access only from instance!'
ip_int = getattr(obj, self.int_field_name, None)
if ip_int is not None:
return int2addr(ip_int)
def __set__(self, obj, value):
""" konwersja z int do string """
assert obj is not None,'access only from instance!'
ip_int = addr2int(value)
setattr(obj, self.int_field_name, ip_int)
class IpRange(object):
""" wlasciwa klasa """
start = IpFieldDescriptor('_start_int')
stop = IpFieldDescriptor('_stop_int')
def __init__(self, start, stop):
self.start = start
self.stop = stop
if __name__ == '__main__':
iprange = IpRange('9', '13')
# konstruktor
print iprange.start, type(iprange.start)
print iprange._start_int, type(iprange._start_int)
print iprange.stop, type(iprange.stop)
print iprange._stop_int, type(iprange._stop_int)
# ustawianie
iprange.start = '14'
iprange.stop = '20'
print iprange.start, type(iprange.start)
print iprange._start_int, type(iprange._start_int)
print iprange.stop, type(iprange.stop)
print iprange._stop_int, type(iprange._stop_int)
ps. co to są "dyskryptory" ? czy to się tak tłumaczy na nasz język ?
--
sacre
> Witam,
> zabieram si� za temat dyskryptor�w po raz ......no du�o tego by�o ale
> tym razem powiedzia�em sobie �e nie odpuszcze bo nie rozumiem ca�ego
> stanu rzeczy z dyskryptorami po co je wymy�lili doj�cie do sk�adowych
> klasy w pythonnie mo�emy uzyska� w bardzo prosyt spos�b prawda
>
> clsss myClass():
> def __init__(self, a, b):
> self.a = a
> self.b = b
> return
>
> my = Class()
> my.a =1
> my.b=2
>
> czysyt �adny kod, doj�cie jest a je�eli chcemy to zakapsu�kowa� to
> zawsz mo�emy zmienne ustawi� na
> self.__a b�dzie to zmienna praywatna kt�rej nie zmodyfikujemy
> z dyskryptorami b�dzie to wygl�da�o tak
>
> class myClass(object):
> def __init__(self, self, a, b):
> self.a = a
> self.b = b
>
> def __get__(self, obj, objtype):
> return self.a
>
> def __set__(self, obj, val):
> self.a = a
>
> 2 klasa nie wiem czy dobrze napisana bo nie rozumiem tego ale to ko�o
> tego ma wygl�da�.
> Tak czy inaczej wi�cej pisania, zagmatwane, moim skromnym zdaniem nie
> bardzo czytelne,
> wyt�umaczcie mi co w tym takiego dobrego i� jest to wprowadzane do
> ka�dego j�zyka programowania.
Zapewne znana Ci jest funkcja "property":
http://docs.python.org/library/functions.html?highlight=property#property
Czy masz jakie� w�tpliwo�ci, �e jest u�yteczna (szczeg�lnie
w kontek�cie wszechobecnych setter�w i getter�w)?
"Property" tworzy w�a�nie deskryptor, kt�ry wygl�da tak:
class property(object):
def __init__(self, fget=None, fset=None, fdel=None, doc=None):
if doc is None and fget is not None and hasattr(fget, "__doc__"):
doc = fget.__doc__
self.__get = fget
self.__set = fset
self.__del = fdel
self.__doc__ = doc
def __get__(self, inst, type=None):
if inst is None:
return self
if self.__get is None:
raise AttributeError, "unreadable attribute"
return self.__get(inst)
def __set__(self, inst, value):
if self.__set is None:
raise AttributeError, "can't set attribute"
return self.__set(inst, value)
def __delete__(self, inst):
if self.__del is None:
raise AttributeError, "can't delete attribute"
return self.__del(inst)
RW
Powiedzcie mi jeszcze jaka jest różnica między funkcjami
object.__getattr__(self, name) a def __get__(self, obj, cls):
object.__setattr__(self, name, value) a def __set__(self, obj, value):
czytając http://docs.python.org/reference/datamodel.html jakoś nie
bardzo pojąłem wielkość różnicy tych funkcji.
ps. deskryptory :-)
Pozdrawiam
On 28 Lis, 16:57, Daniel Mróz <be...@alpha.pl> wrote:
> On 28.11.2009, sacre <sacre...@wp.pl> wrote:> assert obj is not None,'access only from instance!'
To z grubsza znaczy, że wszelkie wyrażenia `assert` zostaną usunięte w
procesie optymalizacji:
$ python -c "assert 1==2"
Traceback (most recent call last):
File "<string>", line 1, in <module>
AssertionError
$ python -Oc "assert 1==2" # cicho
?
> Tak ten przyk�ad podoba mi sie i pokazuje s�uszno�� stosowania __set__
> i __get__, aczkolwiek w "starym stylu klas" mo�na to te� �adnie
> napisaďż˝.
>
> Powiedzcie mi jeszcze jaka jest r�nica mi�dzy funkcjami
> object.__getattr__(self, name) a def __get__(self, obj, cls):
> object.__setattr__(self, name, value) a def __set__(self, obj, value):
>
> czytaj�c http://docs.python.org/reference/datamodel.html jako� nie
> bardzo poj��em wielko�� r�nicy tych funkcji.
Je�li masz ambicj� zrozumienia deskryptor�w, to musisz przeczyta� opis
(najlepszy w sieci, napisany przez tw�rc� tej koncepcji),
do kt�rego link ju� Ci zosta� podany:
http://users.rcn.com/python/download/Descriptor.htm
Gdy tam zajrzysz, to znajdziesz kluczowďż˝ definicjďż˝ dla zrozumienia
tego mechanizmu:
def __getattribute__(self, key):
"Emulate type_getattro() in Objects/typeobject.c"
v = object.__getattribute__(self, key)
if hasattr(v, '__get__'):
return v.__get__(None, self)
return v
Kluczowa zasada to kolejno�� wywo�a�:
1. __getattribute__ jest wo�ana zawsze jako pierwsza
2. __get__ jest wo�ana tylko dla atrybut�w, kt�re maj�
zdefiniowanďż˝ takďż˝ metodďż˝, czyli sďż˝ deskryptorami
3. __getattr__ jest wo�ana zawsze jako ostatnia
i tylko wtedy, gdy powy�szy mechanizm nie by� w stanie
odnale�� sk�adowej
Czyli gdy mamy zdefiniowanďż˝ tylko `__getattribute__`,
to wo�ana jest zawsze:
class A(object):
def __init__(self):
self.x = 99
def __getattribute__(self, name):
print '__getattribute__: %r' % name
v = object.__getattribute__(self, name)
if hasattr(v, '__get__'):
return v.__get__(None, self)
return v
>>> a = A()
>>> a.x
__getattribute__: 'x'
99
>>> a.y
__getattribute__: 'y'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/tmp/python-4766uIx.py", line 7, in __getattribute__
AttributeError: 'A' object has no attribute 'y'
Gdy mamy zdefiniowan� `__getattr__`, to wo�ana jest tylko
przy odwo�aniu do *niezdefiniowanej* sk�adowej:
class B(object):
def __init__(self):
self.x = 99
def __getattr__(self, name):
print '__getattr__: %r' % name
if name == 'y':
return self.x * 10 # odwolanie do self.x nie powoduje zapetlenia
raise AttributeError('%r object has no attribute %r'
% (self.__class__.__name__, name))
>>> b = B()
>>> b.x
99
>>> b.y
__getattr__: 'y'
990
>>> b.z
__getattr__: 'z'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/tmp/python-4766gSA.py", line 10, in __getattr__
AttributeError: 'B' object has no attribute 'z'
Gdy mamy zdefiniowane zar�wno `__getattribute__` jak i `__getattr__`,
to wywo�ywane s� w z g�ry przyj�tej kolejno�ci, czyli na pocz�tku
`__getattribute__`, a na ko�cu `__getattr__` (gdy jest odwo�anie
do *niezdefiniowanej* sk�adowej):
class C(object):
def __init__(self):
self.x = 99
def __getattribute__(self, name):
print '__getattribute__: %r' % name
v = object.__getattribute__(self, name)
if hasattr(v, '__get__'):
return v.__get__(None, self)
return v
def __getattr__(self, name):
print '__getattr__: %r' % name
if name == 'y':
return self.x * 10 # odwolanie do self.x nie powoduje zapetlenia
raise AttributeError('%r object has no attribute %r'
% (self.__class__.__name__, name))
>>> c = C()
>>> c.x
__getattribute__: 'x'
99
>>> c.y
__getattribute__: 'y'
__getattr__: 'y'
__getattribute__: 'x'
990
>>> c.z
__getattribute__: 'z'
__getattr__: 'z'
__getattribute__: '__class__'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/tmp/python-4766tcG.py", line 17, in __getattr__
AttributeError: 'C' object has no attribute 'z'
I teraz, gdy do tej klasy dorzucimy definicjďż˝ `__get__`, to co siďż˝ stanie?
Mogďż˝ siďż˝ dziaďż˝ dziwne rzeczy, gdyďż˝ `__get__` w takim przypadku nie ma
najmniejszego sensu:
class D(object):
def __init__(self):
self.x = 99
def __getattribute__(self, name):
print '__getattribute__: %r' % name
v = object.__getattribute__(self, name)
if hasattr(v, '__get__'):
return v.__get__(None, self)
return v
def __get__(self, instance, owner):
print '__get__: %r' % owner
return self.x
def __getattr__(self, name):
print '__getattr__: %r' % name
if name == 'y':
return self.x * 10 # odwolanie do self.x nie powoduje zapetlenia
raise AttributeError('%r object has no attribute %r'
% (self.__class__.__name__, name))
>>> d = D()
>>> d.x
__getattribute__: 'x'
99
>>> d.y
__getattribute__: 'y'
__getattr__: 'y'
__getattribute__: 'x'
990
>>> d.z
__getattribute__: 'z'
__getattr__: 'z'
__getattribute__: '__class__'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/tmp/python-4766U7Y.py", line 21, in __getattr__
File "/tmp/python-4766U7Y.py", line 9, in __getattribute__
TypeError: unbound method __get__() must be called with D instance as first argument (got NoneType instance instead)
Zgodnie z dokumentacjďż˝ [1]_ ma sens tylko dla:
"""
The following methods (przyp. tlum. __get__, __set__, __delete__) only
apply when an instance of the class containing the method
(a so-called descriptor class) appears in the class dictionary of
another new-style class, known as the owner class.
"""
czyli po naszemu:
"""
Metody __get__, __set__ i __delete__ majďż˝ zastosowanie wtedy i tylko wtedy,
gdy instancja klasy zawieraj�ca te metody (tzw. deskryptor) stanowi sk�adow�
innej klasy nowego stylu.
"""
W zwi�zku z tym deskryptor ma sens w takim przypadku jak ten, gdzie mamy
oddzieln� klas� definiuj�c� sk�adow� i jak�� klas� zawierj�c�
t� sk�adow�:
class E(object):
def __init__(self, val):
self.val = val
def __get__(self, instance, owner):
print '__get__: %r' % owner.__class__.__name__
return self.val
class F(object):
def __init__(self):
self.x = E(99)
def __getattribute__(self, name):
print '__getattribute__: %r' % name
v = object.__getattribute__(self, name)
if hasattr(v, '__get__'):
return v.__get__(None, self)
return v
def __getattr__(self, name):
print '__getattr__: %r' % name
if name == 'y':
return self.x * 10 # odwolanie do self.x nie powoduje zapetlenia
raise AttributeError('%r object has no attribute %r'
% (self.__class__.__name__, name))
>>> f = F()
>>> f.x
__getattribute__: 'x'
__getattribute__: '__class__'
__get__: 'F'
99
>>> f.y
__getattribute__: 'y'
__getattr__: 'y'
__getattribute__: 'x'
__getattribute__: '__class__'
__get__: 'F'
990
>>> f.z
__getattribute__: 'z'
__getattr__: 'z'
__getattribute__: '__class__'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/tmp/python-4766uPl.py", line 26, in __getattr__
AttributeError: 'F' object has no attribute 'z'
A teraz po�wicz ten temat tak z tydzie� w r�nych wariantach
i jest pewna szansa, �e co� si� zacznie klarowa�. ;)
.. [1] http://docs.python.org/reference/datamodel.html?highlight=__getattr__#object.__getattribute__
RW
On 29 Lis, 12:52, Rob Wolfe <r...@smsnet.pl> wrote:
> ak3031884 <ak3031...@gmail.com> writes:
> > Tak ten przykład podoba mi sie i pokazuje słuszność stosowania __set__
> > i __get__, aczkolwiek w "starym stylu klas" można to też ładnie
> > napisać.
>
> > Powiedzcie mi jeszcze jaka jest różnica między funkcjami
> > object.__getattr__(self, name) a def __get__(self, obj, cls):
> > object.__setattr__(self, name, value) a def __set__(self, obj, value):
>
> > czytająchttp://docs.python.org/reference/datamodel.htmljakoś nie
> > bardzo pojąłem wielkość różnicy tych funkcji.
>
> Jeśli masz ambicję zrozumienia deskryptorów, to musisz przeczytać opis
> (najlepszy w sieci, napisany przez twórcę tej koncepcji),
> do którego link już Ci został podany:http://users.rcn.com/python/download/Descriptor.htm
>
> Gdy tam zajrzysz, to znajdziesz kluczową definicję dla zrozumienia
> tego mechanizmu:
>
> def __getattribute__(self, key):
> "Emulate type_getattro() in Objects/typeobject.c"
> v = object.__getattribute__(self, key)
> if hasattr(v, '__get__'):
> return v.__get__(None, self)
> return v
>
> Kluczowa zasada to kolejność wywołań:
> 1. __getattribute__ jest wołana zawsze jako pierwsza
> 2. __get__ jest wołana tylko dla atrybutów, które mają
> zdefiniowaną taką metodę, czyli są deskryptorami
> 3. __getattr__ jest wołana zawsze jako ostatnia
> i tylko wtedy, gdy powyższy mechanizm nie był w stanie
> odnaleźć składowej
>
> Czyli gdy mamy zdefiniowaną tylko `__getattribute__`,
> to wołana jest zawsze:
>
> class A(object):
> def __init__(self):
> self.x = 99
>
> def __getattribute__(self, name):
> print '__getattribute__: %r' % name
> v = object.__getattribute__(self, name)
> if hasattr(v, '__get__'):
> return v.__get__(None, self)
> return v
>
> >>> a = A()
> >>> a.x
>
> __getattribute__: 'x'
> 99>>> a.y
>
> __getattribute__: 'y'
> Traceback (most recent call last):
> File "<stdin>", line 1, in <module>
> File "/tmp/python-4766uIx.py", line 7, in __getattribute__
> AttributeError: 'A' object has no attribute 'y'
>
> Gdy mamy zdefiniowaną `__getattr__`, to wołana jest tylko
> przy odwołaniu do *niezdefiniowanej* składowej:
>
> class B(object):
> def __init__(self):
> self.x = 99
>
> def __getattr__(self, name):
> print '__getattr__: %r' % name
> if name == 'y':
> return self.x * 10 # odwolanie do self.x nie powoduje zapetlenia
> raise AttributeError('%r object has no attribute %r'
> % (self.__class__.__name__, name))
>
> >>> b = B()
> >>> b.x
> 99
> >>> b.y
>
> __getattr__: 'y'
> 990>>> b.z
>
> __getattr__: 'z'
> Traceback (most recent call last):
> File "<stdin>", line 1, in <module>
> File "/tmp/python-4766gSA.py", line 10, in __getattr__
> AttributeError: 'B' object has no attribute 'z'
>
> Gdy mamy zdefiniowane zarówno `__getattribute__` jak i `__getattr__`,
> to wywoływane są w z góry przyjętej kolejności, czyli na początku
> `__getattribute__`, a na końcu `__getattr__` (gdy jest odwołanie
> do *niezdefiniowanej* składowej):
> I teraz, gdy do tej klasy dorzucimy definicję `__get__`, to co się stanie?
> Mogą się dziać dziwne rzeczy, gdyż `__get__` w takim przypadku nie ma
> Zgodnie z dokumentacją [1]_ ma sens tylko dla:
> """
> The following methods (przyp. tlum. __get__, __set__, __delete__) only
> apply when an instance of the class containing the method
> (a so-called descriptor class) appears in the class dictionary of
> another new-style class, known as the owner class.
> """
>
> czyli po naszemu:
>
> """
> Metody __get__, __set__ i __delete__ mają zastosowanie wtedy i tylko wtedy,
> gdy instancja klasy zawierająca te metody (tzw. deskryptor) stanowi składową
> innej klasy nowego stylu.
> """
>
> W związku z tym deskryptor ma sens w takim przypadku jak ten, gdzie mamy
> oddzielną klasę definiującą składową i jakąś klasę zawierjącą
> tę składową:
> A teraz poćwicz ten temat tak z tydzień w różnych wariantach
> i jest pewna szansa, że coś się zacznie klarować. ;)
>
> .. [1]http://docs.python.org/reference/datamodel.html?highlight=__getattr__...
>
> RW