研究对象的工具
Python 3中的以下工具可用于研究对象之间以及对象与类型之间的关系。
- isinstance(obj, class): 用于判断一个对象是否是指定类型的实例。
- id(obj): 返回一个对象的标识。
- type(obj): 返回对象的类型。
- is: 判断两个对象是否相同(即标识相等),这与’=='是不一样的。
使用举例如下。
import collections
# all 4 are objects
obj1=100
obj2=int(100)
obj3=[1,2,3]
obj4=list([1, 2, 3])
# type & isinstance
print(type(obj1), isinstance(obj1, int), isinstance(obj1, object))
print(type(obj2), isinstance(obj2, int), isinstance(obj2, object))
print(type(obj3), isinstance(obj3, list), isinstance(obj3, collections.abc.Sequence), isinstance(obj3, object))
print(type(obj4), isinstance(obj4, list), isinstance(obj4, collections.abc.Sequence), isinstance(obj4, object))
# id
print(id(obj1), id(obj2), id(obj3), id(obj4))
# is vs '=='
print(obj1 is obj2, obj1 == obj2)
print(obj3 is obj4, obj3 == obj4)
<class 'int'> True True
<class 'int'> True True
<class 'list'> True True True
<class 'list'> True True True
4328187728 4328187728 4360572608 4360000128
True True
False True
从上面的例子可以看出,即使是一个数字,它也是一个对象,是class int的一个实例。另外,两个对象相等并不代表两个对象相同,比如例子中的obj3和obj4。相同是指两个对象的id一样。
一切皆对象
在Python 3中有句名言叫做"一切皆对象"。一个整数,一个字符串,一个变量,一个函数,一个模块,一个类型(class),都是一个对象,即某种类型的一个实例。
类型对象
类型对象是指代表类型信息的对象。说到类型对象,可能会引起误解。比如说一个int对象,到底是表示int类型本身信息的对象呢,还是一个int类型的实例。为了避免歧义,本文中采用"某类型的实例"这样的说法。比如整数100是一个int类型的实例,整数200也是一个int类型的实例,字符串’hello’则是一个str类型的实例。对于常见类型,可以创建很多个实例。而类型信息本身,也可以用一个type类型的实例来表示。见下面的代码。
obj_1=int
obj_2=int(100)
obj_3=obj_1(200)
obj_4=str
obj_5=tuple
# obj_1: an instance of class int, representing an integer
print(type(obj_1), obj_1)
# obj_2: an instance of class type, representing class int
print(type(obj_2), obj_2)
# obj_3: an instance of class type, representing class int
print(type(obj_3), obj_3)
# obj_4: an instance of class type, representing class str
print(type(obj_4), obj_4)
# obj_5: an instance of class type, representing class tuple
print(type(obj_5), obj_5)
<class 'type'> <class 'int'>
<class 'int'> 100
<class 'int'> 200
<class 'type'> <class 'str'>
<class 'type'> <class 'tuple'>
从上面的代码及其输出可知:
- 当直接写出一个类名时,其实它也是一个对象,这跟直接写出一个数字一样,都属于的字面值对象。而且这个对象的类型是type,即它是type类型的一个实例。比如obj_1是type类型的实例,所表示的类型是int;obj_2也是type类型的实例,所表示的类型则是str;obj_3也是type类型的实例,所表示的信息是tuple。可见,可以有很多个type类型的实例,他们分别表示不同的类型(class)。
- 使用type类型的实例,可以创建该实例所表示的类型的一个实例。比如obj_1表示的是int类型,因此可通过obj_1创创建一个int类型的实例,即一个整数。
对于type类型的实例,也就是这里说的类型对象,如果所表示的是同一个类型,那么它只有一个实例,也就是单实例模式。这和None对象有点类似。下面的代码说明了这一点。
obj_1=int
obj_2=type(100)
obj_3=type(1000)
print(id(obj_1), id(obj_2), id(obj_3))
print(obj_1 is obj_2, obj_2 is obj_3)
obj_1=str
obj_2=type('hello')
obj_3=type('world')
print(id(obj_1), id(obj_2), id(obj_3))
print(obj_1 is obj_2, obj_2 is obj_3)
4328026000 4328026000 4328026000
True True
4328063920 4328063920 4328063920
True True
一个type类型的实例可以表示class int,class str,或者class list等等。那么class type又用什么表示呢?答案是并无特殊性,也用一个type类型的实例来表示。也就是说,程序中存在一个type类型的实例,它表示的是type类型。见下面的代码。
obj=type
print(type(obj), obj)
obj_2=type(obj)
print(type(obj_2), obj_2)
print(obj is obj_2)
obj_3=type(type(type(type(type(obj)))))
print(type(obj_3), obj_3)
print(obj is obj_3)
<class 'type'> <class 'type'>
<class 'type'> <class 'type'>
True
<class 'type'> <class 'type'>
True
前面例子中的对象是一个type类型的实例,它所表示的类型也是class type。这种对象有一个特殊用途就是可以创建新类型。下面的例子用表示type类型的type类型的实例obj创建了一个新的类型MyClass,该类型有一个属性myvalue;然后创建了一个MyClass类型的实例obj_2。由此可见Python动态类型的强大。详见代码。
obj=type(type)
cls=obj('MyClass', (object,), {'myvalue': 1})
print(type(cls), cls)
obj_2=cls()
print(type(obj_2), obj_2)
print(cls.myvalue, obj_2.myvalue)
obj_2.myvalue=100
print(cls.myvalue, obj_2.myvalue)
<class 'type'> <class '__main__.MyClass'>
<class '__main__.MyClass'> <__main__.MyClass object at 0x103e97910>
1 1
1 100
函数对象
Python 3中的函数也可以作为一个对象。见下面的示例。
print_func=print
print(type(print), type(print_func), print_func)
print_func('Hello, World!')
def myfunc():
print("inside myfunc")
func_obj = myfunc
print(type(myfunc), type(func_obj), func_obj)
func_obj()
<class 'builtin_function_or_method'> <class 'builtin_function_or_method'> <built-in function print>
Hello, World!
<class 'function'> <class 'function'> <function myfunc at 0x103e6f040>
inside myfunc
从上面的结果可见,函数的类型还不只一种。比如print函数是class builtin_function_or_method,而自定义函数则是class function。通过函数对象(函数类型的实例)调用函数,跟直接用函数名调用函数很类似,都是在函数对象后面加一个()并传入参数。那么对于任意一个对象,如果给它加上(),Python如何知道能不能调用函数呢?答案在于Callable接口,该接口定义了方法__call__()。如果一个对象的类型实现了该接口,则表明是可调用的,就能调用函数。函数调用的本质,其实就是调用该函数对象的__call__接口。再多解释一下,上面的例子中,myfunc和func_obj其实是一回事,都是函数对象。在Python 3中,如果只写出一个函数名,那么它被当成一个字面值对象,其类型为class function,这和前面一个类名也表示一个字面值对象是一个道理,这也说明一切皆对象。下面的示例代码也能说明这一点。
class Callable(builtins.object)
| Methods defined here:
|
| __call__(self, *args, **kwds)
| Call self as a function.
import collections
cls=type(myfunc)
print(issubclass(cls, collections.abc.Callable))
func_obj.__call__()
myfunc.__call__()
True
inside myfunc
inside myfunc
在表示类型信息的实例中,如果表示的是同一个类型信息,那么实例唯一。对于函数是否如此呢?答案是肯定的。表示同一个函数信息的class function实例是唯一的。
print(func_obj is myfunc)
True
以下是函数类型class function的信息。
Help on class function in module builtins:
class function(object)
| function(code, globals, name=None, argdefs=None, closure=None)
|
| Create a function object.
|
| code
| a code object
| globals
| the globals dictionary
| name
| a string that overrides the name from the code object
| argdefs
| a tuple that specifies the default argument values
| closure
| a tuple that supplies the bindings for free variables
|
| Methods defined here:
|
| __call__(self, /, *args, **kwargs)
| Call self as a function.
|
| __get__(self, instance, owner, /)
| Return an attribute of instance, which is of type owner.
|
| __repr__(self, /)
| Return repr(self).
|
| ----------------------------------------------------------------------
| Static methods defined here:
|
| __new__(*args, **kwargs) from builtins.type
| Create and return a new object. See help(type) for accurate signature.
|
| ----------------------------------------------------------------------
| Data descriptors defined here:
|
| __annotations__
|
| __closure__
|
| __code__
|
| __defaults__
|
| __dict__
|
| __globals__
|
| __kwdefaults__
def myfunc2(arg1, arg_def='default'):
'myfunc2'
print('inside myfunc2')
print(myfunc2.__annotations__)
print(myfunc2.__defaults__)
print(myfunc2.__doc__)
{}
('default',)
myfunc2
模块对象
跟类型和函数类似,Python 3中的模块也是对象,其类型为class module。当写出一个模块名时,它其实是字面值对象,也就是class module类型的一个实例。以下是class module的定义,从中可以看到模块类型支持__dir__()方法,因此可以用dir()函数来浏览一个模块内的属性、方法、类型等。模块类型的__dict__属性也是类似的作用。
class module(object)
| module(name, doc=None)
|
| Create a module object.
|
| The name must be a string; the optional doc argument can have any type.
|
| Methods defined here:
|
| __delattr__(self, name, /)
| Implement delattr(self, name).
|
| __dir__(...)
| __dir__() -> list
| specialized dir() implementation
|
| __getattribute__(self, name, /)
| Return getattr(self, name).
|
| __init__(self, /, *args, **kwargs)
| Initialize self. See help(type(self)) for accurate signature.
|
| __repr__(self, /)
| Return repr(self).
|
| __setattr__(self, name, value, /)
| Implement setattr(self, name, value).
|
| ----------------------------------------------------------------------
| Static methods defined here:
|
| __new__(*args, **kwargs) from builtins.type
| Create and return a new object. See help(type) for accurate signature.
|
| ----------------------------------------------------------------------
| Data descriptors defined here:
|
| __dict__
import builtins
import sys
obj=sys
print(type(builtins),builtins)
print(type(sys),sys)
print(type(obj),obj)
print(obj is sys)
dir(obj)
<class 'module'> <module 'builtins' (built-in)>
<class 'module'> <module 'sys' (built-in)>
<class 'module'> <module 'sys' (built-in)>
True
['__breakpointhook__',
'__displayhook__',
'__doc__',
'__excepthook__',
'__interactivehook__',
'__loader__',
'__name__',
'__package__',
'__spec__',
'__stderr__',
'__stdin__',
'__stdout__',
'__unraisablehook__',
'_base_executable',
'_clear_type_cache',
'_current_frames',
'_debugmallocstats',
'_framework',
'_getframe',
'_git',
'_home',
'_xoptions',
'abiflags',
'addaudithook',
'api_version',
'argv',
'audit',
'base_exec_prefix',
'base_prefix',
'breakpointhook',
'builtin_module_names',
'byteorder',
'call_tracing',
'callstats',
'copyright',
'displayhook',
'dont_write_bytecode',
'exc_info',
'excepthook',
'exec_prefix',
'executable',
'exit',
'flags',
'float_info',
'float_repr_style',
'get_asyncgen_hooks',
'get_coroutine_origin_tracking_depth',
'getallocatedblocks',
'getcheckinterval',
'getdefaultencoding',
'getdlopenflags',
'getfilesystemencodeerrors',
'getfilesystemencoding',
'getprofile',
'getrecursionlimit',
'getrefcount',
'getsizeof',
'getswitchinterval',
'gettrace',
'hash_info',
'hexversion',
'implementation',
'int_info',
'intern',
'is_finalizing',
'maxsize',
'maxunicode',
'meta_path',
'modules',
'path',
'path_hooks',
'path_importer_cache',
'platform',
'prefix',
'ps1',
'ps2',
'ps3',
'pycache_prefix',
'set_asyncgen_hooks',
'set_coroutine_origin_tracking_depth',
'setcheckinterval',
'setdlopenflags',
'setprofile',
'setrecursionlimit',
'setswitchinterval',
'settrace',
'stderr',
'stdin',
'stdout',
'thread_info',
'unraisablehook',
'version',
'version_info',
'warnoptions']
对象之祖object
Python中所有对象的类型都继承object类型。因此object类型定义的方法,绝大部分对象都可以用。以下是object类型的帮助文档信息。
help(object)
Help on class object in module builtins:
class object
| The base class of the class hierarchy.
|
| When called, it accepts no arguments and returns a new featureless
| instance that has no instance attributes and cannot be given any.
|
| Built-in subclasses:
| async_generator
| BaseException
| builtin_function_or_method
| bytearray
| ... and 93 other subclasses
|
| Methods defined here:
|
| __delattr__(self, name, /)
| Implement delattr(self, name).
|
| __dir__(self, /)
| Default dir() implementation.
|
| __eq__(self, value, /)
| Return self==value.
|
| __format__(self, format_spec, /)
| Default object formatter.
|
| __ge__(self, value, /)
| Return self>=value.
|
| __getattribute__(self, name, /)
| Return getattr(self, name).
|
| __gt__(self, value, /)
| Return self>value.
|
| __hash__(self, /)
| Return hash(self).
|
| __init__(self, /, *args, **kwargs)
| Initialize self. See help(type(self)) for accurate signature.
|
| __le__(self, value, /)
| Return self<=value.
|
| __lt__(self, value, /)
| Return self<value.
|
| __ne__(self, value, /)
| Return self!=value.
|
| __reduce__(self, /)
| Helper for pickle.
|
| __reduce_ex__(self, protocol, /)
| Helper for pickle.
|
| __repr__(self, /)
| Return repr(self).
|
| __setattr__(self, name, value, /)
| Implement setattr(self, name, value).
|
| __sizeof__(self, /)
| Size of object in memory, in bytes.
|
| __str__(self, /)
| Return str(self).
|
| ----------------------------------------------------------------------
| Class methods defined here:
|
| __init_subclass__(...) from builtins.type
| This method is called when a class is subclassed.
|
| The default implementation does nothing. It may be
| overridden to extend subclasses.
|
| __subclasshook__(...) from builtins.type
| Abstract classes can override this to customize issubclass().
|
| This is invoked early on by abc.ABCMeta.__subclasscheck__().
| It should return True, False or NotImplemented. If it returns
| NotImplemented, the normal algorithm is used. Otherwise, it
| overrides the normal algorithm (and the outcome is cached).
|
| ----------------------------------------------------------------------
| Static methods defined here:
|
| __new__(*args, **kwargs) from builtins.type
| Create and return a new object. See help(type) for accurate signature.
|
| ----------------------------------------------------------------------
| Data and other attributes defined here:
|
| __class__ = <class 'type'>
| type(object_or_name, bases, dict)
| type(object) -> the object's type
| type(name, bases, dict) -> a new type
下表总结了object类定义的方法及属性。
object类方法及属性 | 对应内置函数 | 说明 |
---|---|---|
__str__() | str() | 将一个对象转换为字符串,以便于打印。在Python 3中,几乎任何对象都可以通过str()转换成字符串,从而能够看到该对象的信息。这是Python非常易用的一个重要原因。例如str(object()) |
__repr__() | repr() | 得到一个对象的字符串表示,很多情况下和str()一样 |
__dir__() | dir() | 浏览一个对象的属性、方法等。 |
__hash__() | hash() | 返回一个对象的hash值,collections中的mutable类型不支持 |
__eq__()等 | ==等关系运算符 | 大多数内置类型都实现了同类型的关系运算,只有少部分不完全支持,如NoneType |
__sizeof__() | – | 返回一个对象的大小 |
__class__ | type() | 得到一个对象的类型,和对一个对象调用type()结果一样。 |
下面是示例代码。
s='Hello, world!'
print(str(s))
print(repr(s))
print(dir(s))
print(hash(s))
print(s == 'Hello, world!')
print(s.__sizeof__())
print(s.__class__)
Hello, world!
'Hello, world!'
['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'capitalize', 'casefold', 'center', 'count', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'format_map', 'index', 'isalnum', 'isalpha', 'isascii', 'isdecimal', 'isdigit', 'isidentifier', 'islower', 'isnumeric', 'isprintable', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']
1400600443639180378
True
62
<class 'str'>
在Python 3中,所有的类型都会继承自object类,即便在定义类时没有明确写出,系统也会自动将object类作为父类。见下面的例子。
class MyClass:
pass
print(issubclass(MyClass, object))
dir(MyClass)
True
['__class__',
'__delattr__',
'__dict__',
'__dir__',
'__doc__',
'__eq__',
'__format__',
'__ge__',
'__getattribute__',
'__gt__',
'__hash__',
'__init__',
'__init_subclass__',
'__le__',
'__lt__',
'__module__',
'__ne__',
'__new__',
'__reduce__',
'__reduce_ex__',
'__repr__',
'__setattr__',
'__sizeof__',
'__str__',
'__subclasshook__',
'__weakref__']
Python 3有一个特殊的全局唯一对象None,其类型为NoneType。None表示空对象,和未定义、空collection不是一个概念。见示例代码。
x=None
another_None=type(None)()
print(x is None, another_None is None)
print([] is None)
def test_func(arg=None):
if arg is None:
print('no arg')
else:
print(arg)
test_func()
test_func(100)
True True
False
no arg
100