Python'da statik yöntemler?


1719

Python hangi sınıf başlatılmadan çağırabilir statik yöntemleri olması mümkün, gibi:

ClassName.static_method()

Yanıtlar:


2026

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, staticmethoddekoratö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ılabilir C().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.


15
@staticmethodİlk selfparametreden kaçınabildiğinizde neden dekorasyon ekleyerek veya bir işlev işaretçisi kullanarak ? Bir nesne için a, 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
SomethingSomething

1
Python 2.7.12 kullanıyorum, @staticmethod dekoratör ile tanımlanan ilk statik yöntemi çağıramıyorum. Onun givin hatası: TypeError: '
staticmethod

Supratim Samantray, emin misin? çünkü burada 2.4'ten sonra kullanılabileceği açıkça belirtiliyor.
realslimshanky

11
@SomethingSomething, "self" değişken adını kullanmazsanız, ancak dekoratörü eklemezseniz, ilk argüman örn. Arg1, self örneğine başvuru olacaktır. Benlik adı sadece bir ibadettir.
George Moutsopoulos

1
@GeorgeMoutsopoulos - genel olarak kabul edildi. Ancak - yine de yöntemi ClassName.methodName(), statik bir yöntemmiş gibi çağırabileceksiniz ve sonra selfyö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 selfne olursa olsun adın, ilk parametre olarak sağlanacaktır.
SomethingSomething

220

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)

8
İlk örnek (@staticmethod olmadan sınıfa çağırmak) Python 2.7'de işe yaramıyor. "TypeError: unbound yöntemi rollCall () ilk bağımsız değişken olarak Dog örneği ile çağrılmalıdır (bunun yerine int örneği var)"
tba

2
Bu çalışmıyor. Hem Dog.rollCall (-1) hem de rex.rollCall (-1) aynı şekilde TypeError: unbound method rollCall() must be called with Dog instance as first argument (got int instance instead)
dönüyor

3
@MestreLion Bunun büyük bir fayda olmadığını düşünüyorum, çünkü yaptığı tek şey statik ve örnek yöntemleri karıştırmak ve birini diğerine benzetmek. Bir yöntemin statik olduğunu biliyorsanız, statik yönteme erişmeniz gerekir. Yöntemin örneğinize ihtiyacı olmaması veya örneğini kullanmaması, yöntemi kullandığınız her yerde kendiliğinden anlaşılır olmalıdır. Her zaman 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.
Asad Saeeduddin


54

@staticmethodDekoratö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 ...


Bu, python 2.5.2 için çalışmaz 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)
Mahori

7
Bu bir sınıf içinde çalışmaz. Python, selfsöylemediğiniz sürece ilk argüman olarak geçecektir . (bkz: dekoratör)
Navin

9
Aslında bu 2.7'de yanlış ve 3.X itibariyle yasal (3.2'de iyi test edildi). Yani sen olamaz aşağıda 2.7 ve içinde @staticmethod dekoratör olmadan bir sınıf bağlamında bir yöntemini çağırın. 3.2 'de çalışır ve selfnasıl çağrıldığına bağlı olarak uygun bir ref ekler . Test örneği: pastebin.com/12DDV7DB .
spinkus

2
Teknik olarak doğru, ama korkunç bir çözüm. staticmethodDekoratö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.
Ethan Furman

bir yöntem, nokta gösterimi kullanılarak bir nesnenin diğer herhangi bir niteliği gibi çağrılabilir. class C: def callme(): print('called'); C.callme()
pouya

32

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 stringolan 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 clsilk 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'])

11

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

10

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 .


1

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, Anesne adı tarafından değil, sınıf adıyla çağrılır .


-3

Python Statik yöntemler iki şekilde oluşturulabilir.

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

  1. @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


Sadece örnekler verdiniz ve bunu nasıl yapabileceğinizi paylaştınız . Yöntemlerin ne anlama geldiğini açıklamadınız.
zixuan

-4

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.


Soruyu cevaplamadınız, bunun yerine bir örnek verdiniz.
zixuan
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.