zfill Python中的靜態方法?




zfill in python (7)

是否有可能在Python中有靜態方法,所以我可以在不初始化類的情況下調用它們,如:

ClassName.StaticMethod ( )

我不時遇到這個問題。 我喜歡的用例和例子是:

[email protected]:/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']
>>> 

創建類cmath的對像是沒有意義的,因為cmath對像中沒有狀態。 但是,cmath是以某種方式關聯的所有方法的集合。 在上面的例子中,cmath中的所有函數都以某種方式對複數進行操作。


我認為史蒂文其實是對的。 為了回答最初的問題,為了建立一個類方法,簡單地假定第一個參數不會是一個調用實例,然後確保只調用該方法。

(請注意,這個答案是指Python 3.x.在Python 2.x中,你會得到一個TypeError來調用類本身的方法。)

例如:

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)

在這段代碼中,“rollCall”方法假定第一個參數不是實例(如果它是由實例而不是類調用的話)。 只要從類中調用“rollCall”而不是實例,代碼就可以正常工作。 如果我們試圖從一個實例中調用“rollCall”,例如:

rex.rollCall(-1)

然而,它會引發異常,因為它會發送兩個參數:本身和-1,而“rollCall”僅被定義為接受一個參數。

順便說一句,rex.rollCall()會發送正確數量的參數,但也會導致引發異常,因為當函數期望n是數字時,n將代表Dog實例(即rex)。

這是裝飾進入的地方:如果我們在“rollCall”方法之前

@staticmethod

那麼通過明確指出該方法是靜態的,我們甚至可以從一個實例中調用它。 現在,

rex.rollCall(-1)

會工作。 在方法定義之前插入@staticmethod,然後阻止實例將其自身作為參數進行發送。

您可以通過嘗試使用以下代碼來驗證此情況,並將@staticmethod行註釋掉。

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)

是的,使用staticmethod裝飾器

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

MyClass.the_static_method(2) # outputs 2

請注意,某些代碼可能使用靜態方法的舊方法,使用staticmethod作為函數而不是裝飾器。 這應該只用於如果你必須支持古代版本的Python(2.2和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

這與第一個例子完全相同(使用@staticmethod ),只是沒有使用好的裝飾器語法

最後,謹慎使用staticmethod ! 有很少的情況需要在Python中使用靜態方法,並且在單獨的“頂層”函數更清晰的情況下,我已經看到它們被多次使用。

staticmethod ::

靜態方法不會收到隱式的第一個參數。 要聲明一個靜態方法,使用這個習慣用法:

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

@staticmethod表單是一個函數decorator - 有關詳細信息,請參閱函數定義中函數定義的描述。

它可以在類(如Cf() )或實例(如C().f() )上調用。 該實例被忽略,除了它的類。

Python中的靜態方法類似於Java或C ++中的方法。 有關更高級的概念,請參見classmethod()

有關靜態方法的更多信息,請參閱標準類型層次結構中標準類型層次結構的文檔。

2.2版本中的新功能。

在版本2.4中更改:添加了函數裝飾器語法。


是的,請查看staticmethod裝飾器:

>>> class C:
...     @staticmethod
...     def hello():
...             print "Hello World"
...
>>> C.hello()
Hello World

也許最簡單的選擇就是將這些功能放在課堂之外:

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"

使用這種方法,修改或使用內部對象狀態(有副作用)的函數可以保存在類中,並且可重用的實用函數可以移出。

假設這個文件叫做dogs.py 要使用這些,你可以調用dogs.barking_sound()而不是dogs.Dog.barking_sound

如果你真的需要一個靜態方法來成為類的一部分,你可以使用staticmethod裝飾器。


你並不需要使用@staticmethod裝飾器。 只要聲明一個方法(不期望自我參數)並從類中調用它。 如果你想從一個實例中調用它,裝飾器只在那裡(這不是你想要做的)

大多數情況下,你只是使用函數,但...


除了靜態方法對象的特性之外 ,當組織模塊級代碼時,您可以利用它們攻擊某種美感。

# 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

它現在變得更加直觀和自我記錄,在這種情況下,某些組件將被使用,並且理想地命名為不同的測試用例,以及直接測試模塊如何映射到純粹主義者測試下的實際模塊。

我經常發現將這種方法應用於組織項目的實用程序代碼是可行的。 通常情況下,人們會立即搶購併創建一個utils軟件包,最終得到9個模塊,其中一個模塊的LOC為120,其餘的LOC為最多兩個LOC。 我更喜歡從這開始,將它轉換為一個包,並為真正值得他們的野獸創建模塊:

# 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




static-methods