Che cosa sono "metodi di classe" e "metodi di istanza", in Python?

35

C'è stata una discussione in chat relativa a una domanda (la domanda stessa è irrilevante per questa domanda), che ha rivelato che potrei non conoscere Python.

Nella mia mente, sebbene la terminologia differisca da una lingua all'altra, possiamo generalmente categorizzare le funzioni come:

  • [libero] funzioni
  • metodi statici / funzioni membro statiche
  • metodi non statici / funzioni membro non statiche

Apparentemente in Python esiste un altro tipo di funzione che non rientra nelle categorie precedenti, una che è un metodo ma "non conosce la sua classe".

Che cosa sono "metodi di classe" e "metodi di istanza", in Python?

    
posta Lightness Races in Orbit 29.12.2015 - 15:28
fonte

3 risposte

44

La risposta breve

  • un metodo di istanza conosce la sua istanza (e da quella, la sua classe)
  • un metodo di classe conosce la sua classe
  • un metodo statico non conosce la sua classe o istanza

La risposta lunga

Metodi di classe

Un metodo di classe è quello che appartiene alla classe nel suo insieme. Non richiede un'istanza. Invece, la classe verrà automaticamente inviata come primo argomento. Un metodo di classe è dichiarato con @classmethod decorator.

Ad esempio:

class Foo(object):
    @classmethod
    def hello(cls):
        print("hello from %s" % cls.__name__)
Foo.hello()
-> "Hello from Foo"
Foo().hello()
-> "Hello from Foo"

Metodi di istanza

D'altro canto, un metodo di istanza richiede un'istanza per chiamarlo e non richiede alcun decoratore. Questo è di gran lunga il tipo più comune di metodo.

class Foo(object):
    def hello(self):
        print("hello from %s" % self.__class__.__name__)
Foo.hello()
-> TypeError: hello() missing 1 required positional argument: 'self'

(nota: quanto sopra è con python3; con python2 avrai un errore leggermente diverso)

Metodi statici

Un metodo statico è simile a un metodo di classe, ma non otterrà l'oggetto di classe come parametro automatico. Viene creato utilizzando @staticmethod decorator.

class Foo(object):
    @staticmethod
    def hello(cls):
        print("hello from %s" % cls.__name__)

Foo.hello()
-> TypeError: hello() missing 1 required positional argument: 'cls'

Collegamenti alla documentazione

Ecco i link al relativo documentario python3:

La documentazione del modello di dati ha questo da dire sulla differenza tra metodi di classe e metodi statici :

Static method objects Static method objects provide a way of defeating the transformation of function objects to method objects described above. A static method object is a wrapper around any other object, usually a user-defined method object. When a static method object is retrieved from a class or a class instance, the object actually returned is the wrapped object, which is not subject to any further transformation. Static method objects are not themselves callable, although the objects they wrap usually are. Static method objects are created by the built-in staticmethod() constructor.

Class method objects A class method object, like a static method object, is a wrapper around another object that alters the way in which that object is retrieved from classes and class instances. The behaviour of class method objects upon such retrieval is described above, under “User-defined methods”. Class method objects are created by the built-in classmethod() constructor.

Domande correlate

risposta data 29.12.2015 - 15:57
fonte
7

