Apa keuntungan menggunakan metode statis dengan Python?

90

Saya mengalami kesalahan metode tidak terikat di python dengan kode

import random

class Sample(object):
'''This class defines various methods related to the sample'''

    def drawSample(samplesize,List):
        sample=random.sample(List,samplesize)
        return sample

Choices=range(100)
print Sample.drawSample(5,Choices)

Setelah membaca banyak posting bermanfaat di sini, saya memikirkan bagaimana saya bisa menambahkan di @staticmethodatas agar kode berfungsi. Saya seorang pemula python. Adakah yang bisa menjelaskan mengapa seseorang ingin mendefinisikan metode statis? Atau, mengapa tidak semua metode didefinisikan sebagai metode statis?

Curious2learn
sumber
1
Ini pertanyaan yang aneh. Metode statis adalah kebutuhan desain . Ini bukanlah hal "keuntungan". Anda menggunakannya karena Anda harus. Ini adalah fitur desain kelas yang memiliki metode statis. Apakah Anda bertanya apa metode statis itu? Saya pikir pertanyaannya bisa diubah untuk lebih jelas mendefinisikan apa yang perlu Anda ketahui.
S. Lott
15
Tidak, saya tidak ingin tahu apa itu. Yang ingin saya ketahui adalah mengapa ini menjadi "keharusan", yang menjadi jelas dari jawaban yang diberikan oleh orang lain. Saat itulah Anda akan mendefinisikannya daripada metode non-statis. Terima kasih.
Curious2learn
3
@ S. Lott: Kapan menggunakan metode statis sebagai suatu keharusan dibandingkan dengan menggunakan metode kelas normal? Sejauh yang saya tahu, metode kelas dapat melakukan semua yang dapat dilakukan metode statis. Metode statis memang memiliki "keunggulan" seperti yang tercantum di tempat lain di posting ini, tetapi saya tidak dapat melihat alasan mengapa metode kelas tidak dapat digunakan di tempat mana pun metode statis dapat digunakan, sehingga menjadikannya suatu keharusan.
RFV

Jawaban:

128

Metode statis memiliki penggunaan yang terbatas, karena mereka tidak memiliki akses ke atribut instance kelas (seperti metode biasa), dan tidak memiliki akses ke atribut kelas itu sendiri (seperti metode kelas. ).

Jadi mereka tidak berguna untuk metode sehari-hari.

Namun, mereka dapat berguna untuk mengelompokkan beberapa fungsi utilitas bersama dengan sebuah kelas - misalnya konversi sederhana dari satu jenis ke jenis lainnya - yang tidak memerlukan akses ke informasi apa pun selain dari parameter yang disediakan (dan mungkin beberapa atribut global ke modul. )

Mereka dapat ditempatkan di luar kelas, tetapi mengelompokkan mereka di dalam kelas mungkin masuk akal jika hanya diterapkan di sana.

Anda juga dapat mereferensikan metode melalui sebuah instance atau kelas, daripada nama modul, yang dapat membantu pembaca memahami instance apa yang terkait dengan metode tersebut.

Berpikir aneh
sumber
8
@ Curious2learn: Tidak semua , tetapi beberapa metode berguna sebagai metode statis. Pikirkan tentang Localekelas contoh , yang instansinya akan menjadi lokal (duh). Sebuah getAvailableLocales()metode akan menjadi contoh yang bagus dari metode statis kelas tersebut: itu jelas milik kelas Lokal, sementara juga jelas bukan milik contoh tertentu.
MestreLion
... dan ini juga bukan metode kelas, karena mungkin tidak perlu mengakses metode kelas mana pun.
MestreLion
Seorang editor menunjukkan bahwa metode statis dapat mengakses atribut kelas, dengan secara eksplisit menavigasi ke bawah dari class_name.attribute, just not cls.attributeor self.attribute. Ini berlaku untuk atribut "publik". Sesuai ketentuan, Anda tidak boleh mengakses atribut yang disembunyikan dengan garis bawah, atau nama yang tercabik-cabik dengan dua garis bawah, dengan cara ini. Ini juga berarti kode Anda akan lebih rapuh ketika atribut berpindah tempat pada hierarki pewarisan.
Oddthinking
Kutipan dari Guido yang membantu untuk memutuskan kapan harus menggunakan metode statis (tidak pernah): "Kita semua tahu betapa terbatasnya metode statis. (Mereka pada dasarnya adalah kecelakaan - kembali pada hari Python 2.2 ketika saya menemukan kelas dan deskriptor gaya baru , Saya bermaksud menerapkan metode kelas tetapi pada awalnya saya tidak memahaminya dan secara tidak sengaja menerapkan metode statis terlebih dahulu. Kemudian sudah terlambat untuk menghapusnya dan hanya menyediakan metode kelas. "
Boris Churzin
189

