Unexpected Type Error Decorator Exercise

The Exercise

Create a decorator expected_type() that checks if what the decorated function returns is of expected type. An UnexpectedTypeException should be raised if the type returned by the decorated function doesn’t match the ones expected.

Requirements:

  • expected_type() should accept a tuple of many types that may be valid
  • UnexpectedTypeException should be raised if decorated function returns object of type that wasn’t defined in expected_type() 's arguments (you have to implement that class)
  • return_something will be decorated with expected_type in the tests and will look exactly like in the example below

#the decorator creation

def expected_type(*msg):

    def wrapper(return_something):

        for items in msg:

            x = return_something()

            if items == type(x):

                print("hello function is of the type expected")

               

            else:

                print("Type Unexpected Error")

                break

                   

    return wrapper

   

@expected_type('str','dict','set','list')

def return_something():

    return ('hello everyone')

# calling the function

print(return_something)

The Error l am getting is:

Type Unexpected Error
None

I am expecting the code to print hello function is of the type expected but it is not working, how can l correct it?

Thanks

Try to follow the wrapper function logic step-by-step. What each variable is, what happens with it in function, what is printed and when.

1 Like

ok l have started to get what l want now, why am l getting None at the end?, my return_something function has a return statement


#the decorator creation

def expected_type(*msg):

    def wrapper(return_something):

        for items in msg:

            x = return_something()

       

            if items == type(x):

                print("hello function is of the type expected")

                break

               

            else:

                print("Type Unexpected Error")

                                                   

    return wrapper

   

@expected_type(str,dict,set,list)

def return_something():

    return ('hello everyone')

# calling the function

print(return_something)

That’s not how you call a function?

That’s not how you compare an item to a list.
For a start, a for loop will run a set number of times. If you give it 4 items, it will run up to 4 times - think about in what situation it would run 4 times and what it would put out.
And when you are finished and before you rethink everything, just use “if-in”, because that’s the Python way of doing this.

Jumping off @sanity’s comment, I think you are not getting the result you expect because things are not being called when you expect them. You can use a Python REPL to run your code in 3 steps (defining expected_type, defining return_something, and calling return_something), in order to see when exactly things are happening. Is wrapper being ran when return_something is called or during the definition of it?


#the decorator creation

def expected_type(*msg):

    def wrapper(return_something):

        for items in msg:

            x = return_something()

       

            if items == type(x):

                print("hello function is of the type expected")

                break

               

            else:

                print("Type Unexpected Error")

                                                   

    return wrapper

   

@expected_type(str,dict,set,list)

def return_something():

    return ('hello everyone')

# calling the function

return_something()

In line 25 of the code l am getting error that:

TypeError: ‘NoneType’ object is not callable

Why does this error come up when the return something function returns something?

@kylec You are right about what you said, how do l run the code in 3 steps using the REPL

Thanks

I am not the best at counting, so would you kindly tell us which line that is?

return_something returns something before it’s decorated, but what returns decorated version of it?

Decorating return_something function with expected_type(str,dict,set,list) can be written as:

return_something = expected_type(str,dict,set,list)(return_something)

expected_type(str,dict,set,list) returns wrapper, so it’s:

return_something = wrapper(return_something)

So at the end return_something is whatever is returned by wrapper after passing it return_something function. Questions for this arises - what wrapper returns and can it be called, so we can still write return_something().

2 Likes

@ Jagaya This is the line

Thanks

Ok I understand now, when l was looking at decorators, I also found this piece of code, that is almost the same in the structure, like inside the wrapper function

# defining a decorator
def hello_decorator(func):

	# inner1 is a Wrapper function in
	# which the argument is called
	
	# inner function can access the outer local
	# functions like in this case "func"
	def inner1():
		print("Hello, this is before function execution")

		# calling the actual function now
		# inside the wrapper function.
		func()

		print("This is after function execution")
		
	return inner1


# defining a function, to be called inside wrapper
def function_to_be_used():
	print("This is inside the function !!")


# passing 'function_to_be_used' inside the
# decorator to control its behaviour
function_to_be_used = hello_decorator(function_to_be_used)


# calling the function
function_to_be_used()

the source of this is here:

Thanks