В чем разница между @staticmethod и @classmethod?

Я упростил решение Реми Ф с помощью функций set_x/y/zlim .

from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
import matplotlib.pyplot as plt
import numpy as np

fig = plt.figure()
ax = fig.gca(projection='3d')
ax.set_aspect('equal')

X = np.random.rand(100)*10+5
Y = np.random.rand(100)*5+2.5
Z = np.random.rand(100)*50+25

scat = ax.scatter(X, Y, Z)

max_range = np.array([X.max()-X.min(), Y.max()-Y.min(), Z.max()-Z.min()]).max() / 2.0

mid_x = (X.max()+X.min()) * 0.5
mid_y = (Y.max()+Y.min()) * 0.5
mid_z = (Z.max()+Z.min()) * 0.5
ax.set_xlim(mid_x - max_range, mid_x + max_range)
ax.set_ylim(mid_y - max_range, mid_y + max_range)
ax.set_zlim(mid_z - max_range, mid_z + max_range)

plt.show()

enter image description here [/g1]

3233
задан martineau 26 September 2018 в 19:35
поделиться

8 ответов

Может быть, вам поможет небольшой пример кода: обратите внимание на разницу в сигнатурах вызовов foo , class_foo и static_foo :

class A(object):
    def foo(self, x):
        print "executing foo(%s, %s)" % (self, x)

    @classmethod
    def class_foo(cls, x):
        print "executing class_foo(%s, %s)" % (cls, x)

    @staticmethod
    def static_foo(x):
        print "executing static_foo(%s)" % x    

a = A()

Ниже показан обычный способ вызова метода экземпляром объекта. Экземпляр объекта a неявно передается в качестве первого аргумента.

a.foo(1)
# executing foo(<__main__.A object at 0xb7dbef0c>,1)

С помощью classmethods класс экземпляра объекта неявно передается как первый аргумент вместо self ].

a.class_foo(1)
# executing class_foo(<class '__main__.A'>,1)

Вы также можете вызвать class_foo с помощью класса. Фактически, если вы определяете что-то метод класса, вероятно, потому, что вы намереваетесь вызвать его из класса, а не из экземпляра класса. A.foo (1) вызвал бы ошибку TypeError, но A.class_foo (1) отлично работает:

A.class_foo(1)
# executing class_foo(<class '__main__.A'>,1)

Одно из применений, которое люди нашли для методов класса, - это создание наследуемых альтернативных конструкторов .


В staticmethods ни self (экземпляр объекта), ни cls (класс) неявно передаются в качестве первого аргумента . Они ведут себя как простые функции, за исключением того, что вы можете вызывать их из экземпляра или класса:

a.static_foo(1)
# executing static_foo(1)

A.static_foo('hi')
# executing static_foo(hi)

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


foo - это просто функция , но когда вы вызываете a.foo , вы не просто получаете функцию, вы получаете "частично примененную" версию функции с экземпляром объекта a , привязанным в качестве первого аргумента функции. foo ожидает 2 аргумента, а a.foo ожидает только 1 аргумент.

a привязан к foo . Это то, что имеется в виду под термином «связанный» ниже:

print(a.foo)
# <bound method A.foo of <__main__.A object at 0xb7d52f0c>>

С a.class_foo , a не привязан к class_foo , а скорее к классу привязан к class_foo .

print(a.class_foo)
# <bound method type.class_foo of <class '__main__.A'>>

Здесь статическим методом, даже если это метод, a.static_foo просто возвращает хорошая старая функция без привязки аргументов. static_foo ожидает 1 аргумент, а a.static_foo тоже ожидает 1 аргумент.

print(a.static_foo)
# <function static_foo at 0xb7d479cc>

И, конечно же, то же самое происходит, когда вы вызываете static_foo вместо этого с классом A .

print(A.static_foo)
# <function static_foo at 0xb7d479cc>
2953
ответ дан 22 November 2019 в 19:47
поделиться

staticmethod является методом, который ничего не знает о классе или экземпляре, к этому обратились. Это просто получает аргументы, которые были переданы, никакой неявный первый аргумент. Это в основном бесполезно в Python - можно просто использовать функцию модуля вместо staticmethod.

А classmethod, с другой стороны, является методом, который передается класс, к этому обратились, или класс экземпляра, к этому обратились как первый аргумент. Это полезно, когда Вы хотите, чтобы метод был фабрикой для класса: так как это получает фактический класс, к этому обратились как первый аргумент, можно всегда инстанцировать правильного класса, даже когда подклассы включены. Наблюдайте, например, как dict.fromkeys(), classmethod, возвращает экземпляр подкласса, когда обращено подкласс:

