Identifying that a variable is a new-style class i

2019-03-15 05:48发布

问题:

I'm using Python 2.x and I'm wondering if there's a way to tell if a variable is a new-style class? I know that if it's an old-style class that I can do the following to find out.

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'

But I haven't been able to find anything that works for new-style classes. I found this question, but the proposed solutions don't seem to work as expected, because simple values as are identified as classes.

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'

So is there anyway to do something like this? Or is everything in Python just a class and there's no way to get around that?

回答1:

I think what you are asking is: "Can I test if a class was defined in Python code as a new-style class?". Technically simple types such as int are new-style classes, but it is still possible to distinguish classes written in Python from the built-in types.

Here's something that works, although it's a bit of a hack:

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)

Output from Python 2.6:

False
True
False

Here's a different way to do it:

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


回答2:

I believe this suffices:

def is_new_style_class(klass):
    return issubclass(klass, object)

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

Typically, you only need the is_new_style_class function for your purposes. Everything not a class will throw a TypeError, so you might want to update it to:

def is_new_style_class(klass):
    try:
        return issubclass(klass, object)
    except TypeError:
        return False

Examples:

>>> 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, being a type, is by definition a new-style class (see Unifying types and classes in Python 2.2 ), or —if you prefer— new-style classes are by definition types.



回答3:

It's not that "everything is a class": what you're bumping into is that "everything is an object" (that is, every (new-style) thing descends from "object").

But new-style classes are a "type" themselves (actually, the were introduced to bring classes and types together). So you can try checking for

import types

type(o) == types.TypeType

Does that solve your problem?



回答4:

Checking for old-style classes is really easy. Just check type(cls) is types.ClassType. Checking for new-style classes is also easy, isinstance(cls, type). Note that the built-in types are also new-style classes.

There seems to be no trivial way to distinguish built-ins from classes written in Python. New-style classes with __slots__ also don't have __dict__, just like int or str. Checking if str(cls) matches the expected pattern fails if the classes metaclass overrides the __str__ method. Some other ways that also don't work:

  • cls.__module__ == '__builtin__' (you can reassign __module__ on classes)
  • not any(value is cls for value in vars(__builtins__).values()) (you can add stuff to the __builtin__ module).

The fact that unification of builtin and userdefined types is so good that distinguishing them is non-trivial problem should imply to you the underlying point. You really shouldn't have to distinguish between them. It doesn't matter what the object is if it implements the expected protocol.