È possibile avere metodi statici in Python che potrei chiamare senza inizializzare una classe, come:
ClassName.static_method()
È possibile avere metodi statici in Python che potrei chiamare senza inizializzare una classe, come:
ClassName.static_method()
Risposte:
Sì, usando il decoratore di metodi statici
class MyClass(object):
@staticmethod
def the_static_method(x):
print(x)
MyClass.the_static_method(2) # outputs 2
Si noti che alcuni codici potrebbero utilizzare il vecchio metodo di definizione di un metodo statico, utilizzando staticmethod
come funzione anziché come decoratore. Questo dovrebbe essere usato solo se devi supportare le versioni antiche di Python (2.2 e 2.3)
class MyClass(object):
def the_static_method(x):
print(x)
the_static_method = staticmethod(the_static_method)
MyClass.the_static_method(2) # outputs 2
Questo è del tutto identico al primo esempio (usando @staticmethod
), semplicemente non usando la bella sintassi del decoratore
Infine, usa staticmethod()
con parsimonia! Ci sono pochissime situazioni in cui i metodi statici sono necessari in Python e li ho visti usati molte volte in cui una funzione separata di "livello superiore" sarebbe stata più chiara.
Quanto segue è letteralmente dalla documentazione :
Un metodo statico non riceve un primo argomento implicito. Per dichiarare un metodo statico, utilizzare questo idioma:
class C: @staticmethod def f(arg1, arg2, ...): ...
Il modulo @staticmethod è un decoratore di funzioni - per i dettagli vedere la descrizione delle definizioni delle funzioni nelle Definizioni delle funzioni .
Può essere chiamato sulla classe (come
C.f()
) o su un'istanza (comeC().f()
). L'istanza viene ignorata ad eccezione della sua classe.I metodi statici in Python sono simili a quelli trovati in Java o C ++. Per un concetto più avanzato, vedi
classmethod()
.Per ulteriori informazioni sui metodi statici, consultare la documentazione sulla gerarchia dei tipi standard in Gerarchia dei tipi standard .
Novità nella versione 2.2.
Modificato nella versione 2.4: aggiunta la sintassi del decoratore di funzioni.
ClassName.methodName()
, come se fosse statico, e quindi non self
verrà fornito il metodo. Come hai detto, sarà comunque possibile chiamare questo metodo come ClassInstance.methodName()
e self
verrà fornito come primo parametro, indipendentemente dal nome.
Penso che Steven abbia effettivamente ragione . Per rispondere alla domanda originale, quindi, al fine di impostare un metodo di classe, supponi semplicemente che il primo argomento non sarà un'istanza chiamante, quindi assicurati di chiamare solo il metodo dalla classe.
(Nota che questa risposta si riferisce a Python 3.x. In Python 2.x otterrai un TypeError
per chiamare il metodo sulla classe stessa.)
Per esempio:
class Dog:
count = 0 # this is a class variable
dogs = [] # this is a class variable
def __init__(self, name):
self.name = name #self.name is an instance variable
Dog.count += 1
Dog.dogs.append(name)
def bark(self, n): # this is an instance method
print("{} says: {}".format(self.name, "woof! " * n))
def rollCall(n): #this is implicitly a class method (see comments below)
print("There are {} dogs.".format(Dog.count))
if n >= len(Dog.dogs) or n < 0:
print("They are:")
for dog in Dog.dogs:
print(" {}".format(dog))
else:
print("The dog indexed at {} is {}.".format(n, Dog.dogs[n]))
fido = Dog("Fido")
fido.bark(3)
Dog.rollCall(-1)
rex = Dog("Rex")
Dog.rollCall(0)
In questo codice, il metodo "rollCall" presuppone che il primo argomento non sia un'istanza (come sarebbe se fosse chiamato da un'istanza anziché da una classe). Finché "rollCall" viene chiamato dalla classe anziché da un'istanza, il codice funzionerà correttamente. Se proviamo a chiamare "rollCall" da un'istanza, ad esempio:
rex.rollCall(-1)
tuttavia, genererebbe un'eccezione perché invierebbe due argomenti: se stesso e -1, e "rollCall" è definito solo per accettare un argomento.
Per inciso, rex.rollCall () invierebbe il numero corretto di argomenti, ma provocherebbe anche un'eccezione perché ora n rappresenterebbe un'istanza Dog (cioè rex) quando la funzione prevede che n sia numerica.
È qui che entra in gioco la decorazione: se precediamo il metodo "rollCall" con
@staticmethod
quindi, dichiarando esplicitamente che il metodo è statico, possiamo persino chiamarlo da un'istanza. Adesso,
rex.rollCall(-1)
funzionerebbe. L'inserimento di @staticmethod prima di una definizione di metodo, quindi, impedisce a un'istanza di inviare se stessa come argomento.
Puoi verificarlo provando il seguente codice con e senza la riga @staticmethod commentata.
class Dog:
count = 0 # this is a class variable
dogs = [] # this is a class variable
def __init__(self, name):
self.name = name #self.name is an instance variable
Dog.count += 1
Dog.dogs.append(name)
def bark(self, n): # this is an instance method
print("{} says: {}".format(self.name, "woof! " * n))
@staticmethod
def rollCall(n):
print("There are {} dogs.".format(Dog.count))
if n >= len(Dog.dogs) or n < 0:
print("They are:")
for dog in Dog.dogs:
print(" {}".format(dog))
else:
print("The dog indexed at {} is {}.".format(n, Dog.dogs[n]))
fido = Dog("Fido")
fido.bark(3)
Dog.rollCall(-1)
rex = Dog("Rex")
Dog.rollCall(0)
rex.rollCall(-1)
TypeError: unbound method rollCall() must be called with Dog instance as first argument (got int instance instead)
T.my_static_method()
o type(my_t_instance).my_static_method()
, poiché questo è più chiaro e rende immediatamente ovvio che sto chiamando un metodo statico.
Sì, dai un'occhiata al decoratore del metodo statico :
>>> class C:
... @staticmethod
... def hello():
... print "Hello World"
...
>>> C.hello()
Hello World
Non hai davvero bisogno di usare il @staticmethod
decoratore. Dichiarare semplicemente un metodo (che non prevede il parametro auto) e chiamarlo dalla classe. Il decoratore è lì solo nel caso in cui tu voglia essere in grado di chiamarlo anche da un'istanza (che non era quello che volevi fare)
Principalmente, usi solo le funzioni però ...
class Dummy: def static1(): print "hello from static1" @staticmethod def static2(): print "hello from static2" Dummy.static2() Dummy.static1()
Output: ciao da static2 Traceback <ultima chiamata più recente>: file "ll.py", riga 46, in <module> Dummy.static1 () TypeError: metodo non associato static1 () deve essere chiamato con istanza fittizia come primo argomento (invece non ha ottenuto nulla)
self
come primo argomento a meno che tu non gli dica di non farlo. (vedi: decoratore)
self
ref in modo appropriato a seconda di come è stato chiamato. Caso di prova: pastebin.com/12DDV7DB .
staticmethod
decoratore consente di chiamare la funzione sia sulla classe che su un'istanza (questa soluzione non riesce quando si chiama la funzione su un'istanza).
class C: def callme(): print('called'); C.callme()
Metodi statici in Python?
È possibile avere metodi statici in Python in modo da poterli chiamare senza inizializzare una classe, come:
ClassName.StaticMethod()
Sì, i metodi statici possono essere creati in questo modo (anche se è un po 'più Pythonic per utilizzare i trattini bassi invece di CamelCase per i metodi):
class ClassName(object):
@staticmethod
def static_method(kwarg1=None):
'''return a value that is a function of kwarg1'''
Quanto sopra utilizza la sintassi del decoratore. Questa sintassi è equivalente a
class ClassName(object):
def static_method(kwarg1=None):
'''return a value that is a function of kwarg1'''
static_method = staticmethod(static_method)
Questo può essere usato proprio come hai descritto:
ClassName.static_method()
Un esempio incorporato di un metodo statico è str.maketrans()
in Python 3, che era una funzione nel string
modulo in Python 2.
Un'altra opzione che può essere usata mentre descrivi è la classmethod
, la differenza è che il metodo class ottiene la classe come primo argomento implicito e, se viene sottoclassata, ottiene la sottoclasse come primo argomento implicito.
class ClassName(object):
@classmethod
def class_method(cls, kwarg1=None):
'''return a value that is a function of the class and kwarg1'''
Nota che cls
non è un nome richiesto per il primo argomento, ma i programmatori Python più esperti lo considereranno mal fatto se usi qualcos'altro.
Questi sono in genere utilizzati come costruttori alternativi.
new_instance = ClassName.class_method()
Un esempio incorporato è dict.fromkeys()
:
new_dict = dict.fromkeys(['key1', 'key2'])
A parte le particolarità di come si comportano gli oggetti metodo statico , c'è un certo tipo di bellezza che puoi colpire quando si tratta di organizzare il tuo codice a livello di modulo.
# garden.py
def trim(a):
pass
def strip(a):
pass
def bunch(a, b):
pass
def _foo(foo):
pass
class powertools(object):
"""
Provides much regarded gardening power tools.
"""
@staticmethod
def answer_to_the_ultimate_question_of_life_the_universe_and_everything():
return 42
@staticmethod
def random():
return 13
@staticmethod
def promise():
return True
def _bar(baz, quux):
pass
class _Dice(object):
pass
class _6d(_Dice):
pass
class _12d(_Dice):
pass
class _Smarter:
pass
class _MagicalPonies:
pass
class _Samurai:
pass
class Foo(_6d, _Samurai):
pass
class Bar(_12d, _Smarter, _MagicalPonies):
pass
...
# tests.py
import unittest
import garden
class GardenTests(unittest.TestCase):
pass
class PowertoolsTests(unittest.TestCase):
pass
class FooTests(unittest.TestCase):
pass
class BarTests(unittest.TestCase):
pass
...
# interactive.py
from garden import trim, bunch, Foo
f = trim(Foo())
bunch(f, Foo())
...
# my_garden.py
import garden
from garden import powertools
class _Cowboy(garden._Samurai):
def hit():
return powertools.promise() and powertools.random() or 0
class Foo(_Cowboy, garden.Foo):
pass
Ora diventa un po 'più intuitivo e auto-documentante in quale contesto devono essere usati determinati componenti e si adatta in modo ideale per nominare casi di test distinti, oltre ad avere un approccio diretto al modo in cui i moduli di test si associano ai moduli effettivi sotto test per puristi .
Trovo spesso fattibile applicare questo approccio all'organizzazione del codice di utilità di un progetto. Abbastanza spesso, le persone si affrettano immediatamente e creano un utils
pacchetto e finiscono con 9 moduli di cui uno ha 120 LOC e il resto sono due dozzine di LOC al massimo. Preferisco iniziare con questo e convertirlo in un pacchetto e creare moduli solo per gli animali che li meritano davvero:
# utils.py
class socket(object):
@staticmethod
def check_if_port_available(port):
pass
@staticmethod
def get_free_port(port)
pass
class image(object):
@staticmethod
def to_rgb(image):
pass
@staticmethod
def to_cmyk(image):
pass
Forse l'opzione più semplice è quella di mettere quelle funzioni al di fuori della classe:
class Dog(object):
def __init__(self, name):
self.name = name
def bark(self):
if self.name == "Doggy":
return barking_sound()
else:
return "yip yip"
def barking_sound():
return "woof woof"
Utilizzando questo metodo, le funzioni che modificano o utilizzano lo stato dell'oggetto interno (hanno effetti collaterali) possono essere mantenute nella classe e le funzioni di utilità riutilizzabili possono essere spostate all'esterno.
Diciamo che questo file si chiama dogs.py
. Per usarli, dovresti chiamare dogs.barking_sound()
invece di dogs.Dog.barking_sound
.
Se hai davvero bisogno di un metodo statico per far parte della classe, puoi usare il decoratore di metodi statici .
Quindi, i metodi statici sono i metodi che possono essere chiamati senza creare l'oggetto di una classe. Per esempio :-
@staticmethod
def add(a, b):
return a + b
b = A.add(12,12)
print b
Nell'esempio sopra il metodo add
viene chiamato dal nome della classe e A
non dal nome dell'oggetto.
I metodi statici Python possono essere creati in due modi.
Utilizzando staticmethod ()
class Arithmetic:
def add(x, y):
return x + y
# create add static method
Arithmetic.add = staticmethod(Arithmetic.add)
print('Result:', Arithmetic.add(15, 10))
Produzione:
Risultato: 25
Utilizzando @staticmethod
class Arithmetic:
# create add static method
@staticmethod
def add(x, y):
return x + y
print('Result:', Arithmetic.add(15, 10))
Produzione:
Risultato: 25
Incontro questa domanda di volta in volta. Il caso d'uso e l'esempio a cui sono affezionato sono:
jeffs@jeffs-desktop:/home/jeffs $ python36
Python 3.6.1 (default, Sep 7 2017, 16:36:03)
[GCC 6.3.0 20170406] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import cmath
>>> print(cmath.sqrt(-4))
2j
>>>
>>> dir(cmath)
['__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'acos', 'acosh', 'asin', 'asinh', 'atan', 'atanh', 'cos', 'cosh', 'e', 'exp', 'inf', 'infj', 'isclose', 'isfinite', 'isinf', 'isnan', 'log', 'log10', 'nan', 'nanj', 'phase', 'pi', 'polar', 'rect', 'sin', 'sinh', 'sqrt', 'tan', 'tanh', 'tau']
>>>
Non ha senso creare un oggetto di classe cmath, perché non esiste uno stato in un oggetto cmath. Tuttavia, cmath è una raccolta di metodi che sono tutti correlati in qualche modo. Nel mio esempio sopra, tutte le funzioni di cmath agiscono su numeri complessi in qualche modo.
@staticmethod
decorazioni o usare un puntatore a funzione, quando puoi semplicemente evitare il primoself
parametro? Bene, per un oggettoa
, non sarai in grado di chiamarea.your_static_method()
, il che è consentito in altre lingue, ma è comunque considerato una cattiva pratica e il compilatore ti avvisa sempre di questo