Как я должен передавать переменные между функциями в этом классе?

Что я пытаюсь сделать: выполняя скрипт, мне нужно будет набрать два числа, и он сравнит их. Я хочу, чтобы меня спросили всего 3 раза. В первый раз я наберу 10 и 5, второй раз 5 и 10, а в третий раз я наберу 10 и 10, чтобы получить все три возможных ответа.

Моя проблема с первым кодом: getnumbers() вызывается внутри Checknumbers(), Я хочу создавать функции и цикл и строго выполнять ТОЛЬКО функции внутри выделенного цикла, а не внутри другой функции.

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

Я решил это с классом, но я не совсем уверен, что я убиваю язык или это обычная практика. Также я должен ссылаться на класс внутри checknumbers() функция.

Первое решение:

def getnumbers():
    x = input("Enter the X number: ")
    y = input("Enter the Y number: ")
    return x, y

def checknumbers():
    x, y=getnumbers()
    if   x > y:
        print(f'x is larger then y: x is {x} and y is {y}')
    elif y > x:
        print(f"y is larger then x: x is {x} and y is {y}")
    elif y == x:
        print(f"x is equal to y: x is {x} and y is {y}")     
    else:
        print("Dont know mate")


n = 0
while(n < 3):
    checknumbers()
    n += 1

Это вариант с классом:

class ui:
    x = input("Enter the X number: ")
    y = input("Enter the Y number: ")


def checknumbers():
    if   ui.x > ui.y:    
        print(f'x is larger then y: x is {ui.x} and y is {ui.y}')
    elif ui.y > ui.x:
        print(f"y is larger then x: x is {ui.x} and y is {ui.y}")
    elif ui.y == ui.x:
        print(f"x is equal to y: x is {ui.x} and y is {ui.y}")     
    else:
        print("Dont know mate")

n = 0
while(n < 3):
    checknumbers()
    n += 1

Идеальное решение, поэтому обе функции getnumbers() а также checknumbers очищаются независимо друг от друга и вызываются внутри цикла while, проблема в том, что x и y из getnumbers() функция неизвестна checknumbers,

Требование: я не могу иметь никаких ссылок на любые другие функции внутри своих функций, как я могу передать x и y, не ссылаясь на них?:

def getnumbers():
    x = input("Enter the X number: ")
    y = input("Enter the Y number: ")
    return x, y

def checknumbers():
    if   x > y:
        print(f'x is larger then y: x is {x} and y is {y}')
    elif y > x:
        print(f"y is larger then x: x is {x} and y is {y}")
    elif y == x:
        print(f"x is equal to y: x is {x} and y is {y}")     
    else:
        print("Dont know mate")


n = 0
while(n < 3):
    getnumbers()
    checknumbers()
    n += 1

3 ответа

