Статические методы в Python?

Возможно ли иметь статические методы в Python, чтобы я мог их вызывать без инициализации класса, например:

ClassName.StaticMethod ( )
+1558
09 апр. '09 в 21:23
источник поделиться
11 ответов

Да, используя staticmethod decorator

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 необходимы статические методы, и я видел их много раз, когда отдельная функция "верхнего уровня" была бы более ясной.


Дословное из документации::

Статический метод не получает неявный первый аргумент. Чтобы объявить статический метод, используйте эту идиому:

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

Форма @staticmethod представляет собой функцию decorator - см. описание определений функций в Определения функций для деталей.

Он может быть вызван либо в классе (например, C.f()), либо в экземпляре (например, C().f()). Экземпляр игнорируется, за исключением его класса.

Статические методы в Python аналогичны тем, которые существуют в Java или С++. Для более продвинутой концепции см. classmethod().

Дополнительные сведения о статических методах см. в документации по иерархии стандартного типа в Стандартная иерархия типов.

Новое в версии 2.2.

Изменено в версии 2.4: Добавлен синтаксис конструктора функций.

+1869
09 апр. '09 в 21:24
источник

Я думаю, что Стивен на самом деле прав. Чтобы ответить на исходный вопрос, затем, чтобы настроить метод класса, просто предположите, что первый аргумент не будет вызывающим экземпляром, а затем убедитесь, что вы вызываете метод только из класса.

(Обратите внимание, что этот ответ относится к 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 будет представлять экземпляр Dog (т.е. Rex), когда функция ожидает, что n будет численным.

Здесь происходит декорация: если мы предшествуем методу rollCall,

@staticmethod

то, явно указывая, что метод статичен, мы можем даже вызвать его из экземпляра. Теперь,

rex.rollCall(-1)

должно сработать. Таким образом, вставка метода @static перед определением метода останавливает экземпляр от отправки себя в качестве аргумента.

Вы можете проверить это, попробовав следующий код с и без строки @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)
+197
18 апр. '12 в 9:16
источник

Да, посмотрите staticmethod decorator:

>>> class C:
...     @staticmethod
...     def hello():
...             print "Hello World"
...
>>> C.hello()
Hello World
+77
09 апр. '09 в 21:24
источник

Вам действительно не нужно использовать декоратор @staticmethod. Просто объявляя метод (который не ожидает параметра self) и вызывает его из класса. Декоратор только там, если вы хотите иметь возможность вызвать его из экземпляра (что не было тем, что вы хотели сделать)

В основном, вы просто используете функции, хотя...

+46
10 апр. '09 в 16:00
источник

Статические методы в Python?

Возможно ли иметь статические методы в Python, чтобы я мог их назвать без инициализации класса, например:

ClassName.StaticMethod()

Да, статические методы могут быть созданы как это (хотя немного более Pythonic использовать символы подчеркивания вместо методов CamelCase для методов):

class ClassName(object):

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

В приведенном выше примере используется синтаксис декоратора. Этот синтаксис эквивалентен

class ClassName(object):

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

    static_method = staticmethod(static_method)

Это можно использовать так, как вы описали:

ClassName.static_method()

Встроенным примером статического метода является str.maketrans() в Python 3, который был функцией в модуле string в Python 2.


Другим вариантом, который можно использовать при описании, является classmethod, различие заключается в том, что classmethod получает класс как неявный первый аргумент, и если он подклассифицирован, то он получает подкласс как неявный первый аргумент.

class ClassName(object):

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

Обратите внимание, что cls не является обязательным именем для первого аргумента, но большинство опытных кодировщиков Python будут считать это плохо выполненным, если вы используете что-то еще.

Они обычно используются в качестве альтернативных конструкторов.

new_instance = ClassName.class_method()

Встроенный пример dict.fromkeys():

new_dict = dict.fromkeys(['key1', 'key2'])
+32
24 янв. '15 в 4:34
источник

Возможно, самый простой вариант - просто поставить эти функции вне класса:

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.

+9
30 июл. '14 в 16:10
источник

Помимо особенностей того, как объекты статического метода ведут себя, есть определенная красота, с которой вы можете столкнуться, когда дело доходит до организации ваш код на уровне модуля.

# 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 модулей, из которых 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
+9
29 дек. '12 в 19:47
источник

Итак, статические методы - это методы, которые можно вызывать без создания объекта класса. Например :-

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

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

В приведенном выше примере метод add вызывается именем класса A не именем объекта.

0
04 июн. '19 в 13:28
источник

Статические методы Python могут быть созданы двумя способами.

  1. Использование 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))
    

Выход:

Результат: 25

  1. Использование @staticmethod

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

Выход:

Результат: 25

-2
20 дек. '18 в 9:04
источник

В Python 3:

Вот еще один хороший способ использовать нестатические методы, так как они были статическими.

class Account:
# here is the main class

# a non-static method
def login(self, url, email, password):
    # as a convention self is passed as a 
    # placeholder for the class Object itself

    self.login_url = url
    self.user_email = email
    self.user_password = password

    print(self.login_url, self.user_email, self.user_password)

Вызвать нестатический метод как статический

"""
* Referencing the Account.login(self, url, email, password)
* Just call the 'Account' object as the self 
"""
Account.login(Account, "https://example.com/login", "email@example.com", "password_example")

:$ https://example.com/login email@example.com password_example
-2
16 сент. '18 в 15:32
источник

Время от времени я сталкиваюсь с этим вопросом. Вариант использования и пример, который мне нравится, это:

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

Не имеет смысла создавать объект класса cmath, потому что в CMAT-объекте нет состояния. Однако cmath - это совокупность методов, которые в какой-то мере связаны. В моем примере выше все функции в cmath каким-то образом действуют на сложные числа.

-3
08 янв. '18 в 6:53
источник

Посмотрите другие вопросы по меткам или Задайте вопрос