我怎样才能为一个类配备一个__str__
打印类本身的源的方法,不包括方法定义?
我排除了方法定义,因为我的用例是动态生成固定装置(使用fixtures
包;这与 django 固定装置不同),并且我想将这些固定装置存储在文件中。对于那些不知道的人,该fixtures
包使用 python 类来表示夹具数据。
这似乎是一种甚至可以内置到固定装置中的东西,因为在我看来,这将是一个比较常见的用例。
我怎样才能为一个类配备一个__str__
打印类本身的源的方法,不包括方法定义?
我排除了方法定义,因为我的用例是动态生成固定装置(使用fixtures
包;这与 django 固定装置不同),并且我想将这些固定装置存储在文件中。对于那些不知道的人,该fixtures
包使用 python 类来表示夹具数据。
这似乎是一种甚至可以内置到固定装置中的东西,因为在我看来,这将是一个比较常见的用例。
您可以使用元类来做到这一点。在这里,我省略了私有(以下划线开头)和可调用对象(方法、内部类等)。仅包含直接在类上定义的属性(正确列出了基类,因此这应该不是问题)。
class ClassSourceMeta(type):
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))))
__repr__ = __str__
class Mine(object):
__metaclass__ = ClassSourceMeta
a = 42
b = 13
print(Mine)
在 Python 3 中,您需要以另一种方式指定元类:
class Mine(metaclass=ClassSourceMeta):
a = 42
b = 13
注意属性需要有合理repr()
的s。如果它们是类实例,你可能会得到语法上无效的东西,比如a = <__main__.Mine object at 0x02AA4870>
除非你为它们编写一个好的__repr__
方法。对于基本的东西,比如数字和字符串,甚至是列表和字典,你都会被覆盖。
另请注意,属性不一定按照它们定义的顺序出现;属性存储在dict
不保留插入顺序的 a 中。不过,Python 不会在意。
如果fixtures
模块已经使用了元类,您可能需要从该元类继承而不是type
,或者对其元类进行猴子补丁。在 Python 2.x 上,这将需要为__str__
类创建一个方法包装器:
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__