Lihat artikel ini untuk penjelasan rinci.

TL; DR

1. Ini menghilangkan penggunaan selfargumen.

2. Ini mengurangi penggunaan memori karena Python tidak harus membuat contoh metode terikat untuk setiap objek yang diinstiansi:

>>>RandomClass().regular_method is RandomClass().regular_method
False
>>>RandomClass().static_method is RandomClass().static_method
True
>>>RandomClass.static_method is RandomClass().static_method
True

3. Ini meningkatkan keterbacaan kode, menandakan bahwa metode tersebut tidak bergantung pada status objek itu sendiri.

4. Hal ini memungkinkan untuk metode overriding jika metode didefinisikan pada tingkat modul (yaitu di luar kelas) subkelas tidak akan dapat menggantikan metode itu.

zanetu
sumber
3
Ini harus menjadi jawaban yang diterima. Fakta bahwa metode statis pada setiap instance dan kelas itu sendiri adalah objek yang sama adalah keuntungan nyata, terutama bila Anda memiliki banyak instance (misalnya setiap instance untuk record database yang bisa berubah).
Zhuoyun Wei
+1 dan setuju dengan @ZhuoyunWei. Hanya jawaban yang menjelaskan beberapa alasan mengapa metode statis terkadang lebih disukai daripada metode kelas (meskipun 1 dan 3 benar-benar alasan yang sama).
Alex
1
Jawaban terbaik untuk "mengapa metode statis", tetapi pertanyaan asli juga menanyakan "mengapa tidak semua metode statis?". Singkat "tidak ada akses ke atribut instance" akan mencakup itu juga.
Kel
IMO satu-satunya keuntungan nyata adalah bahwa Anda dapat menggantinya dalam subkelas, tetapi bahkan itu memiliki perasaan bahwa Anda melakukan sesuatu yang salah OOP-bijaksana, dalam kasus penggunaan apa Anda akan melakukan itu?
Boris Churzin
23

Ini tidak tepat pada pertanyaan Anda yang sebenarnya, tetapi karena Anda telah mengatakan bahwa Anda adalah pemula python mungkin itu akan membantu, dan tidak ada orang lain yang cukup keluar dan mengatakannya secara eksplisit.

Saya tidak akan pernah memperbaiki kode di atas dengan membuat metode metode statis. Saya akan meninggalkan kelas dan hanya menulis fungsi:

def drawSample(samplesize,List):
    sample=random.sample(List,samplesize)
    return sample

Choices=range(100)
print drawSample(5,Choices)

Jika Anda memiliki banyak fungsi terkait, Anda dapat mengelompokkannya dalam sebuah modul - yaitu, taruh semuanya dalam file yang sama, dinamai sample.pymisalnya; kemudian

import sample

Choices=range(100)
print sample.drawSample(5,Choices)

Atau saya akan menambahkan __init__metode ke kelas dan membuat contoh yang memiliki metode yang berguna:

class Sample(object):
'''This class defines various methods related to the sample'''

    def __init__(self, thelist):
        self.list = thelist

    def draw_sample(self, samplesize):
        sample=random.sample(self.list,samplesize)
        return sample

choices=Sample(range(100))
print choices.draw_sample(5)

(Saya juga mengubah konvensi case pada contoh di atas agar sesuai dengan gaya yang direkomendasikan oleh PEP 8.)

Salah satu kelebihan Python adalah tidak memaksa Anda menggunakan kelas untuk semuanya. Anda dapat menggunakannya hanya jika ada data atau status yang harus dikaitkan dengan metode, untuk tujuan kelas apa. Jika tidak, Anda dapat menggunakan fungsi, untuk apa fungsi itu.

Vicki Laidler
sumber
Terima kasih atas komentarnya. Saya memang membutuhkan kelas dalam hal ini karena saya ingin bekerja dengan sampel yang diambil. Tidak, saya tidak menggunakan metode statis, tetapi ingin mempelajarinya, karena saya menemukan istilah tersebut ketika mencari informasi tentang pesan kesalahan yang saya dapatkan. Tetapi saran Anda tentang mengumpulkan fungsi ke dalam modul tanpa mendefinisikan kelas akan membantu untuk fungsi lain yang saya perlukan. Jadi terima kasih.
Curious2learn
4
+1: Itu adalah penjelasan yang bagus tentang beberapa kesalahpahaman yang dimiliki OP. Dan kau sangat jujur untuk mengatakan, dimuka, bahwa Anda tidak benar-benar menjawab pertanyaannya tentang metode statis, tetapi Anda lebih suka memberi yang lebih baik banyak solusi mengatakan masalahnya tidak memerlukan kelas sama sekali.
MestreLion
22