Решение
  • Вы путаетесь между классами и экземплярами, а также между атрибутами классов и атрибутами экземпляров. (Прочтите, например, это)
    • OO способ хранить переменные состояния (например, x,y), чтобы вам не приходилось передавать их между вызовами функций (/ методов), - создавать их атрибуты экземпляра. (Не атрибуты класса, как вы делали. Не волнуйтесь, я тоже так делал, когда впервые изучал Python).
    • Итак, мы объявляем класс UI; мы получим доступ к его атрибутам экземпляра как self.x, self.y внутри его методы.
    • Не пытайтесь делать что-то напрямую в пользовательском интерфейсе класса. Вы должны сначала создать его экземпляр: ui = UI(), Вы должны следовать соглашению Python, что имена классов - Uppercase / CamelCase: UIимена экземпляров строчные, например ui, ui1, ui2...
    • Вы пытались поместить код непосредственно в определение класса пользовательского интерфейса, не определяли методы и не помещали код в него, а ваш класс пользовательского интерфейса даже не имел __init__()
    • Методы являются функциями внутри класса, они всегда имеют первый аргумент self, Если они этого не сделают, метод не сможет получить доступ к остальной части класса (!)
  • Теперь, когда мы это выяснили, есть несколько способов разложить методы, чтобы сделать то, что вы хотите сделать:
    1. Есть пустой __init__() (Вы могли бы просто заставить свое тело делать pass). Есть get_numbers() а также check_numbers() быть отдельными методами, которые вы вручную вызываете по порядку. Это то, что я покажу ниже и ближе всего к тому, что вы сказали, что вы хотите ("Я не хочу ссылаться на какую-либо функцию внутри другой функции"), но это плохая декомпозиция - что если клиент вызвал check_numbers() до get_numbers()? Это взорвать на TypeError, так как __init__() инициализирует x, y с помощью None.
    2. Лучше было бы иметь __init__() вызвать метод get_numbers() скрытый, чтобы гарантировать, что экземпляр будет правильно инициализирован. (Мы всегда могли позвонить get_numbers() еще раз позже, если мы хотим ввести новые номера). Это легко изменить, я оставляю это тебе.
    3. В подходе 1. мы должны были инициализировать элементы экземпляра для чего-либо (в противном случае пытались получить к ним доступ в check_numbers() взорвется). Итак, мы инициализируем None, который намеренно выбросит исключение, если мы сравним. Это не имеет большого значения, это просто плохое разложение, чтобы не иметь __init__() правильно инициализировать экземпляр (и вызывать любые методы, необходимые для этого). Вот почему подход 2. лучше. Как правило, вы всегда должны иметь __init__() это инициализирует класс в известное состояние, так что любой другой метод может быть безопасно вызван.

Код:

class UI:
    def __init__(self, x=None, y=None):
        self.x = x
        self.y = y
    def get_numbers(self):
        self.x = input("Enter the X number: ")
        self.y = input("Enter the Y number: ")
    def check_numbers(self):
        """This is bad decomposition because if the client calls check_numbers() before get_numbers(), the NoneType will throw a TypeError"""
        if   self.x > self.y:    
            print(f'x is larger then y: x is {self.x} and y is {self.y}')
        elif self.y > self.x:
            print(f'y is larger then x: x is {self.x} and y is {self.y}')
        elif self.y == self.x:
            print(f'x is equal to y: x is {self.x} and y is {self.y}')     
        else:
            print("Don't know mate")

# Declare an instance and reuse it three times    
ui = UI()
for n in range(3):
    ui.get_numbers()
    ui.check_numbers()

Также некоторые незначительные стилистические моменты:

  • вам не нужен цикл while для простого счетчика: n = 0, while(n < 3)... n += 1, Цикл for является однострочным: for n in range(3):
  • Хороший стиль Python (см. PEP-8) заключается в названии методов lower_case_with_underscores, таким образом get_numbers(), check_numbers()
  • отличный нисходящий способ разработки класса - это сначала написать сигнатуры его методов, подумать о том, какие методы и атрибуты вам понадобятся и как они будут работать вместе. Пример: "get_numbers() получит пользовательский ввод, поэтому нам понадобятся атрибуты self.x,y хранить номера так check_numbers() может получить к ним доступ ". И таким образом вы должны столкнуться с любыми проблемами в дизайне классов, прежде чем писать стену кода.

Если вы не хотите звонить getnumbers() в checknumbers()единственная альтернатива, которая имеет смысл - это передавать числа в качестве параметров checknumbers(),

def getnumbers():
    x = int(input("Enter the X number: "))
    y = int(input("Enter the Y number: "))
    return x,y

def checknumbers(x, y):
    if x > y:
        # etc.

...

for _ in range(3):
    x,y = getnumbers()
    checknumbers(x,y)

Это, по крайней мере, имеет лучшее разделение интересов.

  • Я не вижу ничего плохого в первом решении (за исключением того факта, что getumbers возвращает строки в Python 3) . Классы не являются решением для каждой проблемы

  • У меня не может быть ссылок на другие функции внутри моих функций. Как передать x и y, не ссылаясь на них?

    Невозможно передать что-то без ссылки на это. Даже если x а также y если бы глобальные переменные (что намного хуже, чем ваш нынешний дизайн) использовала бы функция using для ссылки на них.

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

Другие вопросы по тегам