可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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.