>>> class DictSubclass(dict):
...     def __repr__(self):
...         return "DictSubclass"
... 
>>> dict.fromkeys("abc")
{'a': None, 'c': None, 'b': None}
>>> DictSubclass.fromkeys("abc")
DictSubclass
>>> 
753
ответ дан Brian Burns 26 September 2018 в 19:35
поделиться
  • 1
    Зафиксированный это, спасибо. It' s теперь zsqr = x * x + y * y как он должен быть – schnaader 22 February 2009 в 17:04

В основном @classmethod делает метод, первым аргументом которого является класс, которым это называют от (а не экземпляр класса), @staticmethod не имеет никаких неявных аргументов.

134
ответ дан Tadeck 26 September 2018 в 19:35
поделиться
  • 1
    Проблема на самом деле definesthat x+y+z=1000, таким образом, Вы устраняете третий цикл полностью с простым z = 1000-x-y – annakata 23 February 2009 в 09:45

@staticmethod просто отключает функцию по умолчанию как дескриптор метода. classmethod обертывает Вашу функцию в контейнер, вызываемый, который передает ссылку на класс владения как первый аргумент:

>>> class C(object):
...  pass
... 
>>> def f():
...  pass
... 
>>> staticmethod(f).__get__(None, C)
<function f at 0x5c1cf0>
>>> classmethod(f).__get__(None, C)
<bound method type.f of <class '__main__.C'>>

, На самом деле, classmethod имеет время выполнения наверху, но позволяет получить доступ к классу владения. Кроме того, я рекомендую использовать метакласс и поместить методы класса для того метакласса:

>>> class CMeta(type):
...  def foo(cls):
...   print cls
... 
>>> class C(object):
...  __metaclass__ = CMeta
... 
>>> C.foo()
<class '__main__.C'>
21
ответ дан Armin Ronacher 26 September 2018 в 19:35
поделиться
  • 1
    Это все имеет смысл, но проверьте свои имена переменной! You' ре, получающее Ваш x' s, y' s и z' s запутанный.:-) – Pitarou 22 February 2009 в 16:49

Я думаю, давая просто, версия Python staticmethod и classmethod помогла бы понять различие между ними на уровне языка.

Они оба - дескрипторы неданных (Было бы легче понять их, если Вы знакомы с дескрипторы первый).

class StaticMethod(object):
    "Emulate PyStaticMethod_Type() in Objects/funcobject.c"

    def __init__(self, f):
        self.f = f

    def __get__(self, obj, objtype=None):
        return self.f


class ClassMethod(object):
    "Emulate PyClassMethod_Type() in Objects/funcobject.c"
    def __init__(self, f):
        self.f = f

    def __get__(self, obj, cls=None):
        def inner(*args, **kwargs):
            if cls is None:
                cls = type(obj)
            return self.f(cls, *args, **kwargs)
        return inner
0
ответ дан 22 November 2019 в 19:47
поделиться

Метод класса получает класс как неявный первый аргумент, точно так же, как метод экземпляра получает экземпляр. Это - метод, который связывается с классом а не объектом класса. Это имеет доступ к состоянию класса, поскольку это берет параметр класса, который указывает на класс а не экземпляр объекта. Это может изменить состояние класса, которое применялось бы через все экземпляры класса. Например, это может изменить переменную класса, которая будет применима ко всем экземплярам.

, С другой стороны, статический метод не получает неявный первый аргумент, по сравнению с методами класса или методами экземпляра. И доступ can’t или изменяет состояние класса. Это только принадлежит классу, потому что с точки зрения дизайна, которая является корректным путем. Но с точки зрения функциональности не связывается, во времени выполнения, к классу.

как инструкция, используйте статические методы в качестве утилит, используйте методы класса, например, в качестве фабрики. Или возможно определить одиночный элемент. И используйте методы экземпляра смоделировать состояние и поведение экземпляров.

Надежда я был ясен!

0
ответ дан 22 November 2019 в 19:47
поделиться

Официальная документация python:

@classmethod

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

 класс C:
 @classmethod
 def f (cls, arg1, arg2, ...): ... 

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

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

Методы класса отличаются от методов C ++ или статические методы Java. Если ты хочешь те, см. staticmethod () в этом section.

@staticmethod

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

 класс C:
 @staticmethod
 def f (arg1, arg2, ...): ... 

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

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

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

98
ответ дан 22 November 2019 в 19:47
поделиться

Здесь - короткая статья по этому вопросу.

Функция @staticmethod - это не что иное, как функция, определенная внутри класса. Он вызывается без предварительного создания экземпляра класса. Его определение неизменяемо через наследование.

Функция @classmethod также вызывается без создания экземпляра класса, но ее определение следует за подклассом, а не за родительским классом, через наследование. Это потому, что первым аргументом для функции @classmethod всегда должен быть cls (class).

71
ответ дан 22 November 2019 в 19:47
поделиться
Другие вопросы по тегам:

Похожие вопросы: