是否可以像在Matlab中一样在IPython中显示对象实例变量? [英] Is it possible to display an objects instance variables in IPython like Matlab does?

查看:106
本文介绍了是否可以像在Matlab中一样在IPython中显示对象实例变量?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正试图从Matlab转向Python。虽然神奇?在IPython中很好,Matlab的一个非常好的功能是你可以在命令行上看到(通过省略;)相关对象的实例变量(在Matlab中称为属性)。这可能在python中(我想通过IPython)?

I'm trying to move away from Matlab to Python. While the magic ? in IPython is nice, one very nice feature of Matlab is that you can see on the command line (by omitting the ;) the instance variables (called properties in Matlab) of the object in question. Is this possible in python (I guess via IPython)?

理想情况下这样的类:

class MyClass(object):
    _x = 5

    @property
    def x(self):
        return self._x + 100

    @x.setter
    def x(self, value):
        self._x = value + 1

    def myFunction(self, y):
        return self.x ** 2 + y

会显示如下内容:

mc = Myclass()
mc
<package.MyClass> <superclass1> <superclass2>

Attributes:
_x: 5
 x: 105

Method Attributes:
myFunction(self, y)

这可以通过覆盖类的打印方法(如果出现这样的事情)来实现吗?或者通过ipython中的魔术方法?

Is that possible via overriding the print method (if such a thing exits) of the class? Or via a magic method in ipython?

推荐答案

简短的回答是没有办法获得所有属性的列表Python中的对象,因为属性可以动态生成。举一个极端的例子,考虑这个类:

The short answer is that there is no way to get a list of all attributes of an object in Python, because the attributes could be generated dynamically. For an extreme example, consider this class:

>>> class Spam(object):
...     def __getattr__(self, attr):
...         if attr.startswith('x'):
...             return attr[1:]
>>> spam = Spam()
>>> spam.xeggs
'eggs'

即使翻译可能有人想出一个列表所有属性,该列表都是无限的。

Even if the interpreter could someone figure out a list of all attributes, that list would be infinite.

对于简单的类, spam .__ dict __ 通常足够好。它不处理动态属性, __ slots __ 基于属性,类属性,C扩展类,从上面的大多数继承的属性,以及各种其他东西。但它至少是某种东西 - 有时,它是你想要的东西。对于第一个近似值,它正是您在 __ init __ 或更高版本中明确指定的内容,而不是其他内容。

For simple classes, spam.__dict__ is often good enough. It doesn't handle dynamic attributes, __slots__-based attributes, class attributes, C extension classes, attributes inherited from most of the above, and all kinds of other things. But it's at least something—and sometimes, it's the something you want. To a first approximation, it's exactly the stuff you explicitly assigned in __init__ or later, and nothing else.

For针对人类可读性的一切的尽力而为,使用 dir(垃圾邮件)

For a best effort aimed at "everything" aimed at human readability, use dir(spam).

为了尽力为程序化使用一切,请使用 inspect.getmembers(spam) 。 (虽然实际上实现只是CPython 2.x中 dir 的包装,它可以做更多 - 事实上在CPython 3.2中也是如此+。)

For a best effort aimed at "everything" for programmatic use, use inspect.getmembers(spam). (Although in fact the implementation is just a wrapper around dir in CPython 2.x, it could do more—and in fact does in CPython 3.2+.)

这些都会处理 __ dict __ 不能执行的各种操作,并且可能会跳过在 __ dict __ 但您不想看到。但它们本身仍然不完整。

These will both handle a wide range of things that __dict__ cannot, and may skip things that are in the __dict__ but that you don't want to see. But they're still inherently incomplete.

无论你使用什么,获取价值和关键都很容易。如果你正在使用 __ dict __ getmembers ,这是微不足道的; __ dict __ 通常是 dict ,或者是一个足够接近的东西dict 用于您的目的, getmembers 显式返回键值对。如果您使用 dir ,您可以非常轻松地获得 dict

Whatever you use, to get the values as well as the keys is easy. If you're using __dict__ or getmembers, it's trivial; the __dict__ is, normally, either a dict, or something that acts close enough to a dict for your purposes, and getmembers explicitly returns key-value pairs. If you're using dir, you can get a dict very easily:

{key: getattr(spam, key) for key in dir(spam)}

最后一件事:对象是一个含糊不清的术语。它可以表示从对象派生的类的任何实例,类的任何实例,新样式类的任何实例或任何值任何类型的(模块,类,功能等)。你几乎可以使用 dir getmembers ;文档中描述了这意味着什么的确切细节。

One last thing: "object" is a bit of an ambiguous term. It can mean "any instance of a class derived from object", "any instance of a class", "any instance of a new-style class", or "any value of any type at all" (modules, classes, functions, etc.). You can use dir and getmembers on just about anything; the exact details of what that means are described in the docs.

一个甚至是最后一件事:你可能会注意到 getmembers 返回类似('__ str__',<方法 - 包装'__str__'的垃圾邮件对象在0x1066be790> ),你可能不感兴趣。由于结果只是名称 - 值对,如果您只想删除 __ dunder __ 方法, _private 变量等。 , 这很简单。但通常,您希望过滤类型成员。 getmembers 函数采用过滤器参数,但是文档在解释如何使用它方面做得不是很好(而且,最重要的是,期望你理解描述符的方式工作)。基本上,如果你想要一个过滤器,它通常是可调用 lambda x:不可调用(x),或者 lambda inspect.isfoo 函数组合而成。

