Наследование класса Python с подключением к серверу Elasticsearch

#python-3.x #elasticsearch #inheritance

#python-3.x #elasticsearch #наследование

Вопрос:

Я пытаюсь создать класс python, который наследует класс Elasticsearch и основывается на нем с помощью некоторых пользовательских методов. Проблема, с которой я сталкиваюсь, заключается в том, что я хотел бы, чтобы конструктор класса подключался к серверу, поэтому инициализация проста. Обычно для подключения к серверу это выглядит примерно так:

 from elasticsearch import Elasticsearch
es = Elasticsearch([{'host': 'XXXXXXX', 'port': XXXX}]
 

В моем классе, который я называю «Эластичным», я хотел бы подключиться к серверу и вернуть объект Elasticsearch при инициализации класса, т.е.:

es = Elastic()

который я могу затем использовать для выполнения существующих методов класса Elasticsearch и моих собственных пользовательских операций, например:

 es.search() # existing class method
es.custom_method_example1() # new class method
 

Я пытался и не смог придумать способ сделать это — моя последняя попытка заключалась в использовании метода __new__ dunder, чтобы я мог вернуть подключенный es объект в качестве нового класса:

 class Elastic(Elasticsearch):
    def __new__(cls, timeout=10, max_retries=5, retry_on_timeout=True, *args, **kwargs):
        "Connect to our ES server."
        return Elasticsearch([{'host': 'XXXXX', 'port': XXXX}], timeout=10, max_retries=5, retry_on_timeout=True, *args, **kwargs)
    
    def custom_method_example1(self, *args, **kwargs):
        """
        Performs some custom method that wasn't possible with the standalone Elasticsearch class
        """
 

Во-первых, это не работает:
AttributeError: 'Elasticsearch' object has no attribute 'custom_method_example1' кажется, что он больше не наследует, а заменяет класс?

И, во-вторых, я понял, прочитав об этом, что __new__ обычно не имеет большого смысла (особенно для программистов-любителей, таких как я), поэтому я, вероятно, использую неправильный подход / усложняю его здесь. Если кто-нибудь знает «правильный» способ сделать это, он был бы очень признателен — я немного читал о дизайне фабрики, и в целом это кажется правильным путем, но я все еще понимаю все это (я аналитик по профессии). Я полагаю, что декораторы могут где-то использоваться??

Спасибо и извините за вафлю

Ответ №1:

Действительно, я очень сильно усложнял это. Не учел, что наследование класса включает в себя наследование самого конструктора — поэтому я могу вызвать подкласс Elastic так же, как и для родительского Elasticsearch :

 from elasticsearch import Elasticsearch

class Elastic(Elasticsearch):
    
    def custom_method_example1(self, *args, **kwargs):
        """
        Performs some custom method that wasn't possible with the standalone Elasticsearch class
        """
 

Для инициализации класса и вызова его методов:

 es = Elastic([{'host': 'XXXXX', 'port': XXXX}], timeout=10, max_retries=5, retry_on_timeout=True)

es.custom_method_example1()

 

РЕДАКТИРОВАТЬ: у меня все еще была проблема с желанием установить новые параметры по умолчанию для моего конструктора подкласса — теперь я узнал, как это сделать, используя super() который явно вызывает родительский конструктор, передавая аргументы, которые я установил в конструкторе подкласса, оставляя меня с:

 from elasticsearch import Elasticsearch

class Elastic(Elasticsearch):
    def __init__(self, hosts=[{'host':'XXXXXX', 'port':XXX}], timeout=10, max_retries=5, retry_on_timeout=True):
        super().__init__(hosts=hosts,timeout=timeout,max_retries=max_retries,retry_on_timeout=retry_on_timeout)  

    def custom_method_example1(self, *args, **kwargs):
        """
        Performs some custom method that wasn't possible with the standalone Elasticsearch class
        """
 

что позволяет мне инициализировать класс следующим образом:

 es = Elastic()