2009-04-09 6 views
29

Иногда требуется проверка аргументов в Python. например У меня есть функция, которая принимает либо адрес другого узла в сети, как исходный строковый адрес или класс Node, который инкапсулирует информацию другого узла.Проверка типов аргументов Python

Я использую типа (0 функции, как в:

if type(n) == type(Node): 
    do this 
elif type(n) == type(str) 
    do this 

Это хороший способ сделать это

+0

Повторите http://stackoverflow.com/questions/378927/what-is-the-best-idiomatic-way-to-check-the-type-of-a-python-variable. См. Ответ там. – monkut

+1

См. Также: [Python-ideas - Предложение: используйте синтаксис mypy для аннотаций функций] (https://mail.python.org/pipermail/python-ideas/2014-August/028618.html) - автор: Guido van Rossum – NevilleDNZ

+0

Текущий принятый ответ не дает решения. Я рекомендую [ответ Йоханнеса Вейса] (https://stackoverflow.com/a/734385/3357935), так как он лучше отвечает на заданный вопрос. –

ответ

103

Использование isinstance() Пример:.

if isinstance(n, unicode): 
    # do this 
elif isinstance(n, Node): 
    # do that 
... 
+4

isinstance() также проверяет подклассы. – AKX

+0

isinstance (n, unicode) не будет соответствовать простым str-объектам в python 2.x. Вместо сравнения с basestring, который соответствует str или unicode: isinstance (n, basestring) –

+2

http://wiki.python.org/moin/Why%20is%20Python%20a%20dynamic%20language%20and%20also%20a%20strongly % 20typed% 20language - часть состояний первого абзаца: в Python ответственность за использование встроенных функций, таких как isinstance() и issubclass(), заключается в проверке типов переменных и правильном использовании. Python старается держаться подальше от вашего пути, предоставляя вам все, что вам нужно для обеспечения сильной проверки типов. –

13
>>> isinstance('a', str) 
True 
>>> isinstance(n, Node) 
True 
+4

ну, проверка типа обязательна в моем приложении. Я использую OleFileIO_PL и возвращает список элементов во вложенном списке. если элемент является типом каталога, это список внутри вложенного списка, если он является файлом, а затем его строкой. Без проверки строки или нет, это будет невозможно использовать. –

5

Походит вы после «общей функции», которая ведет себя по-разному на основе приведенных аргументов. Это немного похоже на то, как вы получите отличия t, когда вы вызываете метод на другом объекте, но вместо того, чтобы просто использовать первый аргумент (объект/я) для поиска функции, вы используете все аргументы.

Turbogears использует что-то вроде этого, чтобы решить, как преобразовать объекты в JSON - если я правильно помню.

Там в an article from 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 
+3

Это более уродливое и менее ремонтопригодное, чем просто взломать его с помощью typehecking IMO; попытка перевести перегруженные функции на язык, где он просто не подходит очень хорошо. – bobince

+0

Мне нравится функция C++ перегрузки функций, которая, по-видимому, возможна при таком подходе. Я думаю, что это делает код более читаемым, так как вам не нужно проверять аргументы для определенных типов или значений. Хорошая публикация! – Woltan

6

Вы можете также использовать TRY улов типа проверить, если это необходимо:

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's a string, 
     # so behavior accordingly 
     pass 

Вы можете увидеть пример этого в Начало Python во втором о генераторах (стр. 197 в моем редактировании ион), и я верю в Python Cookbook. Много раз ловить AttributeError или TypeError проще и, очевидно, быстрее. Кроме того, он может работать лучше всего таким образом, потому что тогда вы не привязаны к определенному дереву наследования (например, ваш объект может быть Node, или он может быть чем-то другим объектом, который имеет то же поведение, что и Node).

+0

+1: проверка атрибутов не повредит повторному использованию кода, поэтому лучше, чем проверка типов, хотя наличие функции с различным поведением на основе типов не является хорошей идеей. – nosklo

+3

До тех пор, пока разные поведения похожи (по крайней мере, в концепции), я не вижу, что такое большая сделка. Мы все, кажется, думаем, что это нормально для + (a.k.a. operator +() в C++) для работы с числами или строками, но на самом деле оно имеет разные типы поведения, основанные на типах. – RobH

+0

В моем примере оператор +, конечно, реализован двумя различными функциями, которые перегружают оператора. К сожалению, поскольку переменные в Python не печатаются, вы не можете перегружать функции, основанные исключительно на типе. – RobH

7

Нет, аргументы typechecking в Python не нужны. Это никогда необходимо.

Если ваш код принимает адреса как rawstring или как объект Node, ваш дизайн не работает.

Это связано с тем, что если вы уже не знаете тип объекта в своей собственной программе, то вы уже делаете что-то неправильно.

Typechecking вредит повторному использованию кода и снижает производительность. Имея функцию , которая выполняет разные действия в зависимости от типа переданного объекта, подвержен ошибкам и имеет более сложное понимание поведения и обслуживания.

Возможны следующие варианты Санер:

  1. Сделать конструктор Node объект, который принимает rawstrings или функцию , которая преобразует строки в Node объектов. Предположим, что ваша функция предполагает, что переданный аргумент является объектом Node. Таким образом, если вам нужно передать строку в функцию, вы просто сделать:

    myfunction(Node(some_string)) 
    

    Это ваш лучший вариант, это чистый, легко понять и поддержать. Любой, кто читает код, сразу же понимает, что происходит, , и вам не нужно проверять typecheck.

  2. Сделайте две функции, которые принимают Node объекты и те, которые принимают rawstrings. Вы можете сделать один звонок другим внутренне, наиболее удобным способом . (myfunction_str может создать объект Node и позвонить по телефону myfunction_node, или наоборот).

  3. Сделать Node объекты имеют метод __str__ и внутри вашей функции, вызов str() на принимаемый аргумента. Таким образом, вы всегда получаете строку принуждением.

В любом случае, не typecheck. Это совершенно бесполезно и имеет только минусы. Рефакторируйте свой код вместо того, чтобы вам не нужно было проверять тип. Вы получаете только выгоду от этого, как в краткосрочной, так и в долгосрочной перспективе.

+22

Если ни Node, ни str не являются вашей собственной реализацией (и их, вероятно, нет здесь), вы не можете добавлять такие методы, как __str__, для поддержки вашего альтернативного поведения (*). В этом случае typechecking является очевидным и приемлемым выбором, предпочтительнее иметь возможность обертывать каждый экземпляр str. – bobince

+0

(*: если вы не предлагаете исправление обезьяны ...) – bobince

+1

@bobince: Обратите внимание, что добавление __str__ - это третий вариант, который я предоставил. В этом случае я поеду с 1-м. – nosklo

Смежные вопросы