Apa itu "metode kelas" dan "metode instan", dalam Python?

37

Telah ada diskusi dalam obrolan yang berkaitan dengan pertanyaan (pertanyaan itu sendiri tidak relevan dengan yang satu ini), yang telah mengungkapkan saya mungkin tidak tahu Python sama sekali.

Dalam benak saya, meskipun terminologi berbeda antar bahasa, kami umumnya dapat mengkategorikan fungsi sebagai:

  • fungsi [gratis]
  • metode statis / fungsi anggota statis
  • metode non-statis / fungsi anggota tidak statis

Rupanya dalam Python ada jenis fungsi lain yang tidak masuk ke dalam kategori di atas, yang merupakan metode tetapi "tidak tahu kelasnya".

Apa itu "metode kelas" dan "metode instan", dalam Python?

Lightness Races with Monica
sumber
1
Jika ada yang tertarik dengan diskusi obrolan, mulailah di sini: chat.stackexchange.com/transcript/message/26479002#26479002
yannis
1
IMO jawaban yang lebih baik diberikan oleh situs web stackexchange yang berbeda: stackoverflow.com/questions/136097/…
Trevor Boyd Smith
FYI tautannya disediakan di bagian bawah yang diterima ... tapi saya pikir banyak orang akan kehilangan tautan atau tidak pernah mendapatkannya dan jadi saya menyalinnya di sini.
Trevor Boyd Smith

Jawaban:

49

Jawaban singkatnya

  • metode instance tahu instance-nya (dan dari situ, kelasnya)
  • metode kelas tahu kelasnya
  • metode statis tidak tahu kelas atau instansnya

Jawaban panjangnya

Metode kelas

Sebuah metode kelas adalah salah satu yang termasuk kelas secara keseluruhan. Itu tidak membutuhkan contoh. Sebagai gantinya, kelas akan secara otomatis dikirim sebagai argumen pertama. Metode kelas dideklarasikan dengan @classmethoddekorator.

Sebagai contoh:

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

Metode Instance

Di sisi lain, metode instance memerlukan instance untuk menyebutnya, dan tidak memerlukan dekorator. Sejauh ini ini adalah jenis metode yang paling umum.

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

(catatan: di atas adalah dengan python3; dengan python2 Anda akan mendapatkan kesalahan yang sedikit berbeda)

Metode statis

Sebuah metode statis mirip dengan metode kelas, tetapi tidak akan mendapatkan objek kelas sebagai parameter otomatis. Itu dibuat dengan menggunakan @staticmethoddekorator.

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

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

Tautan dokumentasi

Berikut ini tautan ke dokumen python3 yang relevan:

The Dokumentasi model data telah mengatakan tentang perbedaan antara metode kelas dan metode statis:

Objek metode statis Objek metode statis menyediakan cara untuk mengalahkan transformasi objek fungsi ke objek metode yang dijelaskan di atas. Objek metode statis adalah pembungkus di sekitar objek lain, biasanya objek metode yang ditentukan pengguna. Ketika objek metode statis diambil dari kelas atau instance kelas, objek yang sebenarnya dikembalikan adalah objek yang dibungkus, yang tidak mengalami transformasi lebih lanjut. Objek metode statis tidak dapat dipanggil sendiri, meskipun objek yang dibungkus biasanya. Objek metode statis dibuat oleh konstruktor staticmethod () bawaan.

Objek metode kelas Objek metode kelas, seperti objek metode statis, adalah pembungkus di sekitar objek lain yang mengubah cara objek tersebut diambil dari kelas dan instance kelas. Perilaku objek metode kelas setelah pengambilan tersebut dijelaskan di atas, di bawah “Metode yang ditentukan pengguna”. Objek metode kelas dibuat oleh konstruktor classmethod () bawaan.

Pertanyaan-pertanyaan Terkait