Mengapa seseorang ingin mendefinisikan metode statis ?

Misalkan kita memiliki classdisebut Mathkemudian

tak seorang pun ingin membuat objek class Math
dan kemudian memanggil metode seperti ceildan floordan fabsdi atasnya.

Jadi kami membuatnya static.

Misalnya melakukan

>> Math.floor(3.14)

jauh lebih baik daripada

>> mymath = Math()
>> mymath.floor(3.14)

Jadi mereka berguna dalam beberapa hal. Anda tidak perlu membuat instance kelas untuk menggunakannya.

Mengapa tidak semua metode didefinisikan sebagai metode statis ?

Mereka tidak memiliki akses ke variabel instance.

class Foo(object):
    def __init__(self):
        self.bar = 'bar'

    def too(self):
        print self.bar

    @staticmethod
    def foo():
        print self.bar

Foo().too() # works
Foo.foo() # doesn't work

Itulah mengapa kami tidak membuat semua metode menjadi statis.

Pratik Deoghare
sumber
10
Tapi kenapa tidak matematika paket? Python memiliki paket untuk itu, Anda tidak memerlukan definisi kelas untuk membuat namespace.
ekstraneon
6
@extraneon: Yup bung, saya tahu itu tetapi saya ingin memiliki sesuatu yang sederhana dan akrab untuk penjelasan jadi saya gunakan Math. Itulah mengapa saya menggunakan huruf besar M.
Pratik Deoghare
6
OP tidak menanyakan apa itu metode statis. Dia bertanya apa keuntungan mereka. Anda menjelaskan bagaimana menggunakannya, bukan bagaimana kegunaannya. Dalam contoh khusus Anda, namespace akan jauh lebih masuk akal.
Javier
4
-1: Penjelasan yang baik dan benar, tetapi contoh yang dipilih dengan sangat buruk: tidak ada alasan untuk membuat Anda Mathmenjadi kelas sejak awal, modul akan lebih cocok. Cobalah untuk menemukan contoh kelas yang masuk akal sebagai kelas, bukan kelas yang "tak seorang pun ingin membuat objek" .
MestreLion
3
Dan kemudian berikan contoh kasus penggunaan yang sah untuk satu (atau beberapa ) metode kelas menjadi statis, tetapi tidak semua . Jika semua metode kelas statis, kelas harus berupa modul. Jika tidak ada yang statis, maka Anda tidak menjawab pertanyaan itu.
MestreLion
13

Saat Anda memanggil objek fungsi dari instance objek, itu menjadi 'metode terikat' dan objek instance itu sendiri diteruskan sebagai argumen pertama.

Saat Anda memanggil sebuah classmethodobjek (yang membungkus sebuah objek fungsi) pada sebuah instance objek, kelas dari objek instance tersebut dilewatkan sebagai argumen pertama.

Saat Anda memanggil staticmethodobjek (yang membungkus objek fungsi), tidak ada argumen pertama implisit yang digunakan.

class Foo(object):

    def bar(*args):
        print args

    @classmethod
    def baaz(*args):
        print args

    @staticmethod
    def quux(*args):
        print args

>>> foo = Foo()

