用于python类的Str方法,该方法重新构造类源
如何为类配备打印类本身的源(不包括方法定义)的用于python类的Str方法,该方法重新构造类源,python,python-2.7,fixtures,quine,Python,Python 2.7,Fixtures,Quine,如何为类配备打印类本身的源(不包括方法定义)的\uuu str\uu方法 我排除方法定义,因为我的用例是动态生成装置(使用fixtures包;这与django装置不同),我希望将这些装置存储在文件中。对于那些不知道的人来说,fixtures包使用python类来表示fixture数据 这似乎是一种甚至可以内置到fixture中的东西,因为在我看来,这将是一个中等常见的用例。您可以使用元类来实现这一点。这里我省略了private(以下划线开头)和可调用对象(方法、内部类等)。只包括直接在类上定义的
\uuu str\uu
方法
我排除方法定义,因为我的用例是动态生成装置(使用fixtures
包;这与django装置不同),我希望将这些装置存储在文件中。对于那些不知道的人来说,fixtures
包使用python类来表示fixture数据
这似乎是一种甚至可以内置到fixture中的东西,因为在我看来,这将是一个中等常见的用例。您可以使用元类来实现这一点。这里我省略了private(以下划线开头)和可调用对象(方法、内部类等)。只包括直接在类上定义的属性(正确列出了基类,因此这不应该是问题) 在Python 3中,需要以另一种方式指定元类:
class Mine(metaclass=ClassSourceMeta):
a = 42
b = 13
请注意,属性需要具有合理的repr()
s。如果它们是类实例,你可能会得到语法上无效的东西,比如a=
,除非你为它们编写了一个好的\uuuuu repr\uuu
方法。对于一些基本的东西,比如数字和字符串,甚至是列表和口述,你都可以
还要注意的是,属性不一定按照定义的顺序出现;属性存储在不保留插入顺序的dict
中。不过Python不会在意的
如果fixtures
模块已经使用了一个元类,那么您可能需要从该元类继承而不是type
,或者对其元类进行monkey-patch。在Python2.x上,这将需要为\uuu str\uu
类制作一个方法包装器:
from types import MethodType
def __str__(cls):
return "class %s(%s):\n\n%s\n" % (cls.__name__,
", ".join(k.__name__ for k in cls.__bases__),
"\n".join(" %s = %r" % (k, v) for (k, v) in
cls.__dict__.items() if not (k.startswith("_") or callable(v))))
MetaclassToPatch.__str__ = MethodType(__str__, None, MetaclassToPatch)
MetaclassToPatch.__repr__ = MetaclassToPatch.__str__
您是否查看了
inspect
模块中的相关功能?这将是一个很好的起点。您可能需要检索类的源代码并手动删除方法定义。如果在执行此操作时遇到问题,您可以提出一个更具体的问题来说明您的尝试。不确定这是否是您所要求的,但inspect模块有一个inspect.getsource(obj)方法,该方法可能就是您所寻找的。虽然我不确定它有哪些依赖项才能读取该源代码。动态生成要作为代码执行的文本?我通常认为这是错误的方法。诸如继承、闭包、eval()
、compile()
等似乎涵盖了大多数/所有动态环境用例。设备在存储时是否需要人类可读?如果没有,为什么不直接腌制它们呢?@JAB对于那些不知道的人来说,fixtures包使用python类来表示fixture数据。太棒了,谢谢!为了处理内部类(fixtures模块使用内部类来表示数据库行/实例,其中内部类包含键值对),我还需要对此进行一些处理。我意识到我的问题中没有明确说明内部类的情况。事实上,我可以为外部类和内部类使用不同的元类来干净地完成这项工作。。。基本上给他们相同的元类,然后你必须有一些代码来缩进他们。不幸的是,如果你这么做的话,我认为我的一句话是不可行的。事实上,这对我不起作用。您的测试代码确实有效。我正在修补现有的元类。呵呵。你可能需要为它做一个方法包装器。午饭后我看看能不能搞定。谢谢。对于我的用例,我通过基于您的方法显式调用函数解决了这个问题,因为我只有两个级别。
from types import MethodType
def __str__(cls):
return "class %s(%s):\n\n%s\n" % (cls.__name__,
", ".join(k.__name__ for k in cls.__bases__),
"\n".join(" %s = %r" % (k, v) for (k, v) in
cls.__dict__.items() if not (k.startswith("_") or callable(v))))
MetaclassToPatch.__str__ = MethodType(__str__, None, MetaclassToPatch)
MetaclassToPatch.__repr__ = MetaclassToPatch.__str__