Pythonic Way To Check for A Parameter Type

拜拜、爱过 提交于 2020-01-14 19:25:51

问题


I'm working on a little side project for work and have made some classes and methods. One of the classes represents a shelf in our inventory and another represents each a bin on the shelf. I have a method to add a new bin to the shelf and I added some logic to make sure it was passed a Location object before it is added to the shelf (right now I'm using lists while I develop before moving everything to a DB).

However I just read in a Python book that I have that it is usually better to handle exceptions as they arise rather than add extra code. I removed the logic to see what error I would get but I didn't get anything it allowed a string in place of the Location object.

Is there a more Pythonic way to enforce what type a parameter is?

What I have for the shelf:

class CrossDock:
locations = []

def add_location(self, location):
    if isinstance(location, Location): #if this is commented out it will take what ever is passed to it
        self.locations.append(location)
    else:
        print("location parameter must be of type: Location. Parameter is of type" + str(type(location)))

Is there a way I can do this with a try/except block?


回答1:


Propagate an exception to the caller. This forces users of your class to fix the invalid type when they misuse the class. Printing is not useful as it does not enforce an interface contract.

class CrossDock(object):
    def __init__(self):
        self.locations = []

    def add_location(self, location):
        if isinstance(location, Location):
            self.locations.append(location)
        else:
            raise TypeError("location must be Location, got: " +
                            repr(type(location)))



回答2:


The most pythonic way is to not type check... everything is duck typed.

What's the canonical way to check for type in python?




回答3:


The exception you might eventually get would happen somewhere else in your code, when you tried to use a Location instance but found something else there instead. There's nothing wrong with checking a parameter when it comes from an unreliable source. This places the exception at the root of the problem, rather than at a potentially more difficult to diagnose secondary location in your code.

You might do pretty much what you have, only raise an exception rather than print the error.

def add_location(self, location):
    if not isinstance(location, Location):
        tmpl = "location parameter must be of type: Location, got %s"
        raise TypeError(tmpl % str(type(location)))
    ... do other processing here after guarding check ...

This type of checking is most appropriate if you have no control over the calling code. If you just want to catch a programming error you've made yourself, you can just use an assert:

def add_location(self, location):
    assert isinstance(location, Location), "location must be of type: Location"
    ... do other processing here

The advice against doing parameter type checks is directed at allowing the most flexibility in your code, like if someone wanted to pass in an object that had the same methods as location. Checking for a hard-coded type would raise an exception even though the code could work.




回答4:


Use assert inside the try/except block

class Location():
    pass

class CrossDock:
    locations = []

    def add_location(self, location):
        try:
            assert(isinstance(location, Location))
            self.locations.append(location)
            print("added")
        except AssertionError:
            print("error: Parameter is of type" + str(type(location)))


c = CrossDock()
loc = Location()
c.add_location("2")
c.add_location(loc)

Will fail on the first add_location call

location parameter must be of type: Location. Parameter is of type<type 'str'>

added


来源:https://stackoverflow.com/questions/20673087/pythonic-way-to-check-for-a-parameter-type

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!