Возможно ли иметь статические методы в Python, которые я мог бы вызывать без инициализации класса, например:
ClassName.static_method()
Возможно ли иметь статические методы в Python, которые я мог бы вызывать без инициализации класса, например:
ClassName.static_method()
Ответы:
Да, используя статический метод декоратор
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 является декоратором функции - подробности см. В описании определений функций в определениях функций .
Он может быть вызван либо в классе (например,
C.f()
), либо в экземпляре (например,C().f()
). Экземпляр игнорируется за исключением его класса.Статические методы в Python похожи на те, которые есть в Java или C ++. Для более продвинутой концепции см
classmethod()
.Для получения дополнительной информации о статических методах см. Документацию по стандартной иерархии типов в разделе Стандартная иерархия типов .
Новое в версии 2.2.
Изменено в версии 2.4: добавлен синтаксис функции декоратора.
ClassName.methodName()
, как если бы он был статическим, и тогда self
метод не будет предоставлен. Как вы сказали, все еще можно будет также вызывать этот метод как ClassInstance.methodName()
и self
будет предоставлен в качестве первого параметра, независимо от его имени.
Я думаю, что Стивен на самом деле прав . Чтобы ответить на исходный вопрос, затем, чтобы настроить метод класса, просто предположите, что первый аргумент не будет вызывающим экземпляром, а затем убедитесь, что вы вызываете метод только из класса.
(Обратите внимание, что этот ответ относится к 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)
должно сработать. Вставка @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)
TypeError: unbound method rollCall() must be called with Dog instance as first argument (got int instance instead)
T.my_static_method()
или type(my_t_instance).my_static_method()
, так как это понятнее и сразу делает очевидным, что я вызываю статический метод.
Да, проверьте статический метод декоратора:
>>> class C:
... @staticmethod
... def hello():
... print "Hello World"
...
>>> C.hello()
Hello World
Вам не нужно использовать @staticmethod
декоратор. Просто объявите метод (не ожидающий параметра self) и вызовите его из класса. Декоратор существует только в том случае, если вы хотите иметь возможность вызывать его также из экземпляра (что не было тем, что вы хотели сделать)
В основном вы просто используете функции, хотя ...
class Dummy: def static1(): print "hello from static1" @staticmethod def static2(): print "hello from static2" Dummy.static2() Dummy.static1()
Вывод: привет из static2 Traceback <последний вызов последнего>: файл "ll.py", строка 46, в <module> Dummy.static1 () TypeError: метод unbound static1 () должен быть вызван с пустым экземпляром в качестве первого аргумента (вместо этого ничего не получил)
self
в качестве первого аргумента, если вы не скажете, что нет. (см .: декоратор)
self
ссылку соответствующим образом в зависимости от того, как он вызывается. Тестовый пример: pastebin.com/12DDV7DB .
staticmethod
Декоратор позволяет вызвать функцию как класс и экземпляр (это решение не выполняется при вызове функции на примере).
class C: def callme(): print('called'); C.callme()
Статические методы в 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
, что метод класса получает класс в качестве неявного первого аргумента, а в случае подкласса он получает подкласс в качестве неявного первого аргумента.
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'])
Помимо особенностей поведения объектов статических методов , есть некоторая красота, с которой вы можете поразить их, когда речь заходит об организации кода на уровне модулей.
# 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
Возможно, самый простой вариант - просто поместить эти функции вне класса:
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
def add(a, b):
return a + b
b = A.add(12,12)
print b
В приведенном выше примере метод add
вызывается именем класса, а A
не именем объекта.
Статические методы Python могут быть созданы двумя способами.
Использование 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
Использование @staticmethod
class Arithmetic:
# create add static method
@staticmethod
def add(x, y):
return x + y
print('Result:', Arithmetic.add(15, 10))
Вывод:
Результат: 25
Я сталкиваюсь с этим вопросом время от времени. Пример использования и пример, который мне нравится:
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, потому что в объекте cmath нет состояния. Тем не менее, cmath - это набор методов, которые каким-то образом связаны между собой. В моем примере выше все функции в cmath так или иначе действуют на комплексные числа.
@staticmethod
украшения или использовать указатель на функцию, когда вы можете просто избежать первогоself
параметра? Ну, для объектаa
вы не сможете вызыватьa.your_static_method()
, что разрешено на других языках, но это в любом случае считается плохой практикой, и компилятор всегда предупреждает об этом