Как я должен передавать переменные между функциями в этом классе?
Что я пытаюсь сделать: выполняя скрипт, мне нужно будет набрать два числа, и он сравнит их. Я хочу, чтобы меня спросили всего 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
, Если они этого не сделают, метод не сможет получить доступ к остальной части класса (!)
- Теперь, когда мы это выяснили, есть несколько способов разложить методы, чтобы сделать то, что вы хотите сделать:
- Есть пустой
__init__()
(Вы могли бы просто заставить свое тело делатьpass
). Естьget_numbers()
а такжеcheck_numbers()
быть отдельными методами, которые вы вручную вызываете по порядку. Это то, что я покажу ниже и ближе всего к тому, что вы сказали, что вы хотите ("Я не хочу ссылаться на какую-либо функцию внутри другой функции"), но это плохая декомпозиция - что если клиент вызвалcheck_numbers()
доget_numbers()
? Это взорвать на TypeError, так как__init__()
инициализирует x, y с помощью None. - Лучше было бы иметь
__init__()
вызвать методget_numbers()
скрытый, чтобы гарантировать, что экземпляр будет правильно инициализирован. (Мы всегда могли позвонитьget_numbers()
еще раз позже, если мы хотим ввести новые номера). Это легко изменить, я оставляю это тебе. - В подходе 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 для ссылки на них.
Я не понимаю, почему у вас сложилось впечатление, что вызов функции внутри другой функции плохой или неправильный дизайн.