我想写使用h5py模块长期储存深度嵌套组类,属性,绑定方法等,以一个HDF5文件。 我真的很接近。 我有我似乎无法化解的唯一的一招是一种以编程方式,在运行时,找出一种方法来确定,如果事情是一个类的实例的类型,而不是一个列表,INT,等我需要递归到类的实例,但显然不应该递归到一个int,float等这需要两个旧式和新式的类工作。 我研究的是不工作的东西/我不能让工作:
使用检查模块
>>> class R(object): pass
...
>>> _R = R()
>>> import inspect
>>> inspect.isclass(_R)
False
>>> inspect.isclass(R)
True
这是没有帮助的,我需要像函数inspect.isclassinstance(_R)
返回True
使用类型模块
如果你使用老式类,有一个叫做InstanceType类型匹配旧式的类的实例,如下面的代码
>>> import types
>>> class R(): pass #old-style class
...
>>> _R = R()
>>> import types
>>> type(_R) is types.InstanceType
True
>>> class R(object): pass #new-style class
...
>>> _R = R()
>>> type(_R) is types.InstanceType
False
但是如果你使用新式的类中有没有相应的类型types
虽然海报可能最有可能需要重新考虑他的设计,在某些情况下有正当需要在Python与创建类的实例内置/扩展类型,在C创建的实例,并区分class
的语句。 虽然两者都是两类,后者是一个类型的类别,因为它们的类型结构在运行时分配的CPython的内部称之为“堆型”。 这蟒蛇继续区分它们中可以看到__repr__
输出:
>>> int # "type"
<type 'int'>
>>> class X(object): pass
...
>>> X # "class"
<class '__main__.X'>
该__repr__
区别正是通过检查类型是否是一个堆型实现。
根据应用的具体需求,一个is_class_instance
功能,可以通过以下方式之一来实现:
# Built-in types such as int or object do not have __dict__ by
# default. __dict__ is normally obtained by inheriting from a
# dictless type using the class statement. Checking for the
# existence of __dict__ is an indication of a class instance.
#
# Caveat: a built-in or extension type can still request instance
# dicts using tp_dictoffset, and a class can suppress it with
# __slots__.
def is_class_instance(o):
return hasattr(o, '__dict__')
# A reliable approach, but one that is also more dependent
# on the CPython implementation.
Py_TPFLAGS_HEAPTYPE = (1<<9) # Include/object.h
def is_class_instance(o):
return bool(type(o).__flags__ & Py_TPFLAGS_HEAPTYPE)
编辑
下面是该函数的第二个版本的解释。 这真的测试的类型是否是一个“堆型”使用CPython的内部使用其自己的目的相同的测试。 这就确保了它将始终为(“类”)和False的非堆类型的实例堆类型的实例(“类型”,但也老式类,这是很容易解决)返回True。 它通过检查是否所述tp_flags
构件 C级的PyTypeObject
结构具有Py_TPFLAGS_HEAPTYPE
位设置。 实施薄弱的部分是它的硬编码的价值Py_TPFLAGS_HEAPTYPE
不断到当前观测值。 (因为不断不是由符号名暴露到Python这是必需的。)虽然理论上这个常数可能会改变,这是极不可能在实践中发生,因为这样的改变会无端破坏现有的扩展模块的ABI。 在看的定义Py_TPFLAGS
常量中Include/object.h
,显而易见的是,新的,而不会干扰旧的被小心地加入。 另一个缺点是,这种代码有机会零在非CPython的实现,如Jython或IronPython的运行。
感谢@ user4815162342,我已经能够得到这个工作。 这里有一个稍微修改后的版本,将返回True为旧式和新型类的实例:
#Added the check for old-style class
Py_TPFLAGS_HEAPTYPE = (1L<<9) # Include/object.h
def is_class_instance(o):
import types
return (bool(type(o).__flags__ & Py_TPFLAGS_HEAPTYPE)
or type(o) is types.InstanceType)
TL;博士 只需调用is_object_pure_python()
远,远低于定义的函数。
像ibell ,我尽职尽责地留下深刻的印象user4815162342的权威的Python 2.x的具体的解决方案 。 一切都没有得到很好的Python的天堂,但是。
问题。 问题无处不在。
该解决方案(虽然有见地)遭受了一点一点腐烂通过简单的编辑,包括不平凡解析:
- 的
L
类型后缀是下的Python 3.x的不支持的 诚然,平凡解析。 - 横解释
is_class_instance()
执行没有考虑具有优化的纯Python类__slots__
。 - CPython的特定
is_class_instance()
在非CPython的解释(例如,pypy)执行失败。 - 用于检测是否类没有类似的实现(而不是类实例 )是纯Python或基于℃。
解决方案! 解决方案无处不在!
为了解决这些问题,以下Python特定3.x的溶液滴L
,检测__slots__
,已重构以选择更加可靠的CPython特异性is_class_instance()
CPython的正在执行,回退到较少可靠的跨解释is_class_instance()
下的所有其他解释的实施, 并已推广到同时检测类和类实例。
对于理智,让我们先检测类的实例:
import platform
# If the active Python interpreter is the official CPython implementation,
# prefer a more reliable CPython-specific solution guaranteed to succeed.
if platform.python_implementation() == 'CPython':
# Magic number defined by the Python codebase at "Include/object.h".
Py_TPFLAGS_HEAPTYPE = (1<<9)
def is_instance_pure_python(obj: object) -> bool:
'''
`True` if the passed object is an instance of a pure-Python class _or_
`False` if this object is an instance of a C-based class (either builtin
or defined by a C extension).
'''
return bool(type(obj).__flags__ & Py_TPFLAGS_HEAPTYPE)
# Else, fallback to a CPython-agnostic solution typically but *NOT*
# necessarily succeeding. For all real-world objects of interest, this is
# effectively successful. Edge cases exist but are suitably rare.
else:
def is_instance_pure_python(obj: object) -> bool:
'''
`True` if the passed object is an instance of a pure-Python class _or_
`False` if this object is an instance of a C-based class (either builtin
or defined by a C extension).
'''
return hasattr(obj, '__dict__') or hasattr(obj, '__slots__')
证明在圭多的布丁
单元测试展示了令人不安的事实:
>>> class PurePythonWithDict(object): pass
>>> class PurePythonWithSlots(object): __slots__ = ()
>>> unslotted = PurePythonWithDict()
>>> slotted = PurePythonWithSlots()
>>> is_instance_pure_python(unslotted)
True
>>> is_instance_pure_python(slotted)
True
>>> is_instance_pure_python(3)
False
>>> is_instance_pure_python([3, 1, 4, 1, 5])
False
>>> import numpy
>>> is_instance_pure_python(numpy.array((3, 1, 4, 1, 5)))
False
这是否推广到类,而实例?
是的,但这样做是不平凡的。 检测类 (而不是类实例 )是否是纯Python或基于C是奇怪困难。 为什么? 因为即使是基于C语言的类提供了__dict__
属性。 因此, hasattr(int, '__dict__') == True
。
尽管如此,在这是一个哈克的方式有一个哈克意志。 对于未知( 可能是平庸的 )原因, dir()
内置剥去__dict__
仅基于C-类其返回的列表属性名称。 因此,检测一个类是否是纯Python或基于下在横解释的方式减少了迭代地搜索由返回的列表dir()
为__dict__
。 为了胜利:
import platform
# If the active Python interpreter is the official CPython interpreter,
# prefer a more reliable CPython-specific solution guaranteed to succeed.
if platform.python_implementation() == 'CPython':
# Magic number defined by the Python codebase at "Include/object.h".
Py_TPFLAGS_HEAPTYPE = (1<<9)
def is_class_pure_python(cls: type) -> bool:
'''
`True` if the passed class is pure-Python _or_ `False` if this class
is C-based (either builtin or defined by a C extension).
'''
return bool(cls.__flags__ & Py_TPFLAGS_HEAPTYPE)
# Else, fallback to a CPython-agnostic solution typically but *NOT*
# necessarily succeeding. For all real-world objects of interest, this is
# effectively successful. Edge cases exist but are suitably rare.
else:
def is_class_pure_python(cls: type) -> bool:
'''
`True` if the passed class is pure-Python _or_ `False` if this class
is C-based (either builtin or defined by a C extension).
'''
return '__dict__' in dir(cls) or hasattr(cls, '__slots__')
更多的证据。 更多布丁。
更多测试驱动感实性:
>>> class PurePythonWithDict(object): pass
>>> class PurePythonWithSlots(object): __slots__ = ()
>>> is_class_pure_python(PurePythonWithDict)
True
>>> is_class_pure_python(PurePythonWithSlots)
True
>>> is_class_pure_python(int)
False
>>> is_class_pure_python(list)
False
>>> import numpy
>>> is_class_pure_python(numpy.ndarray)
False
这一切,她写
对于一般性,让我们统一以上定义为两个高级功能支持在所有可能的Python解释所有可能类型的低级别的功能:
def is_object_pure_python(obj: object) -> bool:
'''
`True` if the passed object is either a pure-Python class or instance of
such a class _or_ `False` if this object is either a C-based class
(builtin or defined by a C extension) or instance of such a class.
'''
if isinstance(obj, type):
return is_class_pure_python(obj)
else:
return is_instance_pure_python(obj)
def is_object_c_based(obj: object) -> bool:
'''
`True` if the passed object is either a C-based class (builtin or
defined by a C extension) or instance of such a class _or_ `False` if this
object is either a pure-Python class or instance of such a class.
'''
return not is_object_pure_python(obj)
看哪! 纯Python。
文章来源: In python at runtime determine if an object is a class (old and new type) instance