Чи можливі статичні методи в 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
декоратор. Просто оголосивши метод (який не очікує параметру самоврядування) і викликати його з класу. Декоратор є лише в тому випадку, якщо ви хочете мати можливість викликати його і з екземпляра (що було не тим, що ви хотіли зробити)
В основному, ви просто використовуєте функції, хоча ...
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: метод без зв’язку static1 () повинен бути зателефонував разом із екземпляром манекена як перший аргумент (замість цього нічого не отримали)
self
як перший аргумент, якщо ви не скажете цього. (див .: декоратор)
self
посилання відповідно до того, як його називають. Тестовий випадок: pastebin.com/12DDV7DB .
staticmethod
Декоратор дозволяє викликати функцію як клас і екземпляр (це рішення не виконується при виконанні функції на прикладі).
class C: def callme(): print('called'); C.callme()
Статичні методи в Python?
Чи можливі статичні методи в Python, щоб я міг викликати їх без ініціалізації класу, наприклад:
ClassName.StaticMethod()
Так, статичні методи можуть бути створені таким чином (хоча для Pytonic трохи кращим є використання підкреслення замість 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'])
Крім особливостей того, як поводяться об'єкти статичного методу , існує певна краса, яку ви можете вразити ними, якщо мова йде про організацію коду на рівні модуля.
# 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()
, що дозволено іншими мовами, але це все одно вважається поганою практикою, і компілятор завжди попереджає про це