有没有Python等价于Ruby的respond_to方法?

11

在Python中有没有一种方法可以查看类是否响应某个方法?就像Ruby中的方法一样:

class Fun
  def hello
    puts 'Hello'
  end
end

fun = Fun.new
puts fun.respond_to? 'hello' # true

还有没有一种方法可以查看方法需要多少个参数?

4个回答

17

嗯... 我认为 hasattrcallable 是实现相同目标最简单的方法:

class Fun:
    def hello(self):
        print 'Hello'

hasattr(Fun, 'hello')   # -> True
callable(Fun.hello)     # -> True

当然,你可以在异常处理块中调用callable(Fun.hello):

try:
    callable(Fun.goodbye)
except AttributeError, e:
    return False

关于必需参数数量的内省;我认为这对语言来说价值可疑(即使在Python中存在),因为这并不能告诉您任何有关所需语义的信息。考虑到在Python中定义可选/默认参数和可变参数函数和方法的简易性,似乎知道函数的“必需”参数数量在编程/内省角度上是非常有限的价值。


谢谢!有没有办法使用方法名字符串来调用 callable 呢? - errorhandler
2
yurib展示了一个使用getattr()函数的实例,以及属性名称(作为字符串)并在其上调用callable()的示例:callable(getattr(Fun(), 'hello'))。 - Jim Dennis
2
@错误:callable(getattr(Fun,"hello", None))getattr的第三个参数是一个默认值,如果对象没有该属性,则返回该值。 - Katriel
@katrielalex:是的,指定默认返回值要好得多。 另外,直接在类上调用getattr似乎很奇怪(而不是像我之前做的那样在类的实例上调用)。这还可能在某些奇怪的情况下失败,其中一些类在 newinit 中动态生成其方法 / 属性。 在实例上调用似乎比直接在类上调用更可取。 - Jim Dennis
@Jim:没错,虽然在__init__中生成实例方法并不是很常见。这取决于使用情况。 - Katriel
@Katrielalex:即使这很少见,最好让您的代码实现与您的意图尽可能接近的语义。如果以后有人更改了您正在编写代码的类的实现,则检查其实例的代码将继续工作,而检查先前实现的类的代码将突然失败。 - Jim Dennis

8

方法:

func = getattr(Fun, "hello", None)
if callable(func):
  ...

参数个数:

import inspect
args, varargs, varkw, defaults = inspect.getargspec(Fun.hello)
arity = len(args)

请注意,如果您有varargs和/或varkw不是None,则arity可以是几乎任何东西。

2

dir(instance) 返回一个对象的属性列表。
getattr(instance,"attr") 返回一个对象的属性。
callable(x) 如果x是可调用的,则返回True。

class Fun(object):
    def hello(self):
        print "Hello"

f = Fun()
callable(getattr(f,'hello'))

正如其他人指出的那样,您应该使用 hasattr() 来检查属性是否存在。 - yurib
hasattr()函数不能判断属性是否为方法(即可调用的)。 - log0
如果类没有属性“hello”,这将引发异常,这可能不是想要的结果。 - Katriel

1

我不是 Ruby 专家,所以我不确定这是否回答了你的问题。我认为你想检查一个对象是否包含某个方法。有很多种方法可以做到这一点。你可以尝试使用 hasattr() 函数来查看对象是否具有该方法:

hasattr(fun, "hello") #True

或者你可以遵循 Python 指南中的不要问能不能问,直接问的方式,所以当对象没有该方法时,只需捕获抛出的异常即可:

try:
    fun.hello2()
except AttributeError:
    print("fun does not have the attribute hello2")

哦,当然你是对的,我把C++和其他语言搞混了。已经修改过了。 - Constantinius
尝试使用异常处理程序包装调用的优点在于,您可以尝试所需的语义并测试结果...这通常比尝试内省然后在尝试调用时必须准备好语义不匹配要好得多。 - Jim Dennis
6年晚的评论提醒:第二个问题在于你正在使用异常作为流程控制,如果你正在循环遍历一堆可能会或可能不会响应某个方法的对象,那么你将会抛出很多错误。 - WattsInABox
不鼓励使用异常来控制流程的Ack - iNecas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接