>>> Foo.bar(1,2,3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unbound method bar() must be called with Foo instance as first argument (got int instance instead)
>>> Foo.baaz(1,2,3)
(<class 'Foo'>, 1, 2, 3)
>>> Foo.quux(1,2,3)
(1, 2, 3)

>>> foo.bar(1,2,3)
(<Foo object at 0x1004a4510>, 1, 2, 3)
>>> foo.baaz(1,2,3)
(<class 'Foo'>, 1, 2, 3)
>>> foo.quux(1,2,3)
(1, 2, 3)
Matt Anderson
sumber
3
+1: Akhirnya penjelasan bagus tentang apa itu metode statis dan metode kelas. Meskipun Anda tidak menjelaskan mengapa orang akan pernah ingin menggunakan metode statis, setidaknya Anda jelas dijelaskan dalam contoh sederhana apa yang baik yang jauh lebih baik daripada dokumentasi resmi tidak.
MestreLion
3

metode statis sangat bagus karena Anda tidak perlu mendeklarasikan instance objek tempat metode tersebut berada.

Situs python memiliki beberapa dokumentasi bagus tentang metode statis di sini:
http://docs.python.org/library/functions.html#staticmethod

David Fox
sumber
Terima kasih David. Tapi mengapa tidak mendefinisikan setiap metode sebagai metode statis, karena mereka juga bekerja pada contoh. Apakah ada kekurangannya?
Curious2learn
4
@ Curious2learn: Tidak, dengan metode statis Anda tidak memiliki akses ke instance: Instance diabaikan kecuali untuk kelasnya.
Felix Kling
4
Argumen itu akan benar di Java, di mana fungsi tidak bisa hidup dengan sendirinya tetapi selalu ditentukan dalam konteks kelas. Tetapi dengan Python Anda dapat memiliki fungsi dan fungsi kelas statis. Jawaban ini tidak benar-benar menunjukkan mengapa memilih metode statis sebagai ganti metode yang tidak ada di kelas.
ekstraneon
1
@extraneon - itu lebih merupakan masalah preferensi organisasi kode; memiliki metode statis memberi satu opsi tambahan.
Charles Duffy
@Felix - Terima kasih. Ini menjelaskan mengapa setiap metode tidak boleh menjadi metode statis.
Curious2learn
3

Alternatif untuk staticmethodadalah: classmethod, instancemethod, dan function. Jika Anda tidak tahu apa ini, gulir ke bawah ke bagian terakhir. Jika a staticmethodlebih baik daripada salah satu alternatif ini, tergantung pada tujuan penulisannya.

keuntungan dari metode statis Python

  • Jika Anda tidak memerlukan akses ke atribut atau metode kelas atau instance, a staticmethodlebih baik daripada a classmethodatau instancemethod. Dengan begitu jelas (dari @staticmethoddekorator) bahwa status kelas dan instance tidak dibaca atau diubah. Namun, menggunakan a functionmembuat perbedaan itu lebih jelas (lihat kerugian).
  • Tanda tangan panggilan a staticmethodsama dengan tanda tangan a classmethodatau instancemethod, yaitu <instance>.<method>(<arguments>). Oleh karena itu dapat dengan mudah diganti dengan salah satu dari tiga jika itu diperlukan nanti atau di kelas turunan. Anda tidak dapat melakukannya dengan sederhana function.
  • A staticmethoddapat digunakan sebagai pengganti a functionuntuk memperjelas bahwa itu secara subjektif milik kelas dan untuk mencegah konflik namespace.

kerugian dari metode statis Python

  • Itu tidak dapat mengakses atribut atau metode dari instance atau kelas.
  • Tanda tangan panggilan a staticmethodsama dengan tanda tangan classmethodatau instancemethod. Ini menutupi fakta bahwa staticmethodsebenarnya tidak membaca atau mengubah informasi objek apa pun. Ini membuat kode lebih sulit untuk dibaca. Mengapa tidak menggunakan a function?
  • A staticmethodsulit digunakan kembali jika Anda perlu memanggilnya dari luar kelas / instance tempat ia didefinisikan. Jika ada potensi untuk digunakan kembali, a functionadalah pilihan yang lebih baik.
  • Ini staticmethodjarang digunakan, jadi orang yang membaca kode yang menyertakannya mungkin membutuhkan waktu lebih lama untuk membacanya.

alternatif untuk metode statis dengan Python

Untuk membahas tentang keuntungan dari staticmethod, kita perlu mengetahui apa alternatif itu dan bagaimana perbedaannya satu sama lain.

  • The staticmethodmilik kelas tetapi tidak dapat mengakses atau mengubah setiap contoh atau kelas informasi.

Ada tiga alternatif untuk itu:

  • The classmethodmemiliki akses ke kelas pemanggil.
  • The instancemethodmemiliki akses ke contoh pemanggil dan kelasnya.
  • Tidak functionada hubungannya dengan kelas. Ini adalah yang paling dekat dalam kapabilitas dengan staticmethod.

Inilah yang terlihat seperti dalam kode:

# function
# has nothing to do with a class
def make_cat_noise(asker_name):
    print('Hi %s, mieets mieets!' % asker_name)

# Yey, we can make cat noises before we've even defined what a cat is!
make_cat_noise('JOey')  # just a function

class Cat:
    number_of_legs = 4

    # special instance method __init__
    def __init__(self, name):
        self.name = name

    # instancemethod
    # the instance (e.g. Cat('Kitty')) is passed as the first method argument
    def tell_me_about_this_animal(self, asker_name):
        print('Hi %s, This cat has %d legs and is called %s'
              % (asker_name, self.number_of_legs, self.name))

    # classmethod
    # the class (e.g. Cat) is passed as the first method argument
    # by convention we call that argument cls
    @classmethod
    def tell_me_about_cats(cls, asker_name):
        print("Hi %s, cats have %d legs."
              % (asker_name, cls.number_of_legs))
        # cls.name  # AttributeError because only the instance has .name
        # self.name  # NameError because self isn't defined in this namespace

    # staticmethod
    # no information about the class or the instance is passed to the method
    @staticmethod
    def make_noise(asker_name):
        print('Hi %s, meooow!' % asker_name)
        # class and instance are not accessible from here

# one more time for fun!
make_cat_noise('JOey')  # just a function

# We just need the class to call a classmethod or staticmethod:
Cat.make_noise('JOey')  # staticmethod
Cat.tell_me_about_cats('JOey')  # classmethod
# Cat.tell_me_about_this_animal('JOey')  # instancemethod -> TypeError

# With an instance we can use instancemethod, classmethod or staticmethod
mycat = Cat('Kitty')  # mycat is an instance of the class Cat
mycat.make_noise('JOey')  # staticmethod
mycat.tell_me_about_cats('JOey')  # classmethod
mycat.tell_me_about_this_animal('JOey')  # instancemethod
Joooeey
sumber
1

Karena fungsi namespacing bagus (seperti yang ditunjukkan sebelumnya):

  1. Ketika saya ingin menjelaskan tentang metode yang tidak mengubah status objek, saya menggunakan metode statis. Ini membuat orang-orang di tim saya enggan untuk mulai mengubah atribut objek dalam metode tersebut.

  2. Ketika saya merefaktor kode yang benar-benar busuk, saya mulai dengan mencoba membuat metode @staticmethodsebanyak mungkin. Hal ini memungkinkan saya untuk mengekstrak metode ini ke dalam kelas - meskipun saya setuju, ini jarang sesuatu yang saya gunakan, itu memang berguna beberapa kali.

vlad-ardelean.dll
sumber
1

Dalam perkiraan saya, tidak ada manfaat kinerja tunggal menggunakan @staticmethods dibandingkan dengan hanya mendefinisikan fungsi di luar dan terpisah dari kelas yang seharusnya menjadi @staticmethoddari.

Satu-satunya hal yang saya katakan membenarkan keberadaan mereka adalah kenyamanan. Metode statis umum digunakan dalam bahasa pemrograman populer lainnya, jadi mengapa tidak python? Jika Anda ingin membuat fungsi dengan perilaku yang sangat terkait dengan kelas tempat Anda membuatnya tetapi fungsi tersebut tidak benar-benar mengakses / mengubah data internal instance kelas dengan cara yang membenarkan konseptualisasi sebagai tipikal metode kelas itu lalu berikan a @staticmethoddi atasnya dan siapa pun yang membaca kode Anda akan segera belajar banyak tentang sifat metode dan hubungannya dengan kelas.

Satu hal yang kadang-kadang ingin saya lakukan adalah menempatkan fungsionalitas yang banyak digunakan kelas saya secara internal ke dalam private @staticmethod. Dengan cara itu saya tidak mengacaukan API yang diekspos oleh modul saya dengan metode yang tidak perlu dilihat oleh siapa pun yang menggunakan modul saya apalagi menggunakannya.

Garrett Gutierrez
sumber
0

Metode statis hampir tidak memiliki alasan untuk menggunakan Python. Anda menggunakan salah satu metode instance atau metode kelas.

def method(self, args):
    self.member = something

@classmethod
def method(cls, args):
    cls.member = something

@staticmethod
def method(args):
    MyClass.member = something
    # The above isn't really working
    # if you have a subclass
Georg Schölly
sumber
Anda mengatakan "hampir". Adakah tempat di mana mereka bisa menjadi lebih baik daripada alternatifnya?
Javier
@ Javier: Saya tidak bisa memikirkannya, tapi mungkin ada satu, mengapa metode itu dimasukkan ke dalam pustaka Python?
Georg Schölly
1
@ Javier, @Georg: Anda yakin sekali bahwa korpus Python tidak memiliki cruft.
Charles Merriam
-1: Jawaban ini tidak menghadirkan setiap kasus penggunaan staticmethodatau setiap penjelasan apa classmethodatau mengapa dan bagaimana hal itu "lebih baik" dari yang statis.
MestreLion
@CharlesMerriam: Tentu saja metode statis memiliki penggunaannya, jika tidak maka metode tersebut akan dihapus atau tidak digunakan lagi dalam Python 3 (di mana sebagian besar bagian warisan telah dihapus). Tidak ada satu kata pun yang menentang staticmethoddalam dokumen untuk mendukung klaim Anda bahwa itu cruft, atau klaim Georg yang classmethodharus digunakan sebagai gantinya).
MestreLion