5

我正在努力学习用 Python 编程,并专注于更好地处理如何使用标准和其他模块。dir 函数在解释器中似乎非常强大,但我想知道我是否因为缺乏 OOP 背景而遗漏了什么。使用 S.Lotts 的书,我决定使用他的 Die 类来学习更多关于语法以及类和实例的使用。

这是原始代码:

class Die(object):
''' simulate a six-sided die '''
def roll(self):
    self.value=random.randrange(1,7)
    return self.value
def getValue(self):
    return self.value

我正在查看它,在创建了一些实例之后,我想知道单词 value 是否是关键字,以及 class 语句中单词 object 的用途是什么,因此我决定通过将类定义更改为以下内容来找出答案:

class Die():
''' simulate a six-sided die '''
def roll(self):
    self.ban=random.randrange(1,7)
    return self.ban
def getValue(self):
    return self.ban

这种变化表明我从我的实例中得到了相同的行为,但是当我执行 dir 时,实例中缺少以下方法/属性:

'__class__', '__delattr__', '__dict__', '__doc__', '__getattribute__',
 '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__',
_repr__', '__setattr__', '__str__', '__weakref__'

我还发现当我在一个实例上做一个目录时,我有一个额外的关键字ban,我最终发现它是我实例的一个属性。这帮助我了解我可以使用d1.ban来访问我的实例的值。我能弄清楚这是一个属性的唯一原因是我输入了d1.happy并得到了一个AttributeError 我发现d1.GetValue是一个附加到 Die 的方法,因为这是解释器告诉我的。

因此,当我尝试使用诸如 BeautifulSoup 之类的复杂但有用的模块时,在键入dir(instance)后,我如何知道列出的哪些内容是我的实例的属性或我的实例的方法。我需要知道这一点,因为这种探索告诉我,我使用属性调用方法的结果,使用方法调用实例上的函数。

这个问题可能太罗嗦了,但它确实帮助我更好地理解了属性和方法之间的区别。具体来说,当我查看在 Die 类的实例上调用 dir 的结果时,我看到了这个

['__doc__', '__module__', 'ban', 'getValue', 'roll']

因此,通过查看该列表来了解哪些是属性和哪些是方法似乎很有用,而不必诉诸试验和错误或导致输入hasattr(myInstance,suspectedAttributeName)

发布问题后,我尝试了

for each in dir(d1):
    print hasattr(d1,each)

严格来说,它告诉我所有方法都是属性。但我不能调用没有()的方法,所以在我看来 hasattr() 具有误导性。

4

6 回答 6

8

而不是:“ print hasattr(d1,each)”,尝试:“ print each, type(getattr(d1,each))”。您应该会发现结果信息丰富。

此外,代替dir()try help(),我认为你真的在寻找。

于 2009-05-18T23:16:17.697 回答
4

考虑使用标准库的inspect模块——它通常是最方便的自省方法,将大量功能打包(你可以从头开始实现它,但重用经过良好测试、精心设计的代码是一件好事)。有关所有详细信息,请参阅http://docs.python.org/library/inspect.html,但例如inspect.getmembers(foo, inspect.ismethod)是获取 foo 的所有方法的好方法(您将获得(name, value)按名称排序的对)。

于 2009-05-19T04:25:07.587 回答
2

严格来说,它告诉我所有方法都是属性。但我不能调用没有 () 的方法,所以在我看来 hasattr() 具有误导性。

为什么会误导?如果obj.ban()是一个方法,那么obj.ban就是对应的属性。你可以有这样的代码:

print obj.getValue()

或者

get = obj.getValue
print get()

如果你想获取一个对象的方法列表,你可以试试这个函数。这并不完美,因为它也会触发不是方法的可调用属性,但对于 99% 的情况应该足够好:

def methods(obj):
    attrs = (getattr(obj, n) for n in dir(obj))
    return [a for a in attrs if a.hasattr("__call__")]
于 2009-05-18T23:07:30.070 回答
2

这个info受 Dive into Python 启发的模块可以达到目的。

def info(obj, spacing=20, collapse=1, variables=False):
    '''Print methods and their doc Strings

    Takes any object'''
    if variables:
    methodList = [method for method in dir(obj)]
    else:
    methodList = [method for method in dir(obj) if callable(getattr(obj,method))]

    #print methodList


    print '\n'.join(['%s %s' %
            (method.ljust(spacing),
             " ".join(str(getattr(obj,method).__doc__).split()))
            for method in methodList])


if __name__=='__main__':
    info(list)
于 2009-05-19T18:40:25.170 回答
1

理想情况下,当使用像 BeautifulSoup 这样的复杂库时,您应该查阅其文档以了解每个类提供了哪些方法。但是,在您没有易于访问的文档的极少数情况下,您可以使用以下方法检查是否存在方法。

所有本身是对象的方法都实现了该__call__方法,并且可以使用返回的 callable() 方法True进行检查,如果被检查的值具有该__call__方法。

以下代码应该可以工作。

x = Die()
x.roll()

for attribute in dir(x) :
    print attribute, callable(getattr(x, attribute))

上面的代码将对所有方法返回 true,对所有不可调用的属性(例如数据成员,如 ban)返回 false。但是,此方法也返回True任何可调用对象(如内部类)。您还可以检查属性的类型是否为instancemethod

于 2009-05-18T23:08:30.223 回答
1

有一个内置的方法叫做 callable。您可以将它应用于任何对象,它会根据是否可以调用它返回 True/False。例如

>>> def foo():
...   print "This is the only function now"
...
>>> localDictionary = dir()
>>> for item in localDictionary:
...   print repr(item) + "is callable: " + str(callable(locals()[item]))
'__builtins__'is callable: False
'__doc__'is callable: False
'__name__'is callable: False
'foo'is callable: True

请注意 locals() 调用将返回一个字典,其中包含当前范围内定义的所有内容。我这样做是因为字典中的项目只是字符串,我们需要在实际对象上运行 callable。

于 2009-05-18T23:09:17.260 回答