Ответ 1
Используйте isinstance()
. Пример:
if isinstance(n, unicode):
# do this
elif isinstance(n, Node):
# do that
...
Иногда проверка аргументов в Python необходима. например, у меня есть функция, которая принимает либо адрес другого узла в сети в качестве необработанного строкового адреса, либо класс Node, который инкапсулирует информацию о другом узле.
Я использую функцию type() как в:
if type(n) == type(Node):
do this
elif type(n) == type(str)
do this
Это хороший способ сделать это?
Обновление 1: Python 3 имеет аннотацию для параметров функции. Их можно использовать для проверки типов с помощью инструмента: http://mypy-lang.org/
Используйте isinstance()
. Пример:
if isinstance(n, unicode):
# do this
elif isinstance(n, Node):
# do that
...
>>> isinstance('a', str)
True
>>> isinstance(n, Node)
True
Нет, аргументы typechecking в Python не нужны. Это никогда необходимо.
Если ваш код принимает адреса как rawstring или как объект Node
, ваш
дизайн нарушен.
Это происходит из-за того, что если вы уже не знаете тип объект в вашей собственной программе, то вы уже делаете что-то неправильно.
Typechecking вредит повторному использованию кода и снижает производительность. Имея функцию который выполняет разные действия в зависимости от типа переданного объекта подвержен ошибкам и имеет более сложное поведение, чтобы понять и поддерживать.
У вас есть следующие варианты:
Создайте конструктор объекта Node
, который принимает rawstrings или функцию
который преобразует строки в объекты Node
. Сделайте свою функцию
аргумент передается Node
. Таким образом, если вам необходимо пройти
string к функции, вы просто выполните:
myfunction(Node(some_string))
Это ваш лучший вариант, он чист, понятен и поддерживается. Любой, кто читает код, сразу же понимает, что происходит, и вам не нужно проверять тип.
Сделайте две функции, которые принимают объекты Node
, и объекты, которые принимают
rawstrings. Вы можете сделать один вызов другим внутренне, в большинстве случаев
удобный способ (myfunction_str
может создать объект Node
и вызвать
myfunction_node
, или наоборот).
У объектов Node
есть метод __str__
и внутри вашей функции,
вызовите str()
в полученный аргумент. Таким образом, вы всегда получаете строку
путем принуждения.
В любом случае не typecheck. Это совершенно не нужно и имеет только отрицательные стороны. Рефакторируйте свой код вместо того, чтобы вам не нужно было проверять тип. Вы получаете только выгоду в этом, как в краткосрочной, так и в долгосрочной перспективе.
Звучит так, будто вы ищете "универсальную функцию", которая работает по-разному в зависимости от приведенных аргументов. Это немного похоже на то, как вы получите другую функцию при вызове метода для другого объекта, но вместо того, чтобы просто использовать первый аргумент (объект/себя) для поиска функции, вместо которой вы используете все аргументы.
Turbogears использует что-то вроде этого для принятия решения о том, как преобразовать объекты в JSON - если я правильно помню.
Есть статья от IBM об использовании пакета диспетчера для такого рода вещей:
Из этой статьи:
import dispatch
@dispatch.generic()
def doIt(foo, other):
"Base generic function of 'doIt()'"
@doIt.when("isinstance(foo,int) and isinstance(other,str)")
def doIt(foo, other):
print "foo is an unrestricted int |", foo, other
@doIt.when("isinstance(foo,str) and isinstance(other,int)")
def doIt(foo, other):
print "foo is str, other an int |", foo, other
@doIt.when("isinstance(foo,int) and 3<=foo<=17 and isinstance(other,str)")
def doIt(foo, other):
print "foo is between 3 and 17 |", foo, other
@doIt.when("isinstance(foo,int) and 0<=foo<=1000 and isinstance(other,str)")
def doIt(foo, other):
print "foo is between 0 and 1000 |", foo, other
Вы также можете использовать try catch для проверки типа:
def my_function(this_node):
try:
# call a method/attribute for the Node object
if this_node.address:
# more code here
pass
except AttributeError, e:
# either this is not a Node or maybe it a string,
# so behavior accordingly
pass
Вы можете увидеть пример этого в начале Python во втором о генераторах (страница 197 в моем выпуске), и я верю в Поваренную книгу Python. Много раз ловить AttributeError
или TypeError
проще и, по-видимому, быстрее. Кроме того, он может работать лучше всего таким образом, потому что тогда вы не привязаны к определенному дереву наследования (например, ваш объект может быть Node
, или это может быть что-то другое, что имеет то же поведение, что и Node
).