ipython matlab,关于python:可以像在Matlab中一样在IPython中显示对象实例变量吗?

我正试图从matlab转向python。而魔法呢?在ipython中,Matlab的一个非常好的特性是,您可以在命令行(通过省略;)上看到相关对象的实例变量(在Matlab中称为属性)。这在Python中是可能的吗(我猜是通过i python实现的)?

理想情况下是这样的一个类:

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

Attributes:

_x: 5

x: 105

Method Attributes:

myFunction(self, y)

是否可以通过重写类的print方法(如果存在这样的东西)来实现?或是通过伊普敦的魔法方法?

尝试在对象名称后面写一个点,然后双击选项卡,例如myobj.。这就是你要找的那种东西吗?

这似乎只是列出了实例变量和方法,这些变量和方法很接近,但不完全相同。我还想看看实例变量的值…

您定义属性的方式很奇怪,它是一个由类属性(MyClass._x)支持的每个实例属性,直到您第一次设置它,这时您创建了一个隐藏类属性的实例属性(mc._x)。这种行为实际上是有用的,但我怀疑这是类和实例成员之间混淆的迹象。

简短的答案是,在Python中无法获取对象所有属性的列表,因为这些属性可以动态生成。对于一个极端的例子,考虑这个类:好的。

>>> class Spam(object):

...     def __getattr__(self, attr):

...         if attr.startswith('x'):

...             return attr[1:]

>>> spam = Spam()

>>> spam.xeggs

'eggs'

即使解释器能让人找出所有属性的列表,这个列表也是无限的。好的。

对于简单的类,spam.__dict__通常足够好。它不处理动态属性、基于__slots__的属性、类属性、C扩展类、从上面大部分继承的属性,以及其他各种事情。但这至少是你想要的,有时也是你想要的。第一个近似值是,它正是您在__init__或更高版本中明确指定的内容,而不是其他内容。好的。

为了最大限度地提高"一切"的可读性,请使用dir(spam)。好的。

为了尽最大努力实现"一切"的程序化使用,请使用inspect.getmembers(spam)。(尽管事实上,在cpython 2.x中,实现只是围绕dir的包装,但它可以做得更多,实际上在cpython 3.2+中也可以做得更多。)好的。

这两种方法都可以处理__dict__所不能处理的各种事情,并且可以跳过__dict__中的那些你不想看到的事情。但它们本身仍然是不完整的。好的。

无论您使用什么,获取值和键都很容易。如果您使用的是__dict__或getmembers,这很简单;__dict__通常是dict,或者是与dict非常接近的东西,用于您的目的,并且getmembers显式返回键值对。如果你使用的是dir,你可以很容易地得到dict:好的。

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

最后一件事:"对象"是一个含糊不清的术语。它可以是"派生自object的类的任何实例"、"类的任何实例"、"新样式类的任何实例"或"任何类型的任何值"(模块、类、函数等)。你可以在任何事情上使用dir和getmembers;这意味着什么的确切细节在文档中描述。好的。

最后一件事是:你可能会注意到getmembers会返回你可能不感兴趣的东西,比如('__str__',。由于结果只是名称-值对,如果您只想删除__dunder__方法、_private变量等,这很容易。但通常情况下,您希望筛选"某种成员"。getmembers函数接受一个过滤参数,但文档并不能很好地解释如何使用它(除此之外,还希望您了解描述符是如何工作的)。基本上,如果您想要一个过滤器,它通常是由inspect.isfoo函数组合而成的callable、lambda x: not callable(x)或lambda。好的。

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

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%magic函数,或者从中生成一个%宏,或者将其保留为一个常规函数并显式调用它。好的。

在一条评论中,您询问是否可以将其打包成一个__repr__函数,而不是试图创建一个%魔力函数或其他什么函数。好的。

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

但是,要记住的一些事情:好的。

由于某种原因,python同时拥有__str__(如果你是print)和__repr__(如果你只是在交互提示下评估一个对象,你会得到什么)。通常,前者是一种很好的人类可读的表示,而后者是一种既可以用eval表示(也可以用交互式提示进行打字),也可以是一种简洁的尖括号形式,使您能够很好地区分对象的类型和标识。好的。

这只是惯例而不是规则,所以你可以随意打破它。但是,如果你打算打破它,你可能仍然想利用str和repr的区别,例如,让repr给你一个完整的内部信息,而str只显示有用的公共价值。好的。

更严重的是,您必须考虑repr值是如何组成的。例如,如果您使用print或repra list,您实际上可以使用'[' + ', '.join(map(repr, item))) + ']'。使用多行repr会让这看起来很奇怪。如果你使用任何一种漂亮的打印机来缩进嵌套的集合,比如内置在IPython中的集合,情况会更糟。结果可能不会是不可读的,它只会破坏漂亮的打印机所提供的好处。好的。

至于你想展示的具体内容:这很容易。像这样:好的。

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 '

'.join(lines)

正确地证明属性名是最困难的部分。(我可能搞错了,因为这是未经测试的代码…)其他的事情要么简单,要么有趣(对getmembers使用不同的过滤器来查看它们的功能)。好的。好啊。

inspect.getmembers(spam)似乎非常接近我要找的(除了列表中的前18个条目)。是否可以重写类的print方法,以便获得(新编辑的)原始问题中描述的行为?

…我是说,而不是一个ipython魔法函数。有没有办法让它成为默认行为?

我可以写一个超类,在那里我重写__repr__来完成我所描述的,然后确保我的所有子类都继承自这个超类吗?

是的,如果您希望所有类都有一个超类,这是一个很好的解决方案。您可能会考虑覆盖__repr__和__str__,这样您就可以在ipython提示下评估obj时提供详细的内部信息,但在print时更简洁易读,但在其他情况下是肯定的。

通过实现_repr_pretty_,我能够用ipython(至少大致上)实现我想要的:

def get_public_variables(obj):

from inspect import getmembers

return [(name, value) for name, value in

getmembers(obj, lambda x: not callable(x)) if

not name.startswith('__')]

class MySuperClass(object):

def _repr_pretty_(self, p, cycle):

for (name, value) in get_public_variables(self):

f = '{:>12}{} {:

'

line = f.format(str(name), ':', str(value))

# p.text(str(name) + ': ' + str(value) + '

')

p.text(line)

class MyClass(MySuperClass):

_x = 5

@property

def x(self):

return self._x + 100

给了我:

mc = MyClass()

mc

Out[15]:

_x: 5

x: 105

很明显,在空白等方面还需要进行一些微调,但这正是我试图完成的工作。

您可以使用obj.__dict__获取对象的实例变量,例如:

class Dog:

def __init__(self, name, age):

self.name = name

self.age = age

d1 = Dog("Fido", 7)

for key, val in d1.__dict__.items():

print(key,":", val)

输出:

age :  7

name :  Fido

但是,您可能会发现,对于可能具有大量实例变量和方法的实际对象,这并不适用。

它似乎也不包括在class Dog:行和def __init__行之间声明的实例变量…

当然,对于不使用__dict__的对象(例如,因为它们有__slots__或者它们在c中实现,或者它们有一个执行上述操作之一的基类)或者具有__dict__但也有自定义__getattr__和朋友的对象,或者……

@用户1507844:这些不是实例变量,它们是类变量。(但你是对的,它不会显示出来。)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值