最近在使用 peewee 来做数据库 ORM,期间遇到一些疑问便查了下源码,结果发现好多以前没有好好理解并整理的知识。
参考视频:https://www.bilibili.com/video/BV1uA411V7dW?p=1
关于 Python 中类的基本用法,参考以前写的文章 《python 小技巧与坑 – python 的类》
总结:
对象(obj)是类(class)的一个实例,而类(class)本身其实也是一个对象,它是元类(metaclass)的实例。
在 Python 中,默认情况下,所有类的元类都是 type,所有类的基类都是 object。
规定术语:
我们先来规定下几个术语在本文中的特定意思,以免混淆。
类对象,用来特指类本身这个对象,而不是由类生成的对象实例。
类实例,用来特指由类生成的对象实例。
类属性(类变量),指在类定义体内部,__init__()
方法之外,定义的属性。类属性可以通过 Class.attr
调用也可以通过 instance.attr
调用。
实例属性(实例变量),指在类的 __init__()
方法中,或类定义体外部,通过 instance.attr
定义的属性。实例属性只能通过 instance.attr
调用。
一、特殊函数与特殊属性
1.1 如何区分对象
is
操作符用来判断两个对象是否为同一个。
id()
函数返回对象的唯一标识,在 CPython 实现中,返回的就是该对象的内存地址。可以使用 hex(id(obj))
将其转换成16进制。
type()
函数返回对象的类型。
1.2 可重写(override)的类方法
1.2.1 __new__(cls[, …])
object.__new__(cls[, ...])
方法用来创建 cls 类的对象实例。其中第一个参数 cls 代表当前类,其余参数应该与构造器表达式保持一致,或者使用可变参数囊括构造器表达式的参数(构造器表达式指 x = ClassName(args)
这种语法)。它的返回值应该是一个新的对象实例(cls 类的实例)。__new__()
实际上是一个静态方法,不过不需要加 @staticmethod
进行声明
当你使用构造器表达式 x = ClassName(args)
来创建对象的时候,Python 解释器会先调用 ClassName.__new__(cls)
创建一个对象实例,然后再对该对象调用 __init__(self[, ...])
进行初始化。
如果 __new__()
方法没有返回一个对象实例,那么后续就不会调用 __init__(self[, ...])
方法。
__new__(cls[, ...])
的默认实现是调用父类的 __new__()
方法 spuer().__new__(cls, )
,你可以在此之后对创建出来的对象实例进行修改。
1.2.2 __init__(self[, …])
__init__(self[, ...])
的调用发生在 __new__(cls)
方法创建完对象实例之后,该对象实例返回给用户之前。self 参数代表该对象实例,其余参数应该与构造器表达式保持一致,或者使用可变参数囊括构造器表达式的参数。__init__()
不需要有返回值,构造器表达式返回的对象实例是由 __new__()
生成的。
在派生类的 __init__()
方法中,必须主动调用父类的 __init__()
方法, super().__init__([args...])
,以确保对象实例中父类部分初始化成功。
1.2.3 __del__(self)
__del__()
方法会在对象实例即将销毁之前自动调用。注意 __del__()
方法实际上并不执行销毁对象、回收内存的操作,这些都是由 Python 垃圾回收机制完成的。所以即使你手动显式调用 x.__del__()
,实际上只是运行了一次 __del__()
方法,并不会销毁对象,甚至连对象的引用计数都不会减少。
要想显式删除一个对象,需要使用 del
语句。del x
并不会直接调用 x.__del__()
,而是将对象 x 的引用计数减1。当对象的引用计数为0的时候,Python 的 GC 机制会自动为其调用 __del__()
。(很诡异,del
在 Python 中是一个 statement,而不是一个 function)
派生类的 __del__()
方法,必须主动调用父类的 __del__()
方法。
Python 并不保证在解释器退出时,会对所有还存活的对象调用 __del__()
方法。
1.2.4 __repr__(self)
Python 的内建函数 repr(x)
会自动调用对象的 x.__repr__()
方法。 __repr__()
必须返回一个“正式的”字符串(相比于 __str__()
而言)。如果可以的话,返回的字符串应该是一个有效的 Python 表达式,能够用来重建对象实例;如果做不到的话,应该返回类似<…some useful description…> 这样格式的字符串。
1.2.5 __str__(self)
Python 的内建函数 str(x)
, print(x)
会自动调用 x.__str__()
方法。该方法必须返回一个“非正式的”字符串,用来代表该对象实例。与 __repr__()
不同的是,__str__()
并不期望返回一个可重建对象的 Python 表达式字符串,可以更随意进行定制。
默认的__str__(self)
方法其实调用的就是 self.__repr__()
。
1.2.6 __call__(self[, …])
当对象 x 被以函数形式 x()
使用的时候,就会自动调用 x.__call__()
方法(x.__call__()
等价于 Class_of_x.__call(x)
)。
1.2.7 示例代码
class User(object): def __new__(cls, *args, **kwargs): # __new__ 方法用于创建 cls 类的对象 print('\n===== 调用 User.__new__() 方法') print('cls: ', cls) print('type(cls): ', type(cls)) print('args: ', args) print('kwargs: ', kwargs) obj = super().__new__(cls) print('id(obj): ', hex(id(obj))) return obj def __init__(self, name): # 对 self 这个对象进行初始化 print('\n===== 调用 User.__init__() 方法') print('id(self): ', hex(id(self))) super(User, self).__init__() self.name = name pass def __del__(self): # __del__() 方法并不能销毁对象,它只是在对象即将被 GC 销毁之前会被系统自动调用 print('\n===== 调用 User.__del__() 方法') pass def __call__(self, *args, **kwds): # 当你在对象后面加上括号,像函数一样调用的时候,形如:u1(),就会自动调用该方法。 print('\n===== 调用 User.__call__() 方法') pass def __str__(self) -> str: # 当在外部 print(user) 或者 str(user) 的时候, print('\n===== 调用 User.__str__() 方法') # return super().__repr__() return '这是 __str__() 的输出: ' + self.__repr__() def __repr__(self) -> str: print('\n===== 调用 User.__repr__() 方法') return super().__repr__() # 创建类的对象实例,实际上执行了两个步骤: # 1. 调用 __new__() 方法 创建对象 # 2. 调用 __init__() 方法 初始化对象 u1 = User('funway') print(u1) u1()
1.2.8 __get__, __set__, __delete__
如果一个类 Class_A 定义了这三个方法,只有当这个类的实例 obj_a 是作为另一个类的类变量(Class_B.a = Class_A())的时候才有可能调用这三个方法。
这时候,赋值语句 obj_b.a = xxx
,调用的就是 a.__set__()
,取值语句 obj_b.a
或 Class_B.a
调用的就是 a.__get__()
。
我们将定义了这三个方法的类叫做 “描述符”(Descriptors)。
class CharField(object): def __init__(self, text): super(CharField, self).__init__() self.__text = text def __get__(self, instance, owner): print('MyDict.__get__: %s, %s, %s' % (self, instance, owner)) if instance is None: return self else: return self.__text pass def __set__(self, instance, value): print('MyDict.__set__: %s, %s, %s' % (self, instance, value)) self.__text = value pass class User(object): name = CharField('funway') def __init__(self): super().__init__() # self.name = 'john' pass pass u1 = User() print('test 1 =======================') print(User.name) # 调用 CharField.__get__(name, ...) print(u1.name) # 调用 CharField.__get__(name, ...) print('test 2 =======================') u1.name = 'zoe' # 调用 CharField.__set__(name, ...) print(u1.name) # 调用 CharField.__set__(name, ...) print('test 3 =======================') User.name = 'nobody' # 直接覆盖 User.name 类属性 print(User.name, type(User.name)) print(u1.name)
peewee 库的 FieldAccessor 类就是一种描述符类,它使得用户可以通过 Model.field 或 model.field 来访问这个类属性底层的真实字段。
1.2.9 __get**__, __set**__
__getitem__(self, key)
用来实现 obj[key]
语法,当用户使用 obj[key]
时候会自动调用该方法。
__setitem__(self, key, value)
用来实现 obj[key]
语法,当用户使用 obj[key] = value
时候会自动调用该方法。
__getattribute__(self, attr)
只要用户使用 obj.attr
语法,就会无条件调用该方法。默认的 __getattribute__
只负责获取已有属性。
尽量不要重写该方法,否则很容易陷入无限循环中然后抛出 RecursionError 异常。
__getattr__(self, attr)
当 obj.attr
调用 __getattribute__
在已有属性字典中找不到 attr 时候,会调用该方法。
__setattr__(self, attr, value)
只要用户使用 obj.attr = value
语法,就会无条件调用该方法。
尽量不要重写该方法,否则很容易陷入无限循环中然后抛出 RecursionError 异常。
1.3 特殊属性
instance.__class__
对象实例 instance 所属的类
class.__bases__
包含该类 class 所有父类的元组
definition.__name__
definition 的名字,definition 可以是类 class, 函数 function, 方法 method, 描述符 descriptor, 生成器 generator instance。
definition.__qualname__
qualified name 指的是比普通 __name__ 更详细的名字,包含层级信息。
object.__dict__
对象 object 的属性字典,包含该对象的所有属性信息。注意!这里的 object 可以是一个对象实例 instance,也可以是一个类 class!
对于 instance.__dict__
,只包含该对象实例自己的对象属性(在 __init__() 方法中定义以及在类体外部定义的),不包含类属性。
对于 class.__dict__
,则只包含该类的类属性。
二、元类 metaclass
2.1 类也是对象,是元类的对象
我们常说的对象,是指由类创建的对象实例。在 Python 中,类本身也是一个对象(下文中,我们将「类对象」这个术语用来特指类这个对象,用「类实例」特指由类创建出来的对象实例)。我们将用来创建类对象的类叫做元类(metaclass)。默认情况下,Python 中的所有类都是 type 类的实例。(同时,Python 中的所有类都是 object 类的派生。这确实绕 =。=#)
当使用 class ClassNmae():
语句定义一个类的时候,其实 python 解释器是通过元类 type 生成了一个类对象,并赋值给这个 ClassName 变量。
# 1、用 class 语句定义一个类 Dog class Dog(object): name = 'nuanuan' def bark(self): print('woof!') pass # 2、用 type 类的构造器表达式定义一个类,类名也是 Dog,赋值给变量 Puppy # type(类名, (父类元组), {定义类成员的字典}) Puppy = type('Dog', (object, ), {'name': '暖暖', 'bark': lambda self: print('汪!')}) d = Dog() # d = Puppy() print(d.name) d.bark() print('d.__class__: ', d.__class__) # 对象 d 所属的类 print('Dog.__class__: ', Dog.__class__) # 对象 Dog 所属的类 print('Dog.__bases__: ', Dog.__bases__) # 类 Dog 的所有父类 print('Puppy.__class__: ', Puppy.__class__) # 对象 Puppy 所属的类 print('Puppy.__bases__: ', Puppy.__bases__) # 类 Puppy 的所有父类 print('type.__class__: ', type.__class__) # 对象 type 所属的类(也是 type) print('type.__bases__: ', type.__bases__) # 类 type 的所有父类(也是 object) print('object.__class__: ', object.__class__) # 对象 object 所属的类(还是 type) print('object.__bases__: ', object.__bases__) # 类 object 的所有父类(object 不再有父类)
元类 type 的构造器表达式形式如此:type(class_name, bases_tuple, attrs_dict)
。其中 class_name 表示类名,bases_tuple 是包含所有父类的元组,attrs_dict 是一个包含类变量和类方法的字典。现在我们已经确认 type()
可以用来动态创建一个类,但实际上它不是很方便。因为在 attrs_dict 参数中,我们很难使用 lambda 表达式写一个复杂函数然后赋值给一个 attr。当然你也可以将某个 attr 关联到一个外部函数,但我觉得这样并不太好。
于是,Python 提供了可自定义的元类,只要一个类派生自 type 类,那么它就是一个元类。
2.2 自定义元类
① 定义元类时,元类必须派生自 type 类。 class MyType(type):
② 在常规类定义中使用元类时,需要使用 metaclass 关键字。 class ClassName(object, metaclass=MyType):
# 1、定义一个元类 MyType class MyType(type): pass # 2、定义一个常规类,继承自 object(可省略不写),元类是 MyType # class User(object, metaclass=MyType): class User(metaclass=MyType): pass u = User() print(User.__class__) print(User.__bases__)
2.2.1 反向思考,元类如何生成常规类
在上面的代码中,我们定义了 User 类的元类是 MyType。也就是说,User 类是 MyType 类的对象实例!
那么我们回顾下上文 1.2 中所说的 __new__()
与 __init__()
方法。类要生成对象,需要先调用 __new__()
生成对象实例,然后调用 __init__()
对这个实例进行初始化,最后才返回。
而用户调用 u = User()
这个语句的时候,如果把 User 看作一个对象,那么 obj()
调用的其实是 obj.__class__.__call__()
!在这里就是 MyType.__call__()
方法。
现在我们扩展一下元类 MyType,让它打印出“工作流程”,但具体的生成操作还由父类 type 进行。
# 1、定义一个元类 MyType # 暂时只打印工作流程,实际工作仍由父类 type 完成 class MyType(type): def __new__(cls, *args, **kwargs): print('MyType.__new__ 创建对象(常规类)') new_cls = super().__new__(cls, *args, **kwargs) return new_cls def __init__(self, *args, **kwargs): print('MyType.__init__ 初始化对象(常规类)') super().__init__(*args, **kwargs) def __call__(self, *args, **kwargs): print('MyType.__call__ 用户调用了「对象()」这个表达式,亦即常规类的构造器表达式') return super().__call__(*args, **kwargs) # return None # 你可以试试看返回 None 😏 pass # 2、定义一个常规类,继承自 object(可省略不写),元类是 MyType class User(metaclass=MyType): name = 'funway' def greet(self): print('hello, my name is %s' % self.name) pass pass print('User 类定义完成') u = User() # 将会执行 User.__class__.__call__() 方法,也就是 MyType.__call__() 方法! u.greet() print('User.__class__: ', User.__class__) print('User.__bases__: ', User.__bases__)
另外,由于 MyType.__call__() 要执行的操作就是 User(),所以我们可以直接在其中自己生成 User 的对象实例,初始化后并返回。所以上面代码中的 MyType.__call__() 等价于如下:
def __call__(self, *args, **kwargs): print('MyType.__call__ 用户调用了「对象()」这个表达式,亦即常规类的构造器表达式') # 这时候的 self,是元类 MyType 的对象实例,亦即常规类 User new_obj = self.__new__(self, *args, **kwargs) self.__init__(new_obj, *args, **kwargs) return new_obj
2.3 子类继承父类的元类
如果一个类,它的父类中定义了 metaclass,那么这个类也会继承该 metaclass,并由该 metaclass 进行创建。
如果一个类派生自多个父类,且每个父类各自有自己的 metaclass。这时候很可能会发生元类冲突 “ TypeError: metaclass conflict ”。需要用户自己想办法去解决,最简单的办法就是在子类定义中显式指定 metaclass。
三、使用元类实现单例模式
3.1 __new__() 实现
其实不使用元类,只用 __new__()
方法来实现更简单。。
# ###### # Note: this is just a simple example and is not thread safe !!! # ###### class MyPrinter(object): # 类成员变量,通过类名调用 ClassName.class_virable _instance = None def __new__(cls): # 判断 _instance 类变量是否为空,空的话则新建一个实例并返回 if cls._instance == None: cls._instance = object.__new__(cls) return cls._instance # 非空的话,则直接返回该实例 else: return cls._instance pass def __init__(self): print('init') # 这时就尽量不要在 __init__ 中做什么修改单例对象的操作了,因为它也每次都会被调用 pass p1=MyPrinter() print(p1) p2=MyPrinter() print(p2)
输出如下图所示:
注意:上述示例代码中的单例模式并非线程安全的!要想实现 thread-safe 的单例模式,请参考《Python 创建线程安全的单例》 一文。(同样,👇下面的 metaclass 实现方式也不是线程安全的)
3.2 metaclass 实现
class SingletonMeta(type): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self._instance = None # 等价于定义了 MyPrinter._instance 类变量 pass def __call__(self, *args, **kwargs): # 如果不存在该单例对象 if not self._instance: # 新建对象 self._instance = self.__new__(self, *args, **kwargs) # 初始化对象 self.__init__(self._instance, *args, **kwargs) pass return self._instance pass class MyPrinter(object, metaclass=SingletonMeta): pass p1 = MyPrinter() p2 = MyPrinter() print(p1) print(p2) print(p1 is p2)
四、peewee 源码分析(Model 类)
元类赋予了我们可以动态创建类的能力,这样说很难以理解,我们用一个现实场景来解释一下。元类最常用的地方就是数据库的 ORM(对象关系映射)框架,我们可以很容易地定义表示数据库表的 Model 类,然后由元类为我们执行通用的数据库绑定、字段绑定等操作。
peewee 就是这么一个 ORM 库,我也是因为最近用到了 peewee,才萌生了写这篇文章的念头。
4.1 基本用法
import uuid, os from peewee import * db = SqliteDatabase(os.path.dirname(__file__) + '/my_app.db') class User(Model): uid = CharField(unique=True, default=lambda: uuid.uuid4().hex) class Meta: database = db db.connect() db.create_tables([User,]) u1 = User() u1.save() print('u1: %s, id(u1)=%s' % (u1, hex(id(u1))))
我们从这一段简单的代码来看一下 peewee 库是怎么实现 ORM 的。
❶ User 继承自 Model 类。
❷ Model 类在 peewee 中的定义是 class Model(with_metaclass(ModelBase, Node))
,也就是说 Model 类继承自 with_metaclass(ModelBase, Node)
。
❸ with_metaclass()
是一个函数,其函数定义是:
MODEL_BASE = '_metaclass_helper_' def with_metaclass(meta, base=object): return meta(MODEL_BASE, (base,), {})
那么with_metaclass(ModelBase, Node)
等价于 ModelBase('_metaclass_helper_', (Node, ), {})
。让我回忆下上文的 type(class_name, (bases_tuple), {attrs_dict}),它其实就是以 ModelBase 为元类,以 Node 为基类,创建了一个名为 ‘_metaclass_helper_’ 的临时类。(注意,该函数返回一个类对象。多次调用该函数,返回的类对象类名是一样的,但实际地址是不一样的!所以可以说每次返回的是不同的类,只是类名一样 =。=#)
为什么要多此一举搞一个临时类出来呢?好像说是为了兼容 Python2 的语法。
OK,知道了 with_metaclass()
的本质,那么 Model 类的定义可以简化为 class Model(Node, metaclass=ModelBase)
,它以 Node 类为基类,以 ModelBase 为元类。同样,User 类就是以 Model 为基类,以 ModelBase 为元类。
❹ 所以,当用户定义 User 类的时候,实际上调用的是元类 ModelBase 的 ModelBase.__new__()
与 ModelBase.__init__()
方法来创建并初始化这个类对象。
然后当用户使用 u1= User()
创建 User 类实例的时候,调用的是元类 ModelBase 的 ModelBase.__call__()
方法。
❺ 我们将 peewee 中的代码简化,其中最终要的几个类为:ModelBase
、Metadata
、FiledAccessor
、Model
。
import uuid, os MODEL_BASE = '_metaclass_helper_' def with_metaclass(meta, base=object): return meta(MODEL_BASE, (base,), {}) # ModelBase 是控制生成 Model 类的元类 class ModelBase(type): def __new__(cls, name, bases, attrs, **kwargs): print('\n@ ModelBase.__new__', cls, name) print(' bases: ', bases) print(' attrs: ', attrs) if name == MODEL_BASE or bases[0].__name__ == MODEL_BASE: print(' 对于临时类 _metaclass_helper_ 或者它的第一级子类 Model,直接返回新建的类') return super(ModelBase, cls).__new__(cls, name, bases, attrs, **kwargs) print(' 对于 Model 的子类,执行自定义操作') print(' 1、获取内部类 Meta 的定义(Meta 主要用来定义数据库名、表名、主键等信息)') meta_options = {} meta = attrs.pop('Meta', None) if meta: for k, v in meta.__dict__.items(): if not k.startswith('_'): meta_options[k] = v print(' meta: ', meta) print(' meta_options: ', meta_options) print(' 2、新建类对象', name) cls = super(ModelBase, cls).__new__(cls, name, bases, attrs, **kwargs) # 这两个是自定义的类属性 print(' 2.1 添加 User.__data__ 类属性,但我没发现这个类属性有啥用,因为最终实际数据是存放在 user.__dat__ 这个实例属性中的!') cls.__data__ = cls.__rel__ = None print(' 2.2 添加 User._meta 属性,并给它加入该类的元信息(数据库名、表名、主键等)') cls._meta = None # cls._meta = Metadata(cls, **meta_options) # 代表元属性的对象 print(' 2.3 获取类的字段信息 fields') fields = [] for key, value in cls.__dict__.items(): # 会先通过 isinstance(value, Field) 判断是不是字段类型,是的才添加进 fields fields.append((key, value)) print(' 2.4 将字段信息 fields 通过 add_field() 添加到 cls._meta 中') print(' add_field() 还有一个很重要的作用!!') print(' 就是调用 Field.bind() 方法,将 User.uid 这个原本定义为 CharField 类型的属性,替换为 FieldAccessor 类!') # for name, field in fields: # cls._meta.add_field(name, field) print(' 2.5 执行其他操作,比如验证类对象、设置外键等') # ... print(' 3、 返回类对象 %s' % name) return cls pass # Metadata 类是存放 Model 的元数据的类,包括 数据库名,表名,主键,字段信息 # 【很重要】的一点是,在 Metadata.add_field() 方法中, # 它会将 User.uid 类属性,转移到自己的 self.fieds, self.columns 实例属性中 # 并且将原来类型为 CharField 类型的 User.uid 类属性,通过 Field.bind() 方法转换成 FieldAccessor 类型。 # FiledAccessor 类定义了 __get__, __set__ 方法,允许通过 u1.uid 直接访问该字段的真实值。 class Metadata(object): pass # Node 类是用来作为查询语句的中间节点,暂且不讨论 class Node(object): pass # Model 是该 ORM 中所有自定义 model_class 的基类 # 它的一大作用就是将元数据中的默认字段值放到 self.__data__ 实例属性中 class Model(with_metaclass(ModelBase, Node)): def __init__(self, *args, **kwargs): print('@ Model.__init__', args ,kwargs) print(' 1. 设置 __data__ 属性,为 _meta 元数据中记录的字段默认值') # self.__data__ = self._meta.get_default_dict() print(' 2. 设置 _dirty 属性,代表被修改过的 “脏字段”') # self._dirty = set(self.__data__) print(' 3. 设置其他对象属性') for k in kwargs: setattr(self, k, kwargs[k]) pass # 自定义的 model_class 类 class User(Model): uid = uuid.uuid4().hex class Meta: database = 'xx.db' pass print('User 类定义完成') u1 = User()
总结一下就是:
① 用户自定义的模型类 User
继承自 Model
类,Model
类的元类是 ModelBase
。
② 所以 User
类也是 ModelBase
元类的对象实例,由 ModelBase.__new__()
负责创建。
③ 在创建 User
类的时候,ModelBase
会为其生成一个 User._meta
类属性,它是 Metadata
类型的对象实例。然后将 User
的数据名、表名、主键、字段信息等元数据保存到 User._meta
中。
④ 在 User._meta.add_field()
方法中,还会将用户定义的 User.uid
这些代表字段信息的类属性,转换成 FiledAccessor
类型。这样,用户就可以使用 user.uid
来访问真实的字段值(FiledAccessor.__get__()
, FiledAccessor.__set__()
)。而此时访问 User.uid
返回的则是 FiledAccessor.field
。
⑤ 在实例化 User 的时候,由 Model.__init__() 负责初始化 self.__data__ 这个实例属性,这里保存着 User 模型真实的字段值。
4.2 为什么 Model 实例打印出来会是 None?
peewee 中 Model 实例打印出来的时候显示为 None,其实是因为这段代码:
class Model(with_metaclass(ModelBase, Node)): # ... def __str__(self): return str(self._pk) if self._meta.primary_key is not False else 'n/a'
Model 类重写了 __str__(self)
方法,打印的是主键字段 self.pk
。如果未设置主键,默认情况下就是 None
,所以打印的是 str(None)
。
只有像如下代码,在 Model 类中特别设置 _meta.primary_key = False
的,才会返回出 ‘n/a’。
class NoPrimaryKey(Model): # ... class Meta: primary_key = False
要想改变这个情况,变成原先预期的打印出对象类型与内存地址,我们可以在子类中重写 Model 的 __str__()
方法:
def __str__(self): # return self.__repr__() # 这里不能使用 self.__repr__()。是因为在 peewee.py 中,ModelBase 基类在 __repr__() 方法中调用了 __str__()方法。 # 这时如果不重写 __repr__(),却又在 __str__() 中调用 __repr__(),就会导致调用死循环。 return object.__repr__(self)