Welcome to the Treehouse Community
Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community!
Looking to learn something new?
Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.
Start your free trial

Michael Strasser
3,073 PointsObject Oriented Python - typed parameters?
Hey, I was wondering if there is a good way to check if a variable is an instance of a certain class, preferably in the parameter part of a function. I'm thinking about building an application which has a class that takes an undefined number of parameters, but these parameters have to be of a certain type. Now I know I could just write a function check_type or something like that which is called in the class constructor. If I write this in a generic way, I could call it in the constructor of every class that needs this functionality. But this seems to me like some kind of "hack", because it feels like Python does not want me to do that ;)
So my question is basically: If you go about building a python application, I feel like this should be a situation which you encounter more often than you like, so there has to be some kind of best practice for this. Am I missing some kind of python functionality, is my approach which I described above the usual way to do this or do you just don't care about this stuff and it's the responsibility of the other code parts to just call your function correctly?
Best regards, Michael
3 Answers

Chris Freeman
Treehouse Moderator 68,390 PointsThere isn't a way to check arguments against desired parameter types within the parameter statement, but you can use a decorator to add argument checking as a wrapper around any function.
From this StackOverflow answer
From the Decorators for Functions and Methods PEP-318:
def accepts(*types):
def check_accepts(f):
assert len(types) == f.func_code.co_argcount
def new_f(*args, **kwds):
for (a, t) in zip(args, types):
assert isinstance(a, t), \
"arg %r does not match %s" % (a,t)
return f(*args, **kwds)
new_f.func_name = f.func_name
return new_f
return check_accepts
Usage:
@accepts(int, (int,float))
def func(arg1, arg2):
return arg1 * arg2
func(3, 2) # -> 6
func('3', 2) # -> AssertionError: arg '3' does not match <type 'int'>
Mocking up some code to create a two decorators. The first decorator_type_check_kwargs
follows your code example to check the type of the keyword arguments against a provided type. It seems that using kwargs
is overkill, so I created a second decorator to work with position args call decorator_type_check_args
. Below is the code snippet followed by the output in the REPL:
def decorator_type_check_kwargs(darg1):
"""decorate a function with an argument - check kwargs against type
"""
def wrap(func):
def dunder_init(*args, **kwargs):
# print args (removing instance reference)
print("{} arguments were positional:{}, keyword:{}"
"".format(func.__name__, args[1:], kwargs))
print("Checking for class type {}".format(darg1)) # .__class__))
for arg in kwargs.values():
if isinstance(arg, darg1):
print("arg {} is OK. It's of type {}".format(arg, darg1))
else:
print("arg {} is BAD! It's type {} is NOT of type {}"
"".format(arg, type(arg), darg1)) # , type(darg1)))
return func(*args, **kwargs)
return dunder_init
return wrap
def decorator_type_check_args(darg1):
"""decorate a function with an argument - check args against type
"""
def wrap(func):
def dunder_init(*args, **kwargs):
# print args (removing instance reference)
print("{} arguments were positional:{}, keyword:{}"
"".format(func.__name__, args[1:], kwargs))
print("Checking for class type {}".format(darg1)) # .__class__))
for arg in args[1:]:
if isinstance(arg, darg1):
print("arg {} is OK. It's of type {}".format(arg, darg1))
else:
print("arg {} is BAD! It's type {} is NOT of type {}"
"".format(arg, type(arg), darg1)) # , type(darg1)))
return func(*args, **kwargs)
return dunder_init
return wrap
class SecondClass():
"""General class does nothing special"""
myclasses = []
@decorator_type_check_kwargs(int)
def __init__(self, **kwargs):
"""Class is initialized with variable number of objects all of
the same type. These are added to the 'myclasses' list
"""
for value in kwargs.items():
self.myclasses.append(value)
class ThirdClass():
"""General class does nothing special"""
myclasses = []
@decorator_type_check_args(str)
def __init__(self, *args):
"""Class is initialized with variable number of objects all of
the same type. These are added to the 'myclasses' list
"""
for value in args:
self.myclasses.append(value)
print("\n\ninstantiate SecondClass")
second_class = SecondClass(arg1="string1", arg2=25)
print("\nCheck second class myclasses {}".format(second_class.myclasses))
print("\n\ninstantiate ThirdClass")
third_class = ThirdClass("boat", 42)
print("\nCheck third class myclasses {}".format(third_class.myclasses))
REPL output when executing snippet
Python 3.4.3 (default, Oct 14 2015, 20:28:29)
[GCC 4.8.4] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> >>> >>> >>>
instantiate SecondClass
__init__ arguments were positional:(), keyword:{'arg2': 25, 'arg1': 'string1'}
Checking for class type <class 'int'>
arg 25 is OK. It's of type <class 'int'>
arg string1 is BAD! It's type <class 'str'> is NOT of type <class 'int'>
Check second class myclasses [('arg2', 25), ('arg1', 'string1')]
instantiate ThirdClass
__init__ arguments were positional:('boat', 42), keyword:{}
Checking for class type <class 'str'>
arg boat is OK. It's of type <class 'str'>
arg 42 is BAD! It's type <class 'int'> is NOT of type <class 'str'>
Check third class myclasses ['boat', 42]
>>>
This is just a jumping of point. Instead of the print statements you could raise errors as needed.

Ken Alger
Treehouse TeacherMichael;
To make sure I am understanding, you want to be able to have something along the lines of:
a = "Hello World"
and then be able to determine if a
is an instance of the string
class, for example? If that is the case, Python has a built in class isinstance
that would let you do something like:
a = "Hello"
if isinstance(a, str):
print(a + " is of type string")
else:
print("Nope")
Does that help? Post back with further questions.
Happy coding,
Ken

Michael Strasser
3,073 PointsHey Ken, thanks for the reply. Here's the situation that I mean: I have some sort of python class, which I wrote:
class Myclass:
a = "Hello"
Now I have another class with a constructor that takes an arbitrary amount of variables:
class Sndclass:
myclasses = []
def __init__(**kwargs):
for value in kwargs.items():
myclasses.append(value);
I am aware that I could call the isInstance function in the for loop, but coming from a statically typed background I was wondering if there is a good way to tell Python to only accept variables of type "Myclass" as parameters for the constructor of Sndclass, or which way would be the best to solve this situation.

Ken Alger
Treehouse TeacherHmmm... not sure how to limit parameters like that. Perhaps Chris Freeman would have some insights.

Chris Freeman
Treehouse Moderator 68,390 PointsVerifying argument types needs to be done in the __init__
method. My posted answer can be extended to create a decorator for use on the __init__
method.
Otherwise you'll have explicitly loop through the parameters checking for isinstance()
or create a function to do this so that your code stays DRY.
Another alternative is to create a mix in class that can be used in the declaration of SndClass or in the other class needing this specific parameter filtering.

Chris Freeman
Treehouse Moderator 68,390 PointsKen, BTW, I never got an email notice that I was tagged in this thread. I normally don't check the "Ringing Bell" icon for notices. I noticed this thread only because I was perusing the posts :-/
Chris Freeman
Treehouse Moderator 68,390 PointsChris Freeman
Treehouse Moderator 68,390 PointsYou think my answer was best? Check it now! it's Super-Best! I added a working mock up of a decorator in the style you might be looking for. It is only a template but should get you started. I left a lot of
print
statements so you can see how it works. Good Luck!Michael Strasser
3,073 PointsMichael Strasser
3,073 PointsThanks a lot, this is very helpful :)