6

Я хочу сделать класс, который использует шаблон проектирования стратегии, подобную этой:Как использовать статический метод в качестве параметра по умолчанию для шаблона проектирования стратегии?

class C: 

    @staticmethod 
    def default_concrete_strategy(): 
     print("default") 

    @staticmethod 
    def other_concrete_strategy(): 
     print("other") 

    def __init__(self, strategy=C.default_concrete_strategy): 
     self.strategy = strategy 

    def execute(self): 
     self.strategy() 

Это дает ошибку:

NameError: name 'C' is not defined 

Замена strategy=C.default_concrete_strategy с strategy=default_concrete_strategy будет работать, но, слева по умолчанию, то переменная экземпляра стратегии будет объектом статического метода, а не вызываемым методом.

TypeError: 'staticmethod' object is not callable 

Это будет работать, если я удалить @staticmethod декоратор, но есть какой-то другой способ? Я хочу, чтобы параметр по умолчанию был сам документирован, чтобы другие сразу увидели пример того, как включить стратегию.

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

+0

Шаблон стратегии в основном бесполезен в python. Поскольку у вас есть функции как объекты первого класса, вы можете просто передавать функции. – Bakuriu

+0

@Bakuriu Ну, как вы можете видеть, стратегия - это функция объекта первого класса. Я думаю, что это все еще называется стратегическим шаблоном? – mtanti

+0

Да, но схема стратегии была в основном изобретена на языках, которые не позволяют передавать функции. Я имею в виду, что в 99% случаев использования вашего класса вы можете просто передать функцию напрямую и получить те же результаты с меньшей сложностью. – Bakuriu

ответ

8

Нет, вы не можете, так как определение class еще не завершено, поэтому имя класса еще не существует в текущем пространстве имен.

Вы можете использовать функцию объекта непосредственно:

class C:  
    @staticmethod 
    def default_concrete_strategy(): 
     print("default") 

    @staticmethod 
    def other_concrete_strategy(): 
     print("other") 

    def __init__(self, strategy=default_concrete_strategy.__func__): 
     self.strategy = strategy 

C еще не существует, когда в настоящее время определены методы, так что вы обратитесь к default_concrete_strategy местным именем. .__func__ распаковывает дескриптор staticmethod для доступа к исходной исходной функции (дескриптор staticmethod сам по себе не может быть использован).

Другим подходом было бы использование по умолчанию дозорного устройства; None будет работать нормально здесь, так как все нормальные значения strategy статические функции:

class C:  
    @staticmethod 
    def default_concrete_strategy(): 
     print("default") 

    @staticmethod 
    def other_concrete_strategy(): 
     print("other") 

    def __init__(self, strategy=None): 
     if strategy is None: 
      strategy = self.default_concrete_strategy 
     self.strategy = strategy 

Поскольку это извлекает default_concrete_strategy из self протокола дескриптора вызывается и функция (несвязанного) возвращается самой staticmethod дескриптора, а после того, как определение класса завершено.

+0

Или он мог бы сначала определить ' default_concrete_strategy' * без * украшения, а затем украсить его после определения '__init__' (поскольку декораторы использовались до 2.4), хотя это было бы довольно громоздким. – Bakuriu

+0

@ Бакуриу: точно; гораздо проще просто развернуть. –

+0

Жаль, если это единственный способ. Было бы неплохо увидеть пример непосредственно в коде того, как передать параметр. @Bakuriu будет украшать метод в конструкторе быть полезным? – mtanti

Смежные вопросы