◎知识点
特殊属性和特殊方法
特殊属性__dict__
特殊属性__doc__
特殊属性__slots__
◎脚本练习
▽ 特殊属性和特殊方法
"""一、特殊属性和特殊方法""" """ 调用内置函数dir()后的返回值中,很多属性和方法都是以双下划线__开头和结尾的,这些属性和方法 中的绝大多数都继承自类object """ print(dir(object)) """ 以双下划线__开头和结尾的属性被称为特殊属性,以双下划线__开头和结尾的方法被称为特殊方法。 特殊属性和特殊方法都是系统预定义的,我们自定义的属性名和方法名不要以双下划线__开头和结尾。 在我们自定义类对象时,经常会重写一个或多个特殊方法,例如__init__。特殊方法会在特定的情形下 被自动调用,很少需要手动调用特殊方法 """
▽ 特殊属性__dict__
"""二、特殊属性__dict__""" """ 对于指定的类对象或实例对象,可以访问特殊属性__dict__获得该类对象或实例对象所绑定的 所有属性和方法的字典。其中,字典中的键为属性名或方法名 """ class MyClass(object): ca = "ca" def __init__(self): self.ia = "ia" def im(self): pass @classmethod def cm(cls): pass @staticmethod def sm(): pass MyClass.ca2 = "ca2" print(MyClass.__dict__) mc = MyClass() mc.ia2 = "ia2" print(mc.__dict__) # {'ia': 'ia', 'ia2': 'ia2'}
▽ 特殊属性__doc__
"""三、特殊属性__doc__""" """ 调用内置函数dir得到的类对象的所有属性中,有一个特殊属性叫__doc__,用于表示类对象的文档字符串 1、什么是类对象的文档字符串(docstring)? 与函数的文档字符串类似,位于类对象的第一行的字符串被称为类对象的文档字符串,通常用三个引号表示 类对象的文档字符串是对类对象的功能简要描述 在PyCharm,类对象的文档字符串用灰色显示 之所以称为"文档"字符串,是因为可以使用工具根据文档字符串自动地生成文档 应该养成编写文档字符串的习惯,以提高程序的可读性 """ class MyClass(object): """这是类对象的文档字符串""" pass """ 2、访问类对象的文档字符串 通过类对象的特殊属性__doc__可以访问类对象的文档字符串 调用内置函数help()得到的帮助信息中会包含类对象的文档字符串 """ print(list.__doc__) print(MyClass.__doc__) # 这是类对象的文档字符串 print(help(list)) print(help(MyClass))
▽ 特殊属性__slots__
"""四、特殊属性__slots__""" """ python是动态语言,所以,在创建对象之后,可以对其动态地绑定属性和方法 如果想要对实例对象动态绑定的属性和方法的名称进行限制,可以在其对应的类对象中 定义特殊属性__slots__,并给__slots__赋值一个所有元素都为字符串的列表或元组, 这样,对实例对象动态绑定的属性和方法的名称就只能来自于__slots__中的元素 """ class MyClass(object): __slots__ = ("attr1", "do_sth1") mc = MyClass() mc.attr1 = 18 # mc.attr2 = 56 # AttributeError: 'MyClass' object has no attribute 'attr2' def do_sth1(self): print("do_sth1被调用了") from types import MethodType mc.do_sth1 = MethodType(do_sth1, mc) mc.do_sth1() # do_sth1被调用了 def do_sth2(self): print("do_sth2被调用了") # mc.do_sth2 = MethodType(do_sth2, mc) # mc.do_sth2() # AttributeError: 'MyClass' object has no attribute 'do_sth2' """ 默认情况下,访问实例对象的属性是通过访问该实例对象的特殊属性__dict__来实现的。例如: 访问obj.x其实访问的是obj.__dict__['x']。 在类对象中定义了特殊属性__slots__后,其实例对象就不会在创建特殊属性__dict__了, 而是为每个属性创建一个描述器,访问属性时就会直接调用这个描述器。调用描述器比访问__dict__要快, 因此,在类对象中定义特殊属性__slots__可以提高属性的访问速度。 此外,在类对象中定义了特殊属性__slots__后,由于其实例对象不再创建特殊属性__dict__,同时, 特殊属性__dict__是一个字典,字典的本质是哈希表,是一种用空间换取时间的数据结构, 因此,在类对象中定义特殊属性__slots__可以减少内存消耗。 """ # AttributeError: 'MyClass' object has no attribute '__dict__' # print(MyClass().__dict__) """ 特殊属性__slots__只对其所在类对象的实例对象起作用,对其所在类对象的子类的实例对象是不起作用的 如果子类也定义了特殊属性__slots__,那么子类的实例对象可以动态绑定的属性和方法的名称为 子类的__slots__加上父类的__slots__ """ class MyChildClass1(MyClass): pass mcc1 = MyChildClass1() mcc1.attr3 = 56 class MyChildClass2(MyClass): __slots__ = ("attr2", "do_sth2") mcc2 = MyChildClass2() mcc2.attr1 = 18 mcc2.attr2 = 18 mcc2.do_sth1 = 18 mcc2.do_sth2 = 18 # AttributeError: 'MyChildClass2' object has no attribute 'attr3' # mcc2.attr3 = 18