Python: функция как атрибут класса, а не метод [duplicate]

Исключение нулевого указателя генерируется, когда приложение пытается использовать null в случае, когда требуется объект. К ним относятся:

  1. Вызов метода экземпляра объекта null.
  2. Доступ или изменение поля объекта null.
  3. Принимая длину null, как если бы это был массив.
  4. Доступ или изменение слотов null, как если бы это был массив.
  5. Бросок null как будто это было значение Throwable.

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

Ссылка: http://docs.oracle.com/javase/8/docs/api/java/lang/NullPointerException.html

1433
задан BartoszKP 5 June 2014 в 21:12
поделиться

9 ответов

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


Ниже приводится дословно из документации: :

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

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

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

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

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

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

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

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

1702
ответ дан jesterjunk 19 August 2018 в 13:43
поделиться
  • 1
    Зачем добавлять декор @staticmethod или использовать указатель функции, когда вы можете просто избежать первого параметра self? Что ж, для объекта a вы не сможете вызвать a.your_static_method(), что разрешено на других языках, но в любом случае считается плохой практикой, и компилятор всегда предупреждает об этом – SomethingSomething 22 May 2017 в 15:40
  • 2
    Я использую python 2.7.12, с @staticmethod decorator. Я не могу вызвать первый статический метод. Его ошибка givin: ТипError: объект staticmethod не может быть вызван – Supratim Samantray 23 July 2017 в 08:07
  • 3
    Супратим Самантрей, ты уверен? потому что здесь четко указано, что он может быть использован после 2.4. – realslimshanky 21 January 2018 в 23:19
  • 4
    – George Moutsopoulos 29 August 2018 в 09:09
  • 5
    – SomethingSomething 29 August 2018 в 10:30

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

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'])
28
ответ дан Aaron Hall 19 August 2018 в 13:43
поделиться

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

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

43
ответ дан hichris123 19 August 2018 в 13:43
поделиться
  • 1
    Либо это не работает, либо неясно, что вы имеете в виду. Я удалю свой downvote, если будет опубликован рабочий пример. – Eric Wilson 9 June 2011 в 20:18
  • 2
    Это не работает, хотя было бы разумно, что это нужно. Глупый питон ...;) – weberc2 1 October 2012 в 04:17
  • 3
    Это не работает внутри класса. Python передаст self в качестве первого аргумента, если вы не сообщите ему об этом. (см .: декоратор) – Navin 9 February 2013 в 18:44
  • 4
    На самом деле это неверно в версии 2.7 и имеет право на 3.X (проверено в 3.2). То есть вы не можете вызывать метод из контекста класса без декоратора @staticmethod в 2.7 и ниже. В 3.2 он работает и будет вставлять self ref соответственно в зависимости от того, как его вызывается. Тестовый пример: pastebin.com/12DDV7DB . – spinkus 24 April 2014 в 09:51
  • 5
    Технически точное, но ужасное решение. Декоратор staticmethod позволяет вызвать функцию как для класса, так и для экземпляра (это решение не выполняется при вызове функции в экземпляре). – Ethan Furman 25 February 2017 в 03:45

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

# 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
ответ дан JJD 19 August 2018 в 13:43
поделиться

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

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
ответ дан Matt Woelk 19 August 2018 в 13:43
поделиться

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

(Обратите внимание, что этот ответ относится к 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)
177
ответ дан Md. Abu Nafee Ibna Zahid 19 August 2018 в 13:43
поделиться
  • 1
    Первый пример (вызов классом без @staticmethod) не работает для меня на Python 2.7. Я получаю & quot; TypeError: unbound метод rollCall () должен быть вызван с экземпляром Dog в качестве первого аргумента (вместо этого был получен int instance) & quot; – tba 21 February 2013 в 23:46
  • 2
    Это не работает. И Dog.rollCall (-1), и rex.rollCall (-1) возвращают те же TypeError: unbound method rollCall() must be called with Dog instance as first argument (got int instance instead) – Mittenchops 14 October 2013 в 15:26
  • 3
    @MestreLion Я думаю, что это не огромная выгода, поскольку все, что он делает, путается с статическими и экземплярами методов и делает один похожим на другой. Если вы знаете, что метод статичен, вы должны получить к нему доступ как статический метод. Тот факт, что метод не нужен или использует ваш экземпляр, должен быть самоочевидным везде, где вы используете этот метод. Я всегда использую T.my_static_method() или type(my_t_instance).my_static_method(), так как это яснее и сразу становится очевидным, что я вызываю статический метод. – Asad Saeeduddin 15 November 2014 в 02:07

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

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 в некотором роде действуют на сложные числа.

-1
ответ дан Moritz 19 August 2018 в 13:43
поделиться

Да, проверьте декоратор staticmethod :

>>> class C:
...     @staticmethod
...     def hello():
...             print "Hello World"
...
>>> C.hello()
Hello World
74
ответ дан Paolo Bergantino 19 August 2018 в 13:43
поделиться
0
ответ дан Erisan Olasheni 31 October 2018 в 01:31
поделиться
Другие вопросы по тегам:

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