Bryan Oakley
sumber
4
@LightnessRacesinOrbit: Saya tidak berpikir metode statis digunakan sangat sering dalam python. Menggunakan sistem saya sebagai sampel acak, ketika saya mencari semua paket yang telah saya instal, hanya sekitar 1% dari semua metode adalah metode statis (yang terus terang lebih dari yang saya harapkan).
Bryan Oakley
1
"Metode statis" biasanya merupakan bau kode, dan tidak disarankan oleh misalnya panduan gaya Gogole Python.
9000
3
Saya pikir jawabannya akan lebih baik jika menarik perhatian subclass, yang mana metode kelas mendapatkan kegunaan.
Winston Ewert
1
@ user2357112: Saya hanya menghitung semua contoh "^ def(", lalu menghitung semua contoh @staticmethod. Sangat tidak ilmiah, tetapi mungkin berada di stadion baseball.
Bryan Oakley
2
@Kashyap: TL; DR berlaku untuk paragraf pertama. Saya pikir ini bekerja lebih baik di bagian atas daripada bagian bawah.
Bryan Oakley
8

Apa itu "metode kelas" dan "metode instan", dalam Python?

  • "Metode instance" menggunakan informasi yang terdapat dalam instance untuk mengetahui nilai apa yang akan dikembalikan (atau efek samping mana yang harus dilakukan). Ini sangat umum.

  • "Metode kelas" menggunakan informasi tentang kelas (dan bukan turunan dari kelas itu) untuk memengaruhi apa yang dilakukannya (mereka biasanya digunakan untuk membuat instance baru sebagai konstruktor alternatif, dan karenanya tidak terlalu umum).

  • "Metode statis" tidak menggunakan informasi apa pun tentang kelas atau instance untuk menghitung apa yang dilakukannya. Biasanya hanya di kelas untuk kenyamanan. (Karena itu, ini juga tidak umum.)

Fungsi X

Ingat kelas matematika, "kamu adalah fungsi dari x f(x),?" Mari kita terapkan itu dalam kode:

y = function(x)

Tersirat di atas adalah bahwa karena xdapat berubah, ydapat berubah ketika xperubahan. Inilah yang dimaksud ketika kita mengatakan bahwa " yadalah fungsi dari x"

Apa yang akan yterjadi bila zadalah 1? 2? 'FooBarBaz'?

ybukan fungsi z, jadi zbisa apa saja dan tidak memengaruhi hasil fungsi dengan anggapan kita functionadalah fungsi murni. (Jika diakses zsebagai variabel global, maka itu bukan fungsi murni - inilah yang dimaksud dengan kemurnian fungsional.)

Ingatlah hal-hal di atas ketika Anda membaca deskripsi berikut:

Metode Instance

Metode instance adalah fungsi yang merupakan fungsi dari instance . Fungsi menerima instance secara implisit sebagai argumen padanya, dan instance digunakan oleh fungsi untuk menentukan output dari fungsi.

Contoh bawaan dari metode instance adalah str.lower:

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

str.lower dipanggil pada instance string, dan menggunakan informasi yang terkandung dalam instance untuk mencari string baru yang akan dikembalikan.

Metode Kelas:

Ingat, dengan Python, semuanya adalah objek. Itu berarti kelas adalah objek, dan dapat dilewatkan sebagai argumen ke suatu fungsi.

Metode kelas adalah fungsi yang merupakan fungsi dari kelas . Itu menerima kelas sebagai argumen untuk itu.

Contoh bawaan adalah dict.fromkeys:

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

Fungsi tersebut secara implisit mengetahui kelasnya sendiri, fungsinya menggunakan kelas tersebut untuk memengaruhi output fungsi, dan ia membuat yang baru dari kelas tersebut dari yang dapat diubah. Sebuah OrderedDict menunjukkan ini saat menggunakan metode yang sama:

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

Metode kelas menggunakan informasi tentang kelas (dan bukan turunan dari kelas itu) untuk memengaruhi tipe kelas yang akan dikembalikan.

Metode Statis

Anda menyebutkan metode yang "tidak tahu kelasnya" - ini adalah metode statis dengan Python. Itu hanya dilampirkan untuk kenyamanan ke objek kelas. Secara opsional bisa menjadi fungsi terpisah di modul lain, tetapi tanda tangan panggilannya akan sama.

Metode statis adalah fungsi baik dari kelas maupun objek.

