Metode statis dengan Python?

1719

Apakah mungkin untuk memiliki metode statis di Python yang dapat saya panggil tanpa menginisialisasi kelas, seperti:

ClassName.static_method()
Joan Venge
sumber

Jawaban:

2026

Yap, menggunakan dekorator metode statis

class MyClass(object):
    @staticmethod
    def the_static_method(x):
        print(x)

MyClass.the_static_method(2)  # outputs 2

Perhatikan bahwa beberapa kode mungkin menggunakan metode lama mendefinisikan metode statis, menggunakan staticmethodsebagai fungsi daripada dekorator. Ini hanya boleh digunakan jika Anda harus mendukung versi Python kuno (2.2 dan 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

Ini sepenuhnya identik dengan contoh pertama (menggunakan @staticmethod), hanya saja tidak menggunakan sintaksis dekorator yang bagus

Akhirnya, gunakan staticmethod()hemat! Ada beberapa situasi di mana metode statis diperlukan dalam Python, dan saya telah melihat mereka menggunakan berkali-kali di mana fungsi "tingkat atas" yang terpisah akan lebih jelas.


Berikut ini kata demi kata dari dokumentasi :

Metode statis tidak menerima argumen pertama implisit. Untuk mendeklarasikan metode statis, gunakan idiom ini:

class C:
    @staticmethod
    def f(arg1, arg2, ...): ...

Bentuk @staticmethod adalah dekorator fungsi - lihat deskripsi definisi fungsi di definisi Fungsi untuk detail.

Itu dapat dipanggil baik di kelas (seperti C.f() ) atau pada instance (seperti C().f()). Instance diabaikan kecuali untuk kelasnya.

Metode statis dengan Python mirip dengan yang ditemukan di Java atau C ++. Untuk konsep yang lebih maju, lihatclassmethod() .

Untuk informasi lebih lanjut tentang metode statis, lihat dokumentasi tentang hierarki jenis standar di Hirarki tipe standar .

Baru di versi 2.2.

Diubah dalam versi 2.4: Sintaks dekorator fungsi ditambahkan.

dbr
sumber
15
Mengapa menambahkan @staticmethoddekorasi atau menggunakan pointer fungsi, ketika Anda dapat dengan mudah menghindari selfparameter pertama ? Nah, untuk suatu objek a, Anda tidak akan bisa menelepon a.your_static_method(), yang diizinkan dalam bahasa lain, tetapi itu tetap dianggap praktik yang buruk dan kompilator selalu memperingatkannya
SomethingSomething
1
Saya menggunakan python 2.7.12, dengan dekorator @staticmethod saya tidak dapat memanggil metode statis pertama yang ditentukan. Galat givinnya
Supratim Samantray
Supratim Samantray, apakah Anda yakin? karena di sini dinyatakan dengan jelas bahwa itu dapat digunakan setelah 2.4.
realslimshanky
11
@ Sesuatu. Sesuatu, jika Anda tidak menggunakan nama variabel "diri", tetapi jangan tambahkan dekorator, argumen pertama misalnya arg1 masih akan menjadi referensi ke contoh diri. Nama diri hanya sebuah konvensi.
George Moutsopoulos
1
@GeorgeMoutsopoulos - disepakati secara umum. Tetapi - Anda tetap dapat memanggil metode tersebut ClassName.methodName(), seolah-olah itu adalah yang statis, dan kemudian tidak selfakan diberikan ke metode tersebut. Seperti yang Anda katakan, masih mungkin memanggil metode ini juga ClassInstance.methodName(), dan selfakan diberikan sebagai parameter pertama, apa pun namanya.
Sesuatu Sesuatu
220

Saya pikir Steven sebenarnya benar . Untuk menjawab pertanyaan awal, maka, untuk mengatur metode kelas, cukup berasumsi bahwa argumen pertama tidak akan menjadi contoh panggilan, dan kemudian pastikan bahwa Anda hanya memanggil metode dari kelas.

(Perhatikan bahwa jawaban ini merujuk ke Python 3.x. Dalam Python 2.x Anda akan mendapatkan TypeError untuk memanggil metode pada kelas itu sendiri.)

Sebagai contoh:

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)

Dalam kode ini, metode "rollCall" mengasumsikan bahwa argumen pertama bukanlah turunan (seperti jika dipanggil oleh turunan alih-alih kelas). Selama "rollCall" dipanggil dari kelas alih-alih sebuah instance, kode akan berfungsi dengan baik. Jika kami mencoba memanggil "rollCall" dari sebuah instance, misalnya:

rex.rollCall(-1)

Namun, itu akan menyebabkan pengecualian untuk dimunculkan karena akan mengirim dua argumen: itu sendiri dan -1, dan "rollCall" hanya didefinisikan untuk menerima satu argumen.

