0

I have the following two very similar functions:

# Get value as int
def get_int(message):
    while True:
        try:
            number = int(input(message))
            return number
        except ValueError:
            print("Invalid input. Try again.")

# Get value as fraction
def get_fraction(message):
    while True:
        try:
            number = Fraction(input(message))
            return number
        except ValueError:
            print("Invalid input. Try again.")

Now I am wondering if that can be done in a simpler way, by combining these two functions into one. This is my first attemt:

# Get value as specific data type
def get_value(message, data_type):
    while True:
        try:
            number = None
            match data_type:
                case "int":
                    number = int(input(message))
                case "fraction":
                    number = Fraction(input(message))
            return number
        except ValueError:
            print("Invalid input. Try again.")

So now I'm passing the data type as an argument. But I am sure there is a simpler way without using a case distinction. Can I pass somehow the real data datype to the function and use this directly in the code?

3
  • What is Fraction? Commented Nov 9, 2021 at 16:33
  • @Tomerikoo It's probably from here: docs.python.org/3/library/fractions.html Commented Nov 9, 2021 at 16:36
  • FYI, you're on the verge of rediscovering the Strategy Pattern. Commented Nov 9, 2021 at 16:37

5 Answers 5

3

Great news: types are first-order citizens in Python. You can do something like this:

def get_value(message, data_type):
    while True:
        try:
            return data_type(input(message))
        except ValueError:
            print("Invalid input. Try again.")

And then call it like this:

get_value("Input an integer:", int)
# or,
get_value("Input a fraction:", Fraction)
Sign up to request clarification or add additional context in comments.

1 Comment

Wow ok! Didn't think it could be that easy. Thanks!
1

Python has decorators for this same task.

# the decorator
def calculate(function):
   
   # the wrapper function
   def wrapper(message):
        while True:
        try:
            number = function(message)
            return number
        except ValueError:
            print("Invalid input. Try again.")

   return wrapper

Now you just use this in your functions:

# Get value as int
@calculate
def get_int(message):
   return int(input(message))


# Get value as fraction
@calculate
def get_fraction(message):
    return Fraction(input(message))

What's happening here is you are defining a function, that takes a function as input. In this case, it is the calculate function. It is taking in the get_int and get_fraction function as inputs.

So when you call the function get_init, it is actually calling calculate(get_init) which is also a function that takes message as input.

Comments

1

Can I pass somehow the real data datype to the function and use this directly in the code?

There's nothing stopping you from passing the actual data type rather than a string:

# Get value as specific data type
def get_value(message, data_type):
    while True:
        try:
            number = data_type(input(message))
            return number
        except ValueError:
            print("Invalid input. Try again.")

Test:

print(get_value('Enter a fraction: ', Fraction))

Output:

Enter a fraction: 1/3
1/3

1 Comment

Thanks! Coming from other languages like Java it is amazing how intuitive python is.
1

You can pass the conversion function itself, rather than a string.

# Get value as specific data type
def get_value(message, converter):
    while True:
        try:
            number = converter(input(message))
            return number
        except ValueError:
            print("Invalid input. Try again.")

def get_int(message):
    return get_value(message, int)

def get_fraction(message):
    return get_value(message, Fraction)

Comments

1

You can pass references to functions just like any other variable. Therefore:

def get_value(message, data_type):
  while True:
    try:
      return data_type(input(message))
    except ValueError:
      print('Invalid input. Try again')

x = get_value('Enter a fraction', Fraction)
y = get_value('Enter an integer', int)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.