在Python中确定变量是一个新式的类?

Identifying that a variable is a new-style class in Python?

我使用的是python 2.x,我想知道是否有一种方法来判断变量是否是一个新的样式类?我知道如果这是一个老式的课程,我可以做以下的事情来了解。

1
2
3
4
5
6
7
8
9
10
11
import types

class oldclass:
  pass

def test():
  o = oldclass()
  if type(o) is types.InstanceType:
    print 'Is old-style'
  else:
    print 'Is NOT old-style'

但我还没有找到适合新课程的东西。我发现了这个问题,但所提出的解决方案似乎没有如预期的那样有效,因为简单的值被标识为类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import inspect

def newclass(object):
  pass

def test():
  n = newclass()
  if inspect.isclass(n):
    print 'Is class'
  else:
    print 'Is NOT class'
  if inspect.isclass(type(n)):
    print 'Is class'
  else:
    print 'Is NOT class'
  if inspect.isclass(type(1)):
    print 'Is class'
  else:
    print 'Is NOT class'
  if isinstance(n, object):
    print 'Is class'
  else:
    print 'Is NOT class'
  if isinstance(1, object):
    print 'Is class'
  else:
    print 'Is NOT class'

有没有什么办法可以这样做?或者说,python中的所有东西都只是一个类,没有办法绕过它?


我认为您要问的是:"我可以测试一个类是否在Python代码中被定义为一个新的样式类吗?".技术上简单的类型,如int是新的样式类,但是仍然可以区分用python编写的类和内置类型。

这是一些有用的东西,尽管它有点像黑客:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def is_new_style(cls):
    return hasattr(cls, '__class__') \
           and \
           ('__dict__' in dir(cls) or hasattr(cls, '__slots__'))


class new_style(object):
    pass

class old_style():
    pass

print is_new_style(int)
print is_new_style(new_style)
print is_new_style(old_style)

python 2.6的输出:

1
2
3
False
True
False

以下是另一种方法:

1
2
def is_new_style(cls):
    return str(cls).startswith('<class ')


我相信这就足够了:

1
2
3
4
5
def is_new_style_class(klass):
    return issubclass(klass, object)

def is_new_style_class_instance(instance):
    return issubclass(instance.__class__, object)

通常情况下,您只需要is_new_style_class功能就可以了。不是类的所有内容都将抛出一个TypeError,因此您可能希望将其更新为:

1
2
3
4
5
def is_new_style_class(klass):
    try:
        return issubclass(klass, object)
    except TypeError:
        return False

实例:

1
2
3
4
5
6
7
8
9
10
11
12
>>> class New(object): pass
...
>>> is_new_style_class(New)
True
>>> class Old: pass
...
>>> is_new_style_class(Old)
False
>>> is_new_style_class(1)
False
>>> is_new_style_class(int)
True

int是一个类型,根据定义,它是一个新的样式类(参见python 2.2中的统一类型和类),或者,如果您愿意,新的样式类是根据定义类型。


不是"一切都是一个阶级":你遇到的是"一切都是一个对象"(即,每一个(新风格)的事物都是从"对象"下降的)。

但是新样式的类本身就是一个"类型"(实际上,它们是为了将类和类型结合在一起而引入的)。所以你可以试着检查

1
2
3
import types

type(o) == types.TypeType

那能解决你的问题吗?


检查旧样式的类真的很容易。只需检查type(cls) is types.ClassType。检查新样式的类也很容易,isinstance(cls, type)。请注意,内置类型也是新样式的类。

似乎没有什么简单的方法来区分内置的和用Python编写的类。带有槽的新样式类也没有槽,就像intstr一样。如果类元类重写了uu str_uuu方法,则检查str(cls)是否与预期模式匹配失败。其他一些也不起作用的方法:

  • cls.__module__ == '__builtin__'(您可以在类上重新分配模块)
  • not any(value is cls for value in vars(__builtins__).values())(您可以向内置模块添加内容)。

内置类型和用户定义类型的统一性是如此之好,以至于区分它们是一个非常重要的问题,这对您来说应该意味着基础点。你真的不应该区分它们。如果对象实现了预期的协议,那么对象是什么并不重要。