Python hangi sınıf başlatılmadan çağırabilir statik yöntemleri olması mümkün, gibi:
ClassName.static_method()
Python hangi sınıf başlatılmadan çağırabilir statik yöntemleri olması mümkün, gibi:
ClassName.static_method()
Yanıtlar:
Evet, statik yöntem dekoratörünü kullanarak
class MyClass(object):
@staticmethod
def the_static_method(x):
print(x)
MyClass.the_static_method(2) # outputs 2
Bazı kodların, staticmethod
dekoratör yerine işlev olarak kullanarak statik bir yöntem tanımlamak için eski yöntemi kullanabileceğini unutmayın . Bu sadece eski Python sürümlerini (2.2 ve 2.3) desteklemeniz gerekiyorsa kullanılmalıdır.
class MyClass(object):
def the_static_method(x):
print(x)
the_static_method = staticmethod(the_static_method)
MyClass.the_static_method(2) # outputs 2
Bu ilk örnekle tamamen aynıdır (kullanarak @staticmethod
), sadece güzel dekoratör sözdizimini kullanmaz
Son olarak, staticmethod()
idareli kullanın ! Python'da statik yöntemlerin gerekli olduğu çok az durum vardır ve bunların ayrı bir "üst düzey" fonksiyonun daha net olduğu birçok kez kullanıldığını gördüm.
Aşağıdaki belgelerden kelimedir ::
Statik bir yöntem, örtük bir ilk argüman almaz. Statik bir yöntem bildirmek için şu deyimi kullanın:
class C: @staticmethod def f(arg1, arg2, ...): ...
@Staticmethod formu bir işlev dekoratörüdür - ayrıntılar için İşlev tanımlarındaki işlev tanımlarının açıklamasına bakın.
Sınıfta (örneğin
C.f()
) veya bir örnekte (örneğin) çağrılabilirC().f()
. Örnek, sınıfı dışında yok sayılır.Python'daki statik yöntemler Java veya C ++ 'da bulunanlara benzer. Daha gelişmiş bir konsept için bkz
classmethod()
.Statik yöntemleri hakkında daha fazla bilgi için, standart tip hiyerarşisine belgelere bakın standart tip hiyerarşisi .
2.2 sürümündeki yenilikler.
2.4 sürümünde değiştirildi: İşlev dekoratörü sözdizimi eklendi.
ClassName.methodName()
, statik bir yöntemmiş gibi çağırabileceksiniz ve sonra self
yönteme hayır sağlanacaktır. Dediğiniz gibi aynı zamanda bu yöntemi çağırmak için, hala mümkün olacaktır ClassInstance.methodName()
, ve self
ne olursa olsun adın, ilk parametre olarak sağlanacaktır.
Bence Steven aslında haklı . Orijinal soruyu cevaplamak için, bir sınıf yöntemi ayarlamak amacıyla, ilk argümanın çağıran bir örnek olmayacağını varsayalım ve yalnızca yöntemi sınıftan çağırdığınızdan emin olun.
(Bu yanıtın Python 3.x'e atıfta bulunduğunu unutmayın. Python 2.x'te TypeError
, yöntemi sınıfın kendisinde çağırmak için bir alacaksınız .)
Örneğin:
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)
Bu kodda, "rollCall" yöntemi, ilk bağımsız değişkenin bir örnek olmadığını varsayar (sınıf yerine bir örnek tarafından çağrılmış gibi). "RollCall" bir örnek yerine sınıftan çağrıldığı sürece kod düzgün çalışır. Bir örnekten "rollCall" ifadesini çağırmaya çalışırsak, örneğin:
rex.rollCall(-1)
ancak, iki bağımsız değişken göndereceği için bir özel durum oluşmasına neden olur: kendisi ve -1 ve "rollCall" yalnızca bir bağımsız değişkeni kabul edecek şekilde tanımlanır.
Bu arada, rex.rollCall () doğru sayıda bağımsız değişken gönderir, ancak işlev n'nin sayısal olmasını beklediğinde artık bir Dog örneğini (yani rex) temsil ettiği için bir istisnanın yükselmesine neden olur.
Dekorasyon burada devreye giriyor: "rollCall" yöntemini
@staticmethod
daha sonra, yöntemin statik olduğunu açıkça belirterek, bunu bir örnekten bile çağırabiliriz. Şimdi,
rex.rollCall(-1)
çalışır. Bir yöntem tanımından önce @staticmethod eklenmesi, bir örneğin kendisini bağımsız değişken olarak göndermesini durdurur.
@Staticmethod satırı açıklanmış ve açıklanmamış aşağıdaki kodu deneyerek bunu doğrulayabilirsiniz.
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()
veya kullanıyorum type(my_t_instance).my_static_method()
, çünkü bu daha net ve statik bir yöntem çağırdığımı hemen belli ediyor.
Evet, statik yöntem dekoratörüne bakın:
>>> class C:
... @staticmethod
... def hello():
... print "Hello World"
...
>>> C.hello()
Hello World
@staticmethod
Dekoratörü kullanmanıza gerek yok . Sadece bir yöntem bildirmek (self parametresini beklemez) ve sınıftan çağırın. Dekoratör sadece bir örnekten de çağırabilmeniz için oradadır (yapmak istediğiniz şey değildi)
Çoğunlukla, sadece fonksiyonları kullanırsınız ...
class Dummy: def static1(): print "hello from static1" @staticmethod def static2(): print "hello from static2" Dummy.static2() Dummy.static1()
Çıktı: merhaba static2 Traceback <en son çağrı son>: Dosya "ll.py", satır 46, <module> Dummy.static1 () TypeError: unbound yöntemi static1 () olmalıdır Dummy örneği ile ilk argüman olarak çağrıldı (bunun yerine hiçbir şey yok)
self
söylemediğiniz sürece ilk argüman olarak geçecektir . (bkz: dekoratör)
self
nasıl çağrıldığına bağlı olarak uygun bir ref ekler . Test örneği: pastebin.com/12DDV7DB .
staticmethod
Dekoratör bir sınıf ve bir örneği (bir örneği işlev çağrısının bu çözelti başarısız) her iki fonksiyonu açmasına olanak sağlar.
class C: def callme(): print('called'); C.callme()
Python'da statik yöntemler?
Python statik yöntemler olması mümkün olduğu gibi, bir sınıf başlatmadan onları çağırabilirsiniz, örneğin:
ClassName.StaticMethod()
Evet, statik yöntemler şu şekilde oluşturulabilir ( yöntemler için CamelCase yerine alt çizgi kullanmak biraz daha Pythonic olsa da ):
class ClassName(object):
@staticmethod
def static_method(kwarg1=None):
'''return a value that is a function of kwarg1'''
Yukarıdaki dekoratör sözdizimini kullanır. Bu sözdizimi şuna eşdeğerdir:
class ClassName(object):
def static_method(kwarg1=None):
'''return a value that is a function of kwarg1'''
static_method = staticmethod(static_method)
Bu, aynen tanımladığınız gibi kullanılabilir:
ClassName.static_method()
Statik bir yöntemin yerleşik bir örneği, Python 2'deki modülde str.maketrans()
bir işlev string
olan Python 3'tedir.
Açıkladığınız gibi kullanılabilecek bir başka seçenek de classmethod
, farkın, sınıf yönteminin sınıfı örtük bir ilk argüman olarak alması ve alt sınıflı olması durumunda, alt sınıfı örtük ilk argüman olarak almasıdır.
class ClassName(object):
@classmethod
def class_method(cls, kwarg1=None):
'''return a value that is a function of the class and kwarg1'''
Bunun cls
ilk argüman için gerekli bir isim olmadığını, ancak çoğu deneyimli Python kodlayıcısının başka bir şey kullanırsanız bunun kötü bir şekilde yapıldığını düşünün.
Bunlar tipik olarak alternatif kurucular olarak kullanılır.
new_instance = ClassName.class_method()
Yerleşik bir örnek dict.fromkeys()
:
new_dict = dict.fromkeys(['key1', 'key2'])
Statik yöntem nesnelerinin nasıl davrandığının özelliklerinin yanı sıra, modül düzeyinde kodunuzu düzenleme konusunda onlarla çarpabileceğiniz belirli bir güzellik vardır.
# 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
Şimdi, bazı bileşenlerin kullanılması gerektiği bağlamda biraz daha sezgisel ve kendi kendini belgeleme haline geliyor ve farklı test senaryolarını adlandırmak ve test modüllerinin saflar için testler altındaki gerçek modüllerle nasıl eşleştiğine dair basit bir yaklaşıma sahip olmak için ideal bir şekilde ortaya çıkıyor .
Sık sık bu yaklaşımı bir projenin yardımcı kodunu düzenlemeye uygun buluyorum. Çoğu zaman, insanlar hemen acele eder ve bir utils
paket oluşturur ve bunlardan biri 120 LOC ve geri kalanları en iyi iki düzine LOC olan 9 modül ile sonuçlanır. Bununla başlamayı ve bir pakete dönüştürmeyi ve sadece onları gerçekten hak eden hayvanlar için modüller oluşturmayı tercih ediyorum:
# 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
Belki de en basit seçenek, bu işlevleri sınıfın dışına koymaktır:
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"
Bu yöntem kullanılarak, dahili nesne durumunu değiştiren veya kullanan (yan etkileri olan) işlevler sınıfta tutulabilir ve yeniden kullanılabilir yardımcı program işlevleri dışarıya taşınabilir.
Diyelim ki bu dosyanın adı dogs.py
. Bunları kullanmak için telefon dogs.barking_sound()
yerine arama yaparsınız dogs.Dog.barking_sound
.
Sınıfın bir parçası olmak için gerçekten statik bir yönteme ihtiyacınız varsa, staticmethod dekoratörünü kullanabilirsiniz .
Dolayısıyla statik yöntemler, bir sınıfın nesnesini yaratmadan çağrılabilecek yöntemlerdir. Örneğin :-
@staticmethod
def add(a, b):
return a + b
b = A.add(12,12)
print b
Yukarıdaki örnekte yöntem add
, A
nesne adı tarafından değil, sınıf adıyla çağrılır .
Python Statik yöntemler iki şekilde oluşturulabilir.
Staticmethod () kullanma
class Arithmetic:
def add(x, y):
return x + y
# create add static method
Arithmetic.add = staticmethod(Arithmetic.add)
print('Result:', Arithmetic.add(15, 10))
Çıktı:
Sonuç: 25
@Staticmethod kullanma
class Arithmetic:
# create add static method
@staticmethod
def add(x, y):
return x + y
print('Result:', Arithmetic.add(15, 10))
Çıktı:
Sonuç: 25
Zaman zaman bu soru ile karşılaşıyorum. Sevdiğim kullanım örneği ve örneği:
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']
>>>
Sınıf cmath nesnesi oluşturmak mantıklı değildir, çünkü cmath nesnesinde durum yoktur. Bununla birlikte, cmath, bir şekilde ilişkili olan yöntemlerin bir koleksiyonudur. Yukarıdaki örneğimde, cmath içindeki tüm işlevler bir şekilde karmaşık sayılar üzerinde etkili olur.
@staticmethod
İlkself
parametreden kaçınabildiğinizde neden dekorasyon ekleyerek veya bir işlev işaretçisi kullanarak ? Bir nesne içina
,a.your_static_method()
diğer dillerde izin verilen arayamazsınız, ancak yine de kötü bir uygulama olarak kabul edilir ve derleyici her zaman bunun hakkında uyarır