Secara kebetulan, rex.rollCall () akan mengirimkan jumlah argumen yang benar, tetapi juga akan menyebabkan pengecualian yang muncul karena sekarang n akan mewakili turunan Dog (yaitu, rex) ketika fungsi mengharapkan n menjadi numerik.

Di sinilah dekorasi datang: Jika kita mendahului metode "rollCall" dengan

@staticmethod

kemudian, dengan secara eksplisit menyatakan bahwa metode ini statis, kita bahkan dapat menyebutnya dari sebuah instance. Sekarang,

rex.rollCall(-1)

akan bekerja. Penyisipan @staticmethod sebelum definisi metode, kemudian, menghentikan instance mengirimkan dirinya sebagai argumen.

Anda dapat memverifikasi ini dengan mencoba kode berikut dengan dan tanpa garis @staticmethod dikomentari.

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)
Richard Ambler
sumber
8
Contoh pertama (memanggil kelas tanpa @staticmethod) tidak berfungsi untuk saya di Python 2.7. Saya mendapatkan "TypeError: metode terikat rollCall () harus dipanggil dengan turunan Dog sebagai argumen pertama (mendapat int instance sebagai gantinya)"
tba
2
Ini tidak bekerja. Baik Dog.rollCall (-1) dan rex.rollCall (-1) mengembalikan hal yang samaTypeError: unbound method rollCall() must be called with Dog instance as first argument (got int instance instead)
Mittenchops
3
@MestreLion Saya pikir ini bukan manfaat besar, karena semua yang dilakukannya adalah mengacaukan metode statis dan contoh dan membuat satu terlihat seperti yang lain. Jika Anda tahu metode itu statis, Anda harus mengaksesnya sebagai metode statis. Fakta bahwa metode tersebut tidak memerlukan atau menggunakan instance Anda harus jelas di mana pun Anda menggunakan metode tersebut. Saya selalu menggunakan T.my_static_method()atau type(my_t_instance).my_static_method(), karena ini lebih jelas dan membuatnya segera jelas bahwa saya memanggil metode statis.
Asad Saeeduddin
81

Ya, lihat dekorator metode statis :

>>> class C:
...     @staticmethod
...     def hello():
...             print "Hello World"
...
>>> C.hello()
Hello World
Paolo Bergantino
sumber
54

Anda tidak benar - benar perlu menggunakan @staticmethod dekorator. Hanya mendeklarasikan metode (yang tidak mengharapkan parameter mandiri) dan memanggilnya dari kelas. Dekorator hanya ada jika Anda ingin dapat memanggilnya dari sebuah instance juga (yang bukan itu yang ingin Anda lakukan)

Sebagian besar, Anda hanya menggunakan fungsi ...

hichris123
sumber
Ini tidak akan berfungsi untuk python 2.5.2 class Dummy: def static1(): print "hello from static1" @staticmethod def static2(): print "hello from static2" Dummy.static2() Dummy.static1() Output: halo dari static2 Traceback <panggilan terakhir terakhir>: File "ll.py", baris 46, dalam <module> Dummy.static1 () TypeError: unbound method static1 () harus dipanggil dengan contoh Dummy sebagai argumen pertama (tidak mendapatkan apa-apa)
Mahori
7
Ini tidak berfungsi di dalam kelas. Python akan selfdianggap sebagai argumen pertama kecuali Anda mengatakannya untuk tidak melakukannya. (lihat: dekorator)
Navin
9
Sebenarnya ini salah di 2.7 dan legal pada 3.X (diuji dengan baik di 3.2). Itu Anda tidak bisa memanggil metode dari konteks kelas tanpa dekorator @staticmethod di 2.7 dan di bawah. Dalam 3.2 ia bekerja dan akan memasukkan selfreferensi secara tepat tergantung pada bagaimana namanya. Test case: pastebin.com/12DDV7DB .
spinkus
2
Secara teknis akurat, tetapi solusi yang mengerikan. The staticmethoddekorator memungkinkan seseorang untuk memanggil fungsi pada kedua kelas dan sebuah contoh (solusi ini gagal saat memanggil fungsi pada contoh).
Ethan Furman
sebuah metode dapat dipanggil seperti atribut lain dari objek yang menggunakan notasi titik. class C: def callme(): print('called'); C.callme()
pouya
32

Metode statis dengan Python?

Apakah mungkin untuk memiliki metode statis di Python sehingga saya dapat memanggil mereka tanpa menginisialisasi kelas, seperti:

ClassName.StaticMethod()

Ya, metode statis dapat dibuat seperti ini (walaupun sedikit lebih Pythonic untuk menggunakan garis bawah daripada CamelCase untuk metode):

