Python 3之对象

研究对象的工具

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值