这里我要找的是PHP的print_r函数。
这样我就可以通过查看有问题的对象的状态来调试脚本。
这里我要找的是PHP的print_r函数。
这样我就可以通过查看有问题的对象的状态来调试脚本。
当前回答
我需要在一些日志中打印调试信息,无法使用pprint,因为它会破坏它。相反,我这样做了,得到了几乎相同的结果。
DO = DemoObject()
itemDir = DO.__dict__
for i in itemDir:
print '{0} : {1}'.format(i, itemDir[i])
其他回答
已经提到了Dir,但它只提供属性的名称。如果你也想要它们的值,试试__dict__。
class O:
def __init__ (self):
self.value = 3
o = O()
输出如下:
>>> o.__dict__
{'value': 3}
我没有测试过性能,但我相信这是在Python中以列表形式枚举任何对象的属性/属性/键的最快方法。
# If core==False, ignore __k__ entries
def obj_props(obj, core=False) -> list:
assert not obj is None, f"obj must not be null (None)"
_props = []
_use_dir=False
def _add(p):
if not core and p.find('__') == 0: return
_props.append(p)
if hasattr(obj, '__dict__'):
for p in obj.__dict__.keys(): _add(p)
elif hasattr(obj, '__slots__'):
for p in obj.__slots__: _add(p)
elif hasattr(obj, 'keys'):
try:
for p in obj.keys(): _add(p)
except Exception as ex:
_props = []
_use_dir = True
else:
_use_dir = True
if _use_dir:
# fall back to slow and steady
for p in dir(obj):
if not core and p.find('__') == 0: continue
v = getattr(obj, p)
v_t = type(v).__name__
if v_t in ('function', 'method', 'builtin_function_or_method', 'method-wrapper'): continue
_props.append(p)
return _props
上面应该适用于常规的python对象(使用__dict__),使用插槽的对象(__slots__),甚至适用于像对象一样的字典。
大多数其他示例使用dir(obj),它将枚举对象的所有方法和属性,如果您只需要它的属性,则会对性能造成影响。
是否有内置函数打印对象的所有当前属性和值?
不。投票最多的答案排除了某些类型的属性,而接受的答案显示了如何获取所有属性,包括方法和部分非公共api。但是没有好的完整的内置函数。
所以简短的推论是你可以写你自己的,但它会计算属性和其他计算数据描述符,这是公共API的一部分,你可能不想要:
from pprint import pprint
from inspect import getmembers
from types import FunctionType
def attributes(obj):
disallowed_names = {
name for name, value in getmembers(type(obj))
if isinstance(value, FunctionType)}
return {
name: getattr(obj, name) for name in dir(obj)
if name[0] != '_' and name not in disallowed_names and hasattr(obj, name)}
def print_attributes(obj):
pprint(attributes(obj))
其他答案的问题
观察当前投票最多的答案在一个有很多不同类型数据成员的类上的应用:
from pprint import pprint
class Obj:
__slots__ = 'foo', 'bar', '__dict__'
def __init__(self, baz):
self.foo = ''
self.bar = 0
self.baz = baz
@property
def quux(self):
return self.foo * self.bar
obj = Obj('baz')
pprint(vars(obj))
只打印:
{'baz': 'baz'}
因为vars只返回对象的__dict__,而且它不是一个副本,所以如果你修改vars返回的dict,你也在修改对象本身的__dict__。
vars(obj)['quux'] = 'WHAT?!'
vars(obj)
返回:
{'baz': 'baz', 'quux': 'WHAT?!'}
——这很糟糕,因为quux是一个我们不应该设置的属性,不应该在命名空间中…
应用目前公认的答案(和其他答案)中的建议并没有好到哪里去:
>>> dir(obj)
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__slots__', '__str__', '__subclasshook__', 'bar', 'baz', 'foo', 'quux']
正如我们所看到的,dir只返回与对象相关的所有(实际上是大部分)名称。
检查。评论中提到的Getmembers也有类似的缺陷——它返回所有的名称和值。
从类
在教学时,我让我的学生创建一个函数,提供对象的语义公共API:
def api(obj):
return [name for name in dir(obj) if name[0] != '_']
我们可以扩展它以提供对象的语义命名空间的副本,但我们需要排除未分配的__slots__,如果我们认真对待“当前属性”的请求,我们需要排除计算属性(因为它们可能变得昂贵,并且可能被解释为不是“当前”):
from types import FunctionType
from inspect import getmembers
def attrs(obj):
disallowed_properties = {
name for name, value in getmembers(type(obj))
if isinstance(value, (property, FunctionType))
}
return {
name: getattr(obj, name) for name in api(obj)
if name not in disallowed_properties and hasattr(obj, name)
}
现在我们不计算或显示属性,quux:
>>> attrs(obj)
{'bar': 0, 'baz': 'baz', 'foo': ''}
警告
但也许我们知道我们的房产并不贵。我们可能想要改变逻辑以包括它们。也许我们希望排除其他自定义数据描述符。
然后我们需要进一步定制这个函数。因此,我们不能有一个内置函数神奇地知道我们想要什么并提供它。这是我们需要自己创造的功能。
结论
没有内置函数可以做到这一点,您应该根据自己的情况选择语义上最合适的方法。
from pprint import pprint
def print_r(the_object):
print ("CLASS: ", the_object.__class__.__name__, " (BASE CLASS: ", the_object.__class__.__bases__,")")
pprint(vars(the_object))
def dump(obj):
for attr in dir(obj):
print("obj.%s = %r" % (attr, getattr(obj, attr)))
有许多第三方函数根据作者的喜好添加了异常处理、国家/特殊字符打印、递归嵌套对象等功能。但它们基本上都可以归结为这个。