class ClassName(object):

    @staticmethod
    def static_method(kwarg1=None):
        '''return a value that is a function of kwarg1'''

Di atas menggunakan sintaksis dekorator. Sintaks ini setara dengan

class ClassName(object):

    def static_method(kwarg1=None):
        '''return a value that is a function of kwarg1'''

    static_method = staticmethod(static_method)

Ini dapat digunakan seperti yang Anda gambarkan:

ClassName.static_method()

Contoh bawaan dari metode statis adalah str.maketrans()di Python 3, yang merupakan fungsi dalam stringmodul di Python 2.


Pilihan lain yang dapat digunakan seperti yang Anda gambarkan adalah classmethod, perbedaannya adalah bahwa metode class mendapatkan kelas sebagai argumen pertama implisit, dan jika subclass, maka ia mendapatkan subclass sebagai argumen pertama implisit.

class ClassName(object):

    @classmethod
    def class_method(cls, kwarg1=None):
        '''return a value that is a function of the class and kwarg1'''

Perhatikan bahwa clsini bukan nama yang diperlukan untuk argumen pertama, tetapi coders Python paling berpengalaman akan menganggapnya buruk jika Anda menggunakan hal lain.

Ini biasanya digunakan sebagai konstruktor alternatif.

new_instance = ClassName.class_method()

Contoh bawaan adalah dict.fromkeys():

new_dict = dict.fromkeys(['key1', 'key2'])
Aaron Hall
sumber
11

Selain kekhasan bagaimana objek metode statis berperilaku, ada jenis kecantikan tertentu yang bisa Anda singgung ketika mengatur kode level modul Anda.

# 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

Sekarang menjadi sedikit lebih intuitif dan mendokumentasikan diri sendiri di mana konteks komponen tertentu dimaksudkan untuk digunakan dan ideal untuk penamaan kasus uji yang berbeda serta memiliki pendekatan langsung tentang bagaimana modul tes memetakan ke modul yang sebenarnya di bawah tes untuk puritan .

Saya sering merasa layak untuk menerapkan pendekatan ini untuk mengatur kode utilitas proyek. Cukup sering, orang langsung terburu-buru dan membuat utilspaket dan berakhir dengan 9 modul yang satu memiliki 120 LOC dan sisanya adalah dua lusin LOC terbaik. Saya lebih suka memulai dengan ini dan mengubahnya menjadi sebuah paket dan membuat modul hanya untuk binatang buas yang benar-benar layak mendapatkannya:

# 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
Filip Dupanović
sumber
10

Mungkin opsi paling sederhana adalah dengan menempatkan fungsi-fungsi itu di luar kelas:

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"

Dengan menggunakan metode ini, fungsi-fungsi yang memodifikasi atau menggunakan keadaan objek internal (memiliki efek samping) dapat disimpan di kelas, dan fungsi utilitas yang dapat digunakan kembali dapat dipindahkan ke luar.

Katakanlah file ini dipanggil dogs.py. Untuk menggunakan ini, Anda akan menelepon dogs.barking_sound()bukan dogs.Dog.barking_sound.

Jika Anda benar-benar membutuhkan metode statis untuk menjadi bagian dari kelas, Anda dapat menggunakan staticmethod dekorator.

Matt Woelk
sumber
1

Jadi, metode statis adalah metode yang dapat dipanggil tanpa membuat objek kelas. Sebagai contoh :-

    @staticmethod
    def add(a, b):
        return a + b

b = A.add(12,12)
print b

Dalam contoh metode di atas adddipanggil dengan nama kelas Abukan nama objek.

Aman Raheja
sumber
-3

Metode Python Static dapat dibuat dengan dua cara.

  1. Menggunakan 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))

Keluaran:

Hasil: 25

  1. Menggunakan @staticmethod

    class Arithmetic:
    
    # create add static method
    @staticmethod
    def add(x, y):
        return x + y
    
    print('Result:', Arithmetic.add(15, 10))

Keluaran:

Hasil: 25

Pembuat kode
sumber
Anda baru saja memberikan contoh dan membagikan cara bagaimana Anda bisa melakukannya. Anda tidak menjelaskan apa arti metode tersebut.
zixuan
-4

Saya menemukan pertanyaan ini dari waktu ke waktu. Kasus penggunaan dan contoh yang saya sukai adalah:

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

Tidak masuk akal untuk membuat objek kelas cmath, karena tidak ada keadaan dalam objek cmath. Namun, cmath adalah kumpulan metode yang semuanya terkait dalam beberapa cara. Dalam contoh saya di atas, semua fungsi dalam cmath bekerja pada bilangan kompleks dengan beberapa cara.

pengguna1928764
sumber
Anda tidak menjawab pertanyaan tetapi Anda memberikan contoh.
zixuan