[python] Statické metody v Pythonu
Petr Prikryl
PrikrylP na skil.cz
Středa Listopad 8 15:28:49 CET 2006
Díval jsem se na to znovu a beru zpět to,
že si myslím, že tohle využití vypadá zajímavě.
superman
> [...]Protože v předkovi uhel se počítá s tím, že v metodě
> __add__ se přes self předává jen jeden argument, najednou
> si v potomku začne stěžovat na dva. Python má v tomhle
> asi nepořádek a asi nesnáší takové šťoury jako jsem já.
> Takže závěr nikdy nezkoušejte předefinovat statickou
> metodu nestatickou, protože Python si s tím neví
> rady a začne hlásit chyby i tam, kde by to v jiných
> jazycích bylo v pořádku. Never is perfect :-)))
> [myšleno asi Nobody is perfect -- Někdo to rád horké]
> class uhel:
>
> @staticmethod
> def static(a):
> print "trida1.static(): ", a
>
> def method(self):
> self.static(1)
>
> class zemepisny_uhel(uhel):
>
> #@staticmethod
> def static(a):
> print "trida2.static(): ", a
>
> a = uhel()
> a.method()
>
> b = zemepisny_uhel()
> b.method()
>
> trida1.static(): 1
> Traceback (most recent call last):
> File "C:\home\astrol\test.py", line 25, in ?
> b.method()
> File "C:\home\astrol\test.py", line 10, in method
> self.static(1)
> TypeError: static() takes exactly 1 argument (2 given)
>
> Závěr: Python se chová tak, jako kdyby definici třídy znovu
> překládal do definice potomka. Zápis self.static přeloží
> v uhel.method jako volání statické metody s jedním parametrem,
> zatímco v zemepisny_uhel jako volání normální metody se dvěma
> parametry. Řekl bych, že tato feature je dost error prone,
> a že vlastnost "zapouzdření" dostává pěkně na zadek.
Já na tom nevidím nic divného. V části
> class zemepisny_uhel(uhel):
> #@staticmethod
> def static(a):
> print "trida2.static(): ", a
je dekorátor zapoznámkovaný, takže je to stejné, jako kdybych
napsal
class zemepisny_uhel(uhel):
def static(a):
print "trida2.static(): ", a
Což je stejné jako
class zemepisny_uhel(uhel):
def static(self):
print "trida2.static(): ", self
Jenom jsi porušil konvenci, že první argument metody se má
pojmenovat self. No a druhý argument tam není. Myslím,
že interpret Pythonu v tom docela jasno MÁ ;o)
A ještě k tomu použití statické metody. Možná máš znalosti
C++, kde se zápis typu
zem_uhel + "30N54"
typicky dosahuje přetížením operátoru + a typicky se
implementuje tak, že se na místě druhého argumentu očekává
konstantní reference a třídu zemepisny_uhel. Jenže
u třídy zemepisny_uhel by se v takovém případě typicky
definoval konstruktor, který bere odkaz na konstantní string
a může se tam tedy dosadit i literál. Překladač pak automaticky
udělá tohle:
zem_uhel + zemepisny_uhel("30N54")
tj. nejdříve zkonstruuje pomocný objekt pro druhý argument.
Dále se to dá rozepsat jako
zem_uhel.operator+(zemepisny_uhel(("30N54")))
Python ale implicitně podobný konstruktor nezavolá. Podle
mého by tedy měla být třída uhel vytvořena tak, aby její
složka __radians jednoduše obsahovala platnou hodnotu, nebo
by se měla definovat metoda, která hodnotu v radiánech
vrací. Metoda __add__ by jako argument měla brát instanci
třídy uhel a udělat jednoduše
class uhel:
def __init__(self, radian):
self.__rad = radian
def __add__(self, u):
return self.__rad + u.__rad
def __str__(self):
return str(self.__rad)
u1 = uhel(1.0)
u2 = uhel(2.0)
print u1
print u2
u3 = u1 + u2
u4 = u1 + uhel(3.0)
print u3
print u4
Třída zemepisny_uhel by byla odvozená v tom smyslu,
že by měla jinou implementaci __init__(), ve které
by se mohly rozpoznávat různé formy předaného argumentu.
Pak by to mohlo vypadat takhle:
class uhel:
def __init__(self, radian):
self.__rad = radian
def __add__(self, u):
return self.__rad + u.__rad
def __str__(self):
return str(self.__rad)
class zemepisny_uhel(uhel):
def __init__(self, s):
uhel.__init__(self, float(s))
u1 = uhel(1.0)
u2 = uhel(2.0)
print u1
print u2
u3 = u1 + u2
u4 = u1 + uhel(3.0)
print u3
print u4
z = zemepisny_uhel('4.0')
print z
print u1 + z
print z + u2
Uplatnění pro statické metody jsem v tom příkladu
zatím nenašel.
Poznámka: kromě staticmethod() a příslušného
dekorátoru existuje i classmethod(), ke které
jsme se zatím nedostali.
pepr
Další informace o konferenci Python