是否有一个内置函数来打印对象的所有当前属性和值?

所以我在这里寻找的是类似PHP的print_r函数。

这样我就可以通过查看有问题的对象的状态来调试我的脚本。

1207121 次浏览

您可以使用“dir()”函数来执行此操作。

>>> import sys>>> dir(sys)['__displayhook__', '__doc__', '__excepthook__', '__name__', '__stderr__', '__stdin__', '__stdot__', '_current_frames', '_getframe', 'api_version', 'argv', 'builtin_module_names', 'byteorder, 'call_tracing', 'callstats', 'copyright', 'displayhook', 'dllhandle', 'exc_clear', 'exc_info''exc_type', 'excepthook', 'exec_prefix', 'executable', 'exit', 'getcheckinterval', 'getdefaultncoding', 'getfilesystemencoding', 'getrecursionlimit', 'getrefcount', 'getwindowsversion', 'heversion', 'maxint', 'maxunicode', 'meta_path', 'modules', 'path', 'path_hooks', 'path_importer_ache', 'platform', 'prefix', 'ps1', 'ps2', 'setcheckinterval', 'setprofile', 'setrecursionlimit, 'settrace', 'stderr', 'stdin', 'stdout', 'subversion', 'version', 'version_info', 'warnoption', 'winver']>>>

另一个有用的功能是帮助。

>>> help(sys)Help on built-in module sys:
NAMEsys
FILE(built-in)
MODULE DOCShttp://www.python.org/doc/current/lib/module-sys.html
DESCRIPTIONThis module provides access to some objects used or maintained by theinterpreter and to functions that interact strongly with the interpreter.
Dynamic objects:
argv -- command line arguments; argv[0] is the script pathname if known
def dump(obj):for attr in dir(obj):print("obj.%s = %r" % (attr, getattr(obj, attr)))

有许多第三方函数根据作者的喜好添加了异常处理、国家/特殊字符打印、递归到嵌套对象等内容。但它们都基本上归结为这一点。

已经提到了dir,但这只会给您属性的名称。如果您也想要它们的值,请尝试__dict__

class O:def __init__ (self):self.value = 3
o = O()

以下是输出:

>>> o.__dict__
{'value': 3}

你真的把两种不同的东西混合在一起了。

使用#0#1#2模块来获取您感兴趣的内容(我使用__builtins__作为示例;您可以使用任何对象代替)。

>>> l = dir(__builtins__)>>> d = __builtins__.__dict__

把那本字典按你喜欢的方式打印出来:

>>> print l['ArithmeticError', 'AssertionError', 'AttributeError',...

>>> from pprint import pprint>>> pprint(l)['ArithmeticError','AssertionError','AttributeError','BaseException','DeprecationWarning',...
>>> pprint(d, indent=2){ 'ArithmeticError': <type 'exceptions.ArithmeticError'>,'AssertionError': <type 'exceptions.AssertionError'>,'AttributeError': <type 'exceptions.AttributeError'>,...'_': [ 'ArithmeticError','AssertionError','AttributeError','BaseException','DeprecationWarning',...

漂亮的打印也可以在交互式调试器中作为命令使用:

(Pdb) pp vars(){'__builtins__': {'ArithmeticError': <type 'exceptions.ArithmeticError'>,'AssertionError': <type 'exceptions.AssertionError'>,'AttributeError': <type 'exceptions.AttributeError'>,'BaseException': <type 'exceptions.BaseException'>,'BufferError': <type 'exceptions.BufferError'>,...'zip': <built-in function zip>},'__file__': 'pass.py','__name__': '__main__'}

您希望将vars()pprint()混合:

from pprint import pprintpprint(vars(your_object))

要打印对象的当前状态,您可以:

>>> obj # in an interpreter

print repr(obj) # in a script

print obj

为您的类定义__str____repr__方法。从python留档

__repr__(self)repr()内置函数和字符串调用转换(反向引号)到计算“官方”字符串对象的表示。如果可能,这应该看起来像一个有效的Python表达式可能是用于使用相同的值(给出适当的环境)。如果这是不可能的,形式为“<…一些有用的字符串描述…>“应该返回。返回值必须是字符串对象。如果一个类定义了repr()但不是__str__(),那么__repr__()是也用于当“非正式”字符串表示该实例类是必需的。这通常是用于调试,所以很重要表示是信息丰富而明确。

__str__(self)str()内置函数和print调用计算“非正式”的声明对象的字符串表示。__repr__()的不同之处在于它不一定是有效的Python表达:更方便或可以使用简明表示相反。返回值必须是字符串对象。

元编程示例用魔法转储对象

$ cat dump.py
#!/usr/bin/pythonimport sysif len(sys.argv) > 2:module, metaklass  = sys.argv[1:3]m = __import__(module, globals(), locals(), [metaklass])__metaclass__ = getattr(m, metaklass)
class Data:def __init__(self):self.num = 38self.lst = ['a','b','c']self.str = 'spam'dumps   = lambda self: repr(self)__str__ = lambda self: self.dumps()
data = Data()print data

无论据:

$ python dump.py
<__main__.Data instance at 0x00A052D8>

使用通用工具

$ python dump.py gnosis.magic MetaXMLPickler
<?xml version="1.0"?><!DOCTYPE PyObject SYSTEM "PyObjects.dtd"><PyObject module="__main__" class="Data" id="11038416"><attr name="lst" type="list" id="11196136" ><item type="string" value="a" /><item type="string" value="b" /><item type="string" value="c" /></attr><attr name="num" type="numeric" value="38" /><attr name="str" type="string" value="spam" /></PyObject>

它有点过时,但仍然有效。

在大多数情况下,使用__dict__dir()会得到你想要的信息。如果你碰巧需要更多的细节,标准库包括检查模块,它可以让你得到一些令人印象深刻的细节。一些真正的信息包括:

  • 函数和方法参数的名称
  • 类层次结构
  • 实现函数/类对象的源代码
  • 帧对象的局部变量

如果你只是在寻找“我的对象有什么属性值?”,那么dir()__dict__可能就足够了。如果你真的想挖掘任意对象的当前状态(请记住,在python中几乎所有东西都是对象),那么inspect值得考虑。

pprint包含一个“漂亮的打印机”,用于生成数据结构的美观表示。格式化程序生成的数据结构表示可以被解释器正确解析,并且也易于人类阅读。如果可能,输出保留在单行上,并在拆分多行时缩进。

也许值得查一下

是否有一个Python相当于Perl的Data::Dumper?

我的建议是

https://gist.github.com/1071857

请注意,perl有一个名为Data::Dumper的模块,它将对象数据转换回perl源代码(注意:它不会将代码转换回源代码,并且几乎总是您不想在输出中使用对象方法函数)。这可用于持久性,但常见目的是调试。

有许多标准python pprint无法实现的事情,特别是当它看到一个对象的实例并为您提供对象的内部十六进制指针时,它会停止降序(errr,顺便说一句,该指针并没有太多用途)。所以简而言之,python是关于这个伟大的面向对象范式的,但是你开箱即用的工具是为处理对象以外的东西而设计的。

perl Data::Dumper允许你控制你想走多深,还可以检测循环链接结构(这非常重要)。这个过程在perl中基本上更容易实现,因为对象除了它们的祝福之外没有特别的魔力(一个普遍定义良好的过程)。

为什么不简单点:

for key,value in obj.__dict__.iteritems():print key,value

我需要在一些日志中打印DEBUG信息,但无法使用pprint,因为它会破坏它。相反,我这样做了,得到了几乎相同的东西。

DO = DemoObject()
itemDir = DO.__dict__
for i in itemDir:print '{0}  :  {1}'.format(i, itemDir[i])

要转储“myObject”:

from bson import json_utilimport json
print(json.dumps(myObject, default=json_util.default, sort_keys=True, indent=4, separators=(',', ': ')))

我尝试了vars()和dir();都失败了,因为对象没有__dict__(异常. TypeError:vars()参数必须有__dict__属性)。

我认为json.dumps()可以在没有默认=json_util.default的情况下适用于大多数对象,但是我在对象中有一个datetime字段,所以标准的json序列化器失败了。参见如何克服Python中的“datetime.datetimeJSON不可序列化”?

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))

如果你使用它进行调试,并且你只想递归转储所有内容,那么接受的答案是不令人满意的,因为它要求你的类已经有了良好的__str__实现。如果不是这种情况,这样做会更好:

import jsonprint(json.dumps(YOUR_OBJECT,default=lambda obj: vars(obj),indent=1))

这以json或yaml缩进格式递归打印出所有对象内容:

import jsonpickle # pip install jsonpickleimport jsonimport yaml # pip install pyyaml
serialized = jsonpickle.encode(obj, max_depth=2) # max_depth is optionalprint json.dumps(json.loads(serialized), indent=4)print yaml.dump(yaml.load(serialized), indent=4)

您可以尝试Flask调试工具栏。
https://pypi.python.org/pypi/Flask-DebugToolbar

from flask import Flaskfrom flask_debugtoolbar import DebugToolbarExtension
app = Flask(__name__)
# the toolbar is only enabled in debug mode:app.debug = True
# set a 'SECRET_KEY' to enable the Flask session cookiesapp.config['SECRET_KEY'] = '<replace with a secret key>'
toolbar = DebugToolbarExtension(app)

尝试p的

from ppretty import ppretty

class A(object):s = 5
def __init__(self):self._p = 8
@propertydef foo(self):return range(10)

print ppretty(A(), show_protected=True, show_static=True, show_properties=True)

输出:

__main__.A(_p = 8, foo = [0, 1, ..., 8, 9], s = 5)

尝试beeprint

它不仅可以帮助您打印对象变量,还可以帮助您输出漂亮的输出,如下所示:

class(NormalClassNewStyle):dicts: {},lists: [],static_props: 1,tupl: (1, 2)

我喜欢使用Python对象内置类型

对于属性,无论它们是方法还是变量:

o.keys()

对于这些属性的值:

o.values()

每个人都在挣扎

  • vars()不返回所有属性。
  • dir()不返回属性值。

以下代码打印obj所有属性及其值:

for attr in dir(obj):try:print("obj.{} = {}".format(attr, getattr(obj, attr)))except AttributeError:print("obj.{} = ?".format(attr))

如果您想在复杂数据结构中查看所有,请执行以下操作:

from pprint import pprintpprint(my_var)

其中my_var是你感兴趣的变量。当我使用pprint(vars(my_var))时,我什么也没得到,这里的其他答案没有帮助,或者该方法看起来不必要地长。顺便说一句,在我的特殊情况下,我正在检查的代码有一个字典字典。

值得指出的是,对于一些自定义类,您可能最终会得到无用的<someobject.ExampleClass object at 0x7f739267f400>类型输出。在这种情况下,您可能必须实现__str__方法,或者尝试一些其他解决方案。

我还发现,在我得到这种object类型输出的一个实例中,vars()向我展示了我想要的。因此,涵盖这两种情况的更好解决方案是分别尝试两种情况。但是使用vars()有时会抛出异常,例如TypeError: vars() argument must have __dict__ attribute

我仍然想找到一些在所有场景中都能工作的简单东西,而不需要第三方库。

我建议使用help(your_object)

help(dir)

 If called without an argument, return the names in the current scope.Else, return an alphabetized list of names comprising (some of) the attributesof the given object, and of attributes reachable from it.If the object supplies a method named __dir__, it will be used; otherwisethe default dir() logic is used and returns:for a module object: the module's attributes.for a class object:  its attributes, and recursively the attributesof its bases.for any other object: its attributes, its class's attributes, andrecursively the attributes of its class's base classes.

help(vars)

Without arguments, equivalent to locals().With an argument, equivalent to object.__dict__.

是否有一个内置函数来打印对象的所有当前属性和值?

不会。投票最多的答案排除了某些类型的属性,接受的答案展示了如何获得所有属性,包括非公共api的方法和部分内容。但是这没有好的完整内置函数。

所以简短的推论是你可以自己编写,但它会计算属性和其他计算的数据描述符,它们是公共API的一部分,你可能不希望这样:

from pprint import pprintfrom inspect import getmembersfrom 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 = 0self.baz = baz@propertydef quux(self):return self.foo * self.bar
obj = Obj('baz')pprint(vars(obj))

仅打印:

{'baz': 'baz'}

因为vars只有返回一个对象的__dict__,它不是一个副本,所以如果你修改vars返回的字典,你也在修改对象本身的__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只返回所有(实际上只是大多数)与对象关联的名称。

评论中提到的inspect.getmembers也有类似的缺陷-它返回所有名称值。

从课堂上

在教学时,我让我的学生创建一个函数,提供对象的语义公共API:

def api(obj):return [name for name in dir(obj) if name[0] != '_']

我们可以扩展它以提供对象语义命名空间的复制,但我们需要排除未分配的__slots__,如果我们认真对待“当前属性”的请求,我们需要排除计算属性(因为它们可能变得昂贵,并且可能被解释为不是“当前”):

from types import FunctionTypefrom 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': ''}

警告

但也许我们确实知道我们的属性并不昂贵。我们可能希望更改逻辑以包含它们。也许我们想排除其他定制数据描述符。

然后我们需要进一步定制这个函数。因此,我们不能拥有一个神奇地确切知道我们想要什么并提供它的内置函数是有道理的。这是我们需要自己创建的功能。

结论

没有内置函数可以做到这一点,您应该做在语义上最适合您的情况的事情。

无论变量在类内、类内__init__或类外如何定义,这都有效。

your_obj = YourObj()attrs_with_value = {attr: getattr(your_obj, attr) for attr in dir(your_obj)}

回答开始,可以稍微修改它以仅获取对象的“属性”,如下所示:

def getAttributes(obj):from pprint import pprintfrom inspect import getmembersfrom types import FunctionType    
def attributes(obj):disallowed_names = {name for name, value in getmembers(type(obj))if isinstance(value, FunctionType)}return {name for name in dir(obj)if name[0] != '_' and name not in disallowed_names and hasattr(obj, name)}pprint(attributes(obj))

临时添加此函数时很有帮助,无需对现有源代码进行大量更改即可删除

这个项目修改了pprint以显示所有对象字段值,它忽略了he对象__repr__成员函数,它还递归到嵌套对象中。它适用于python3,请参阅https://github.com/MoserMichael/pprintex您可以通过pip安装它:pip install printex

虽然有很多好的答案,但这里有一个1-line可以给出属性以及值:

(str(vars(config)).split(",")[1:])

我将此列为单独的答案,因为我只想简单地打印对象的相关值(不包括__main等),而不使用循环或漂亮的打印,并且没有找到方便的答案。

vars()似乎显示了这个对象的属性,但dir()似乎也显示了父类的属性。您通常不需要看到继承的属性,例如strdoc字典等。

In [1]: class Aaa():...:     def __init__(self, name, age):...:         self.name = name...:         self.age = age...:In [2]: class Bbb(Aaa):...:     def __init__(self, name, age, job):...:         super().__init__(name, age)...:         self.job = job...:In [3]: a = Aaa('Pullayya',42)
In [4]: b = Bbb('Yellayya',41,'Cop')
In [5]: vars(a)Out[5]: {'name': 'Pullayya', 'age': 42}
In [6]: vars(b)Out[6]: {'name': 'Yellayya', 'age': 41, 'job': 'Cop'}
In [7]: dir(a)Out[7]:['__class__','__delattr__','__dict__','__dir__','__doc__','__eq__',......'__subclasshook__','__weakref__','age','name']

我没有测试过性能,但我相信这是在Python中仅枚举任何对象的属性/属性/键作为列表的最快方法。

# If core==False, ignore __k__ entriesdef obj_props(obj, core=False) -> list:assert not obj is None, f"obj must not be null (None)"_props = []_use_dir=Falsedef _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 = Trueelse:_use_dir = Trueif _use_dir:# fall back to slow and steadyfor p in dir(obj):if not core and p.find('__') == 0: continuev = 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),它将枚举对象的所有方法和属性,如果您只需要其属性,则会降低性能。