One even-last-er thing: You may notice that getmembers returns things like ('__str__', <method-wrapper '__str__' of Spam object at 0x1066be790>), which you probably aren't interested in. Since the results are just name-value pairs, if you just want to remove __dunder__ methods, _private variables, etc., that's easy. But often, you want to filter on the "kind of member". The getmembers function takes a filter parameter, but the docs don't do a great job explaining how to use it (and, on top of that, expect that you understand how descriptors work). Basically, if you want a filter, it's usually callable, lambda x: not callable(x), or a lambda made up of a combination of inspect.isfoo functions.

所以,这很常见,你可能想把它写成一个函数:

So, this is common enough you may want to write it up as a function:

def get_public_variables(obj):
    return [(name, value) for name, value 
            in inspect.getmembers(obj, lambda x: not callable(x))
            if not name.startswith('_')]

您可以将其转换为自定义IPython%魔术函数,或只是制作一个%宏,或者只是将其作为常规函数并明确调用它。

You can turn that into a custom IPython %magic function, or just make a %macro out of it, or just leave it as a regular function and call it explicitly.

在评论中,您询问是否可以将其打包到 __ repr __ 函数中,而不是尝试创建%magic函数或其他任何内容。

In a comment, you asked whether you can just package this up into a __repr__ function instead of trying to create a %magic function or whatever.

如果您已经从一个根类继承了所有类,那么这是一个好主意。您可以编写一个适用于所有类的 __ repr __ (或者,如果它适用于99%的类,则可以覆盖 __ repr __ 在另外1%)中,然后每当你评估解释器中的任何对象或打印出来时,你都会得到你想要的东西。

If you've already got all of your classes inheriting from a single root class, this is a great idea. You can write a single __repr__ that works for all of your classes (or, if it works for 99% of them, you can override that __repr__ in the other 1%), and then every time you evaluate any of your objects in the interpreter or print them out, you'll get what you want.

但是,请注意以下几点:

However, a few things to keep in mind:

Python同时具有 __ str __ (你得到的是什么)如果你打印一个对象)和 __ repr __ (如果你只是在交互式提示符下评估一个对象,你会得到什么)一个原因。通常,前者是一个很好的人类可读表示,而后者是 eval -able(或者可以打字到交互式提示符),或者简洁的角括号形式,让您足以区分对象的类型和身份。

Python has both __str__ (what you get if you print an object) and __repr__ (what you get if you just evaluate an object at the interactive prompt) for a reason. Usually, the former is a nice human-readable representation, while the latter is something that's either eval-able (or typable-into-the-interactive-prompt), or the concise angle-bracket form that gives you just enough to distinguish the type and identity of an object.

这只是一个约定而不是规则,所以你可以随意打破它。但是,如果你 打破它,你可能仍然想要使用 str / repr 区别 - 例如,make repr 为您提供所有内部的完整转储,而 str 显示只是有用的公共价值。

That's just a convention rather than a rule, so you can feel free to break it. However, if you are going to break it, you may still want to make use of the str/repr distinction—e.g., make repr give you a complete dump of all the internals, while str shows just the useful public values.

更严重的是,您必须考虑如何组成 repr 值。例如,如果您打印 repr a 列表,你有效地得到了'['+','。join(map(repr,item)))+']'。对于多行 repr ,这看起来很奇怪。如果你使用任何一种试图缩进嵌套集合的漂亮打印机,比如在IPython中内置的集合,那就更糟了。结果可能不会令人难以理解,它只是打败了漂亮的打印机所要提供的好处。

More seriously, you have to consider how repr values are composed. For example, if you print or repr a list, you get, effectively, '[' + ', '.join(map(repr, item))) + ']'. This is going to look pretty odd with a multi-line repr. And it'll be even worse if you use any kind of pretty-printer that tries to indent nested collections, like the one that's built into IPython. The result probably won't be unreadable, it'll just defeat the benefits that the pretty-printer is meant to provide.

至于你想要显示的具体内容:这一切都很简单。这样的事情:

As for the specific stuff you want to display: That's all pretty easy. Something like this:

def __repr__(self):
    lines = []

    classes = inspect.getmro(type(self))
    lines.append(' '.join(repr(cls) for cls in classes))

    lines.append('')
    lines.append('Attributes:')
    attributes = inspect.getmembers(self, callable)
    longest = max(len(name) for name, value in attributes)
    fmt = '{:>%s}: {}' % (longest, )
    for name, value in attributes:
        if not name.startswith('__'):
            lines.append(fmt.format(name, value))

    lines.append('')
    lines.append('Methods:')
    methods = inspect.getmembers(self, negate(callable))
    for name, value in methods:
        if not name.startswith('__'):
            lines.append(name)

    return '\n'.join(lines)

对属性名称进行右对齐是最困难的部分这里。 (我可能错了,因为这是未经测试的代码......)其他所有内容都很简单,或者很有趣(使用不同的过滤器来玩 getmembers 来看看他们做了什么)。

Right-justifying the attribute names is the hardest part here. (And I probably got it wrong, since this is untested code…) Everything else is either easy, or fun (playing with different filters to getmembers to see what they do).

这篇关于是否可以像在Matlab中一样在IPython中显示对象实例变量?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