What are “class methods” and “instance methods”, in Python?

  • Un "metodo di istanza" utilizza le informazioni contenute nell'istanza per capire quale valore restituire (o quale effetto collaterale fare). Questi sono molto comuni.

  • Un "metodo di classe" utilizza le informazioni sulla classe (e non un'istanza di quella classe) per influenzare ciò che fa (sono tipicamente usati per creare nuove istanze come costruttori alternativi, e quindi non sono incredibilmente comune).

  • Un "metodo statico" non utilizza alcuna informazione sulla classe o sull'istanza per calcolare ciò che fa. Di solito è solo nella classe per comodità. (Come tali, anche questi non sono molto comuni).

Funzione di X

Ricorda la classe matematica, "y è una funzione di x, f(x) ?" Applichiamo quello nel codice:

y = function(x)

La conseguenza di quanto sopra è che poiché x può cambiare, y può cambiare quando x cambia. Questo è ciò che si intende quando diciamo che " y è una funzione di x "

Che cosa sarà y quando z è 1 ? %codice%? %codice%?

2 non è una funzione di 'FooBarBaz' , quindi y può essere qualsiasi cosa e non influire sul risultato della funzione assumendo che il nostro z sia una funzione pura. (Se accede a z come variabile globale, allora non è una funzione pura - questo è ciò che si intende per purezza funzionale.)

Tieni a mente quanto sopra quando leggi le seguenti descrizioni:

Metodi di istanza

Un metodo di istanza è una funzione che è una funzione di un'istanza . La funzione accetta implicitamente l'istanza come argomento e l'istanza viene utilizzata dalla funzione per determinare l'output della funzione.

Un esempio built-in di un metodo di istanza è str.lower:

>>> 'ABC'.lower()
'abc'

function viene chiamato sull'istanza della stringa e utilizza le informazioni contenute nell'istanza per determinare quale nuova stringa deve essere restituita.

Metodi di classe:

Ricorda, in Python, tutto è un oggetto. Ciò significa che la classe è un oggetto e può essere passata come argomento a una funzione.

Un metodo di classe è una funzione che è una funzione di la classe . Accetta la classe come argomento.

Un esempio incorporato è z :

>>> dict.fromkeys('ABC')
{'C': None, 'B': None, 'A': None}

La funzione conosce implicitamente la propria classe, la funzione usa la classe per influenzare l'output della funzione, e ne crea una nuova da quella iterabile. Un OrderedDict lo dimostra quando si utilizza lo stesso metodo:

>>> from collections import OrderedDict
>>> OrderedDict.fromkeys('ABC')
OrderedDict([('A', None), ('B', None), ('C', None)])

Il metodo class usa informazioni sulla classe (e non un'istanza di quella classe) per influenzare il tipo di classe da restituire.

Metodi statici

Hai menzionato un metodo che "non conosce la sua classe" - questo è un metodo statico in Python. È semplicemente collegato per comodità all'oggetto di classe. Potrebbe facoltativamente essere una funzione separata in un altro modulo, ma la sua firma di chiamata sarebbe la stessa.

Un metodo statico non è una funzione né della classe né dell'oggetto.

Un esempio built-in di un metodo statico è str.maketrans da Python 3.

>>> str.maketrans('abc', 'bca')
{97: 98, 98: 99, 99: 97}

Dato un paio di argomenti, rende un dizionario che non è una funzione della sua classe.

È comodo perché str.lower è sempre disponibile nello spazio dei nomi globale, quindi puoi facilmente utilizzarlo con la funzione di traduzione:

>>> 'abracadabra'.translate(str.maketrans('abc', 'bca'))
'bcrbabdbcrb'

In Python 2, devi accedervi dal modulo dict.fromkeys :

>>> 'abracadabra'.translate(str.maketrans('abc', 'bca'))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: type object 'str' has no attribute 'maketrans'
>>> import string
>>> 'abracadabra'.translate(string.maketrans('abc', 'bca'))
'bcrbabdbcrb'

Esempio

class AClass(object):
    """In Python, a class may have several types of methods: 
    instance methods, class methods, and static methods
    """

    def an_instance_method(self, x, y, z=None):
        """this is a function of the instance of the object
        self is the object's instance
        """
        return self.a_class_method(x, y)

    @classmethod
    def a_class_method(cls, x, y, z=None):
        """this is a function of the class of the object
        cls is the object's class
        """
        return cls.a_static_method(x, y, z=z)

    @staticmethod
    def a_static_method(x, y, z=None):
        """this is neither a function of the instance or class to 
        which it is attached
        """
        return x, y, z

Facciamo un'istanza:

>>> instance = AClass()

Ora l'istanza può chiamare tutti i metodi:

>>> instance.an_instance_method('x', 'y')
('x', 'y', None)
>>> instance.a_static_method('x', 'y')
('x', 'y', None)
>>> instance.a_class_method('x', 'y')
('x', 'y', None)

Ma di solito la classe non è chiamata a chiamare il metodo di istanza, anche se è previsto chiamare gli altri:

>>> AClass.a_class_method('x', 'y')
('x', 'y', None)
>>> AClass.a_static_method('x', 'y')
('x', 'y', None)
>>> AClass.an_instance_method('x', 'y')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: an_instance_method() missing 1 required positional argument: 'y'

Dovresti passare esplicitamente l'istanza per chiamare il metodo di istanza:

>>> AClass.an_instance_method(instance, 'x', 'y')
('x', 'y', None)
    
risposta data 29.12.2015 - 15:56
fonte
4
  • Un "metodo di istanza" è un metodo che ottiene l'oggetto istanza come suo primo parametro, che per convenzione è chiamato self . Questa è l'impostazione predefinita.

  • Un "metodo statico" è un metodo senza il parametro iniziale self . Questo è implementato con il decoratore @staticmethod .

  • Un "metodo di classe" è un metodo in cui il parametro iniziale non è un oggetto istanza, ma l'oggetto classe ( vedi questa parte dei documenti Python per cosa è un" oggetto di classe "), che per convenzione si chiama cls . Questo è implementato con il decoratore @classmethod .

L'uso tipico del termine "metodo statico" in C / C ++ / etc si applica a entrambi i metodi "statici" e "classe" Python, poiché entrambi i tipi di metodi mancano di un riferimento all'istanza. In C / C ++ / etc, i metodi normalmente hanno accesso implicito a tutti i membri / metodi non di istanza della classe, che è probabilmente il motivo per cui questa distinzione esiste solo in linguaggi come Python / Ruby / etc.

    
risposta data 29.12.2015 - 17:34
fonte

Leggi altre domande sui tag