是否可以像Matlab那样在IPython中显示对象实例变量?
我正试图从Matlab转向Python。而魔法呢?在IPython is nice中,Matlab的一个非常好的特性是,您可以在命令行(省略;)上看到所讨论对象的实例变量(在Matlab中称为属性)。这在python中可能吗(我想是通过IPython实现的) 理想情况下,像这样的类:是否可以像Matlab那样在IPython中显示对象实例变量?,python,matlab,ipython,Python,Matlab,Ipython,我正试图从Matlab转向Python。而魔法呢?在IPython is nice中,Matlab的一个非常好的特性是,您可以在命令行(省略;)上看到所讨论对象的实例变量(在Matlab中称为属性)。这在python中可能吗(我想是通过IPython实现的) 理想情况下,像这样的类: class MyClass(object): _x = 5 @property def x(self): return self._x + 100 @x.sett
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
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)
将显示如下内容:
mc = Myclass()
mc
<package.MyClass> <superclass1> <superclass2>
Attributes:
_x: 5
x: 105
Method Attributes:
myFunction(self, y)
mc=Myclass()
司仪
属性:
_x:5
x:105
方法属性:
myFunction(自我,y)
是否可以通过重写类的print方法(如果存在这样的方法)实现这一点?或者通过ipython?中的神奇方法,您可以使用
obj获取对象的实例变量。例如:
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
您可能会发现,对于可能有大量实例变量和方法的真实对象,这并不适用。简单的回答是,在Python中无法获得对象所有属性的列表,因为这些属性可以动态生成。对于一个极端的例子,考虑这个类:
>>> class Spam(object):
... def __getattr__(self, attr):
... if attr.startswith('x'):
... return attr[1:]
>>> spam = Spam()
>>> spam.xeggs
'eggs'
即使解释器能够找出所有属性的列表,该列表也是无限的
对于简单的类,spam.\uuu dict\uu
通常就足够了。它不处理动态属性、基于
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu>的属性、类属性、C扩展类、从上述大部分继承的属性以及所有其他类型的东西。但它至少是某种东西,有时,它是你想要的东西。第一个近似值是,它正是您在\uuuu init\uuuu
或更高版本中显式指定的内容,而不是其他内容
为了尽最大努力实现“一切”的可读性,请使用
为了尽最大努力实现“一切”的程序化使用,请使用。(虽然实际上,该实现只是CPython 2.x中dir
的包装,但它可以做得更多,事实上在CPython 3.2+中也可以做到。)
它们既可以处理\uuuuu dict\uuuu
无法处理的大量内容,也可以跳过\uuuu dict\uuuu
中您不想看到的内容。但它们本质上仍然是不完整的
无论您使用什么,获取值和键都很容易。如果您使用的是\uuu dict\uuu
或getmembers
,那么它很简单;\uuuu dict\uuuu
通常是一个dict
,或者是一个与dict
非常接近的对象,并且getmembers
显式返回键值对。如果您使用的是dir
,您可以非常轻松地获得dict
:
{key: getattr(spam, key) for key in dir(spam)}
最后一件事:“对象”是一个模糊的术语。它可以表示“从对象派生的类的任何实例”、“类的任何实例”、“新样式类的任何实例”或“任何类型的任何值”(模块、类、函数等)。你可以在任何事情上使用dir
和getmembers
;文件中详细描述了这意味着什么
还有最后一件事:您可能会注意到,getmembers
返回像(“str”、
)这样的东西,您可能对此不感兴趣。由于结果只是名称-值对,如果您只想删除\uu\dunder\uu
方法、\u private
变量等,这很容易。但通常,您希望筛选“类型的成员”。getmembers
函数接受一个过滤器参数,但是文档并没有很好地解释如何使用它(最重要的是,希望您了解描述符是如何工作的)。基本上,如果您想要一个过滤器,它通常是可调用的
,lambda x:不可调用的(x)
,或者由inspect.isfoo
函数组合而成的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函数,或者只使用它生成一个%宏,或者只将其作为常规函数并显式调用
在一篇评论中,您询问是否可以将其打包成一个\uuu repr\uuu
函数,而不是尝试创建一个%magic函数或其他任何函数
如果您已经从一个根类继承了所有类,那么这是一个好主意。您可以编写一个适用于所有类的\uuuuu repr\uuuuuu
(或者,如果它适用于99%的类,您可以在其他1%中重写该\uuuu repr\uuuuu
),然后每次在解释器中计算任何对象或打印它们时,您都会得到想要的结果
但是,要记住以下几点:
Python既有\uuuu str\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。通常,前者是一种很好的人类可读的表示形式,而后者要么是eval
-able(或可在交互提示中键入),要么是简洁的尖括号形式,让您刚好能够区分对象的类型和标识
这只是一个惯例而不是规则,所以你可以随意打破它。但是,如果您打算破坏它,您可能仍然希望利用str
/repr
的区别,例如,makerepr
为您提供所有内部文件的完整转储,而str
只显示有用的公共值
更严重的是,你必须考虑<代码> RPRP/COD>值是如何组成的。例如,如果您print
或repr
一个列表
,您将得到有效的'['+','.join(map(repr,item)))+']'
。如果使用多行repr
,这看起来会很奇怪。如果你使用任何一种漂亮的打印机来缩进嵌套的集合,比如
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}{} {:<} \n'
line = f.format(str(name), ':', str(value))
# p.text(str(name) + ': ' + str(value) + '\n')
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