Использование статических переменных NamedTuples вне класса в функции

Я использую NamedTuple для определения сервера, к которому я хочу подключиться с помощью telnetlib. Затем я создал класс, который определяет подключение к серверу, с деталями сервера и методом подключения внутри класса. Затем вне класса я хочу использовать метод подключения с сервером NamedTuple в качестве учетных данных для подключения. Однако я продолжаю получать сообщение об ошибке, что в методе подключения отсутствует аргумент NamedTuple.

Я попытался вытащить NamedTuple за пределы класса, попытался поместить Namedtuple в метод инициализации класса. ничего не работает.

Это мой код:

import telnetlib
from typing import NamedTuple

class Unit(NamedTuple):
    name: str
    ip: str
    port: str

    def printunit(self, unit):
        print(unit.name)
        print(unit.ip)
        print(unit.port)

class TnCnct:
    Server1 = Unit("Server1", "1.1.1.1", "23")
    Server2 = Unit("Server2", "2.2.2.2", "23")
    Server3 = Unit("Server3", "3.3.3.3", "23")

    def __init__(self):
        pass

    def cnct(self, u):
        try:
            tn = telnetlib.Telnet(u.ip, u.port, 10)
            tn.open(u.ip, u.port)
            tn.close()
            response = u.name + " " + "Success!"
        except Exception as e:
            response = u.name + " " + "Failed!"
            print(e)
        finally:
            print(response)


TnCnct.cnct(TnCnct.Server1)

Точная ошибка, которую я получаю:

TypeError: cnct() missing 1 required positional argument: 'u'

person Alon    schedule 04.08.2019    source источник


Ответы (2)


<сильный>1. Вы можете использовать namedtuples из коллекций, а не ввод:

namedtuples:

Возвращает новый подкласс кортежа с именем typename. Новый подкласс используется для создания объектов, похожих на кортежи, которые имеют поля, доступные для поиска по атрибутам, а также индексируемые и итерируемые. Экземпляры подкласса также имеют полезную строку документации (с typename и field_names) и полезный метод repr(), который выводит содержимое кортежа в формате имя=значение.

vs typing:

Этот модуль поддерживает подсказки типов, как указано в PEP 484 и PEP 526. Наиболее фундаментальная поддержка состоит из типов Any, Union, Tuple, Callable, TypeVar и Generic. Полную спецификацию см. в PEP 484. Упрощенное введение в подсказки типов см. в PEP 483.

Типизированные NamedTuples — это просто оболочка вокруг исходных namedtuples.

<сильный>2. Вам нужны экземпляры для использования instancemethods:

Исправления для обоих:

import telnetlib
from collections import namedtuple

def printunit(self, unit):
    print(unit.name)
    print(unit.ip)
    print(unit.port)

Unit = namedtuple("Unit","name ip port")
Unit.printunit = printunit 

class TnCnct:
    Server1 = Unit("Server1", "1.1.1.1", "23")
    Server2 = Unit("Server2", "2.2.2.2", "23")
    Server3 = Unit("Server3", "3.3.3.3", "23")

    def __init__(self):
        pass

    def cnct(self, u):
        try:
            tn = telnetlib.Telnet(u.ip, u.port, 10)
            tn.open(u.ip, u.port)
            tn.close()
            response = u.name + " " + "Success!"
        except Exception as e:
            response = u.name + " " + "Failed!"
            print(e)
        finally:
            print(response)

# create a class instance and use the cnct method of it 
connector = TnCnct()
connector.cnct(TnCnct.Server1)

Разница между экземпляром и классом (методы/переменные) подробно описана, например. здесь:

person Patrick Artner    schedule 04.08.2019
comment
Совершенно правильно использовать typing.NamedTuple, как это делал OP. Попробуйте. - person Francis Colas; 04.08.2019
comment
@FrancisColas уверен, что это так ... загляните в types-sources - ИТ также использует collections.namedtuple для внутреннего использования, это просто оболочка над collections.namedtuple - так почему же для начала используется косвенное обращение вместо использования правильного модуля? - person Patrick Artner; 04.08.2019
comment
Что ж, в этом смысл необязательного ввода в Python, вы используете его для предоставления информации о типе (что является хорошей идеей). Если вы не хотите этого делать, ничего страшного; но ваше первоначальное утверждение было «Вам нужно использовать namedtuples из коллекций» (выделено мной), что не было ни предметом вопроса, ни фактическим улучшением его кода. Вы исправили это на «может захотеть», но это все еще отвлекает от остальной части вашего ответа, что на самом деле хорошо. - person Francis Colas; 04.08.2019

cnct — это метод, для которого требуется экземпляр объекта. Здесь вы пытаетесь вызвать его как метод класса. Если это то, что вы хотите, вы должны использовать декоратор:

    @classmethod
    def cnct(cls, u):
        ...
person Francis Colas    schedule 04.08.2019
comment
О, это сработало отлично! Я в значительной степени новичок в объектно-ориентированном программировании. Не могли бы вы объяснить мне, почему это не сработало? Или как я мог заставить его работать как метод экземпляра объекта? - person Alon; 04.08.2019
comment
Чтобы узнать о разнице между методом экземпляра и класса, см. вторую часть ответа от @patrick-artner. - person Francis Colas; 04.08.2019
comment
Кроме того, класс с единственным методом, который не использует self, часто является хорошим кандидатом на преобразование в функцию (но это не мантра, это дизайнерское решение, о котором следует подумать). См. например: docs.quantifiedcode.com/python-anti-patterns/correctness / - person Francis Colas; 04.08.2019