Contoh built-in dari metode statis adalah str.maketrans dari Python 3.

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

Diberikan beberapa argumen, itu membuat kamus yang bukan fungsi dari kelasnya.

Ini nyaman karena strselalu tersedia di namespace global, sehingga Anda dapat dengan mudah menggunakannya dengan fungsi terjemahan:

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

Dalam Python 2, Anda harus mengaksesnya dari stringmodul:

>>> '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'

Contoh

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

Mari instantiate:

>>> instance = AClass()

Sekarang instance dapat memanggil semua metode:

>>> 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)

Tetapi kelas biasanya tidak dimaksudkan untuk memanggil metode instance, meskipun diharapkan memanggil yang lain:

>>> 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'

Anda harus secara eksplisit memberikan instance untuk memanggil metode instance:

>>> AClass.an_instance_method(instance, 'x', 'y')
('x', 'y', None)
Aaron Hall
sumber
"Ini adalah metode statis dalam Python. Ini hanya dilampirkan untuk kenyamanan ke objek kelas. Secara opsional bisa menjadi fungsi terpisah dalam modul lain, tetapi tanda tangan panggilannya akan sama." Tampaknya lebih membingungkan daripada nyaman. Mengapa Anda melampirkan fungsi ke kelas jika tubuhnya tidak memiliki gagasan tentang kelas itu.
Lightness Races with Monica
@LightnessRacesinOrbit Saya sudah menguraikan pada setiap titik
Aaron Hall
Secara pribadi, cara saya selalu melihatnya adalah bahwa metode instance adalah operasi pada instance tertentu, metode kelas adalah semacam konstruktor (untuk kenyamanan, tidak seperti MyClass(1,2,3)tapi bukan suka, MyClass.get_special(1,2,3)), dan metode statis hanya sebagai menjadi fungsi normal yang bisa berdiri sendiri.
Zizouz212
Ya, classmethods biasanya digunakan untuk konstruktor alternatif (lihat contoh dict.fromkeys saya di atas, lihat juga kode sumber pandas.DataFrame), tetapi itu bukan karakteristik yang menentukan. Saya kadang-kadang hanya perlu mengakses data yang disimpan di tingkat kelas dari suatu metode, tanpa mengakses instance. Jika Anda memanggil tipe (self) (atau lebih buruk, self .__ class__) dan tidak menggunakan self secara langsung dalam metode instan, itu pertanda baik bahwa Anda harus menganggapnya sebagai metode kelas. Karena metode kelas tidak memerlukan contoh, itu membuat mereka lebih mudah untuk dipasangkan.
Aaron Hall
4
  • "Metode instance" adalah metode yang dapat melewati objek instance sebagai parameter pertama, yang oleh konvensi disebut self. Ini standarnya.

  • "Metode statis" adalah metode tanpa selfparameter awal . Ini diimplementasikan dengan dekorator @staticmethod .

  • "Metode kelas" adalah metode di mana parameter awal bukan objek instan, tetapi objek kelas ( lihat bagian dokumen Python ini untuk apa "objek kelas"), yang oleh konvensi disebut cls. Ini diimplementasikan dengan dekorator @classmethod .

Penggunaan khas dari istilah "metode statis" dalam C / C ++ / etc berlaku untuk metode "kelas" Python "statis" dan Python, karena kedua jenis metode tersebut tidak memiliki referensi ke instance. Dalam C / C ++ / etc, metode biasanya memiliki akses implisit ke semua anggota / metode non-instance kelas, yang mungkin mengapa perbedaan ini hanya ada dalam bahasa seperti Python / Ruby / etc.

Ixrec
sumber
Apakah metode statis di C / C ++ memiliki referensi ke objek kelas? Atau hanya "anggota" kelas? Bisakah mereka membuat anggota baru di kelas? :)
Aaron Hall
3
@ AaronHall Dalam C / C ++, tidak ada yang namanya objek kelas, dan Anda tidak perlu referensi untuk memanggil metode statis. Anda hanya menulis Class::staticMethod()dan hanya itu (selama Anda tidak dilarang menyebutnya karena staticMethod()bersifat pribadi atau semacamnya).
Ixrec