Apakah mungkin untuk memiliki metode statis di Python yang dapat saya panggil tanpa menginisialisasi kelas, seperti:
ClassName.static_method()
Apakah mungkin untuk memiliki metode statis di Python yang dapat saya panggil tanpa menginisialisasi kelas, seperti:
ClassName.static_method()
Jawaban:
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 staticmethod
sebagai 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 (sepertiC().f()
). Instance diabaikan kecuali untuk kelasnya.Metode statis dengan Python mirip dengan yang ditemukan di Java atau C ++. Untuk konsep yang lebih maju, lihat
classmethod()
.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.
ClassName.methodName()
, seolah-olah itu adalah yang statis, dan kemudian tidak self
akan diberikan ke metode tersebut. Seperti yang Anda katakan, masih mungkin memanggil metode ini juga ClassInstance.methodName()
, dan self
akan diberikan sebagai parameter pertama, apa pun namanya.
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)
TypeError: unbound method rollCall() must be called with Dog instance as first argument (got int instance instead)
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.
Ya, lihat dekorator metode statis :
>>> class C:
... @staticmethod
... def hello():
... print "Hello World"
...
>>> C.hello()
Hello World
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 ...
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)
self
dianggap sebagai argumen pertama kecuali Anda mengatakannya untuk tidak melakukannya. (lihat: dekorator)
self
referensi secara tepat tergantung pada bagaimana namanya. Test case: pastebin.com/12DDV7DB .
staticmethod
dekorator memungkinkan seseorang untuk memanggil fungsi pada kedua kelas dan sebuah contoh (solusi ini gagal saat memanggil fungsi pada contoh).
class C: def callme(): print('called'); C.callme()
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 string
modul 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 cls
ini 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'])
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 utils
paket 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
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.
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 add
dipanggil dengan nama kelas A
bukan nama objek.
Metode Python Static dapat dibuat dengan dua cara.
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
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
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.
@staticmethod
dekorasi atau menggunakan pointer fungsi, ketika Anda dapat dengan mudah menghindariself
parameter pertama ? Nah, untuk suatu objeka
, Anda tidak akan bisa menelepona.your_static_method()
, yang diizinkan dalam bahasa lain, tetapi itu tetap dianggap praktik yang buruk dan kompilator selalu memperingatkannya