一、类
(一)一切皆对象
类的名称:类名
类的属性:一组数据
类的方法:允许对类进行操作的方法(行为)
(二)封装、抽象、实例化
(1)数据集中到一个对象叫封装。通过对象的属性封装数据。
(2)根据业务需求抽象出所需要的类,明确每个对象的职责,在类中定义职责所需要的方法。定义类的方法时,第一个参数一定是self。或者说当看到函数传入的第一个参数时self,可以推测这个函数是类的方法。
(3)实例化、属性赋值、方法调用
(4)实例化时解释器会自动调用__new__()构造对象,然后调用__init__()初始化。
(三)魔法方法
在python中方法名如果是__xxxx__()的,那么就有特殊的功能,因此叫做“魔法”方法
__init__(self[,…])中的self参数不需要开发者传递,解释器会自动把当前的对象引用传递进去
当使用print输出对象的时候,如果定义了__str__()方法,将对象转化为字符串输出,即打印出该方法中return的数据,而不是打印对象的内存地址。
在内存中销毁一个对象时python中自动调用__del__()方法:当有1个变量保存了对象的引用时,该对象的引用计数就会加1,反之亦是,删除会减1。当该对象引用计数变为0或程序结束时,会调用__del__()方法。
获得一个对象的所有属性和方法,可以使用dir()函数,它返回一个包含字符串的list。仅仅把属性和方法列出来是不够的,配合getattr()、setattr()以及hasattr(),可以直接操作一个对象的状态。比如,获得一个str对象的所有属性和方法:
>>>dir('ABC')
['__add__', '__class__',..., '__subclasshook__', 'capitalize', 'casefold',..., 'zfill']
(四)方法或属性命名中的下划线
xx:共有变量
_x:单前置下划线:私有化属性或方法
__xx:双前置下划线:避免与子类中的属性命名冲突,无法再外部直接访问(名字重整所以访问不到)
__xx__:双前后下划线:用户名字空间的魔法对象或属性。例如:__init__,不要自己发明这样的名字
xx_:单后置下划线:用于避免与Python关键词冲突
通过name mangling(名字重整)目的就是以防子类意外重写基类的方法或者属性。如_Class__object机制就可以访问private了。
_x是在模块导入的时候不会将方法导入
(五)隐藏属性(私有)示例
self.__xxxx
在类的外部无法被访问。要访问必须回到类中定义一个获取方法。
使用property简化getter和setter操作。参考《使用@property》
@property是一个装饰器,实现比较复杂,我们先考察如何使用。把一个getter方法变成属性,只需要加上@property就可以了,此时,@property本身又创建了另一个装饰器@xxx.setter。
(六)隐藏方法(私有)示例
def __xxxx():
在类的外部无法被调用(原因:名字重整)
(七)继承与多继承
可以通过调用print(xxx.__mro__)查看多继承下的优先级
(八)重写
子类也定义了与父类相同的方法名,叫做重写,会优先调用子类的方法
当子类的__init__()被重写时,如果仍想调用父类的__init__(),可以添加super().__init__()方法。同样的,有super().__xxx__()方法
(九)类属性一旦定义就存在,也分为公共类属性和私有类属性;对象属性只有在对象定以后才有
(十)类方法与静态方法
方法中的self是类本身,调用方法时传的值也必须是类的公有属性,就是说类方法只能操作类本身的公有字段
class A(object): @classmethod #类方法要在方法上面加一个修饰器,类方法的参数xxx(一般用cls,就像对象方法用self),代表当前的类 def test(xxx): …… xxx.属性 #等同于操作A.属性 …… A.test() #可以在类的方法中修改类属性
静态方法:通过类直接调用,不需要创建对象,不会隐式传递self。
class A(object): @staticmethod #静态方法,属于类,没有类似self,cls这样的默认传递的参数,可以通过类名来调用 def test(): ……
(十一)__new__()方法
__new__至少要有一个参数cls,代表要实例化的类,此参数在实例化时由python解释器自动提供
__new__必须要有返回值,返回实例化出来的实例,这点在自己实现__new__时要特别注意,可以return父类__new__出来的实例,或者直接是object的__new__出来的实例
__init__有一个参数self,就是这个__new__返回的实例,__init__在__new__的基础上可以完成一些其他初始化的动作,__init__不需要返回值
我们可以将类比作制造商,__new__方法就是前期的原材料购买环节,__init__方法就是在有原材料的基础上,加工,初始化商品环节
(十二)动态语言:可以在运行的过程中,修改代码
可以做的事情:
①为对象动态添加属性
注意为对象动态添加的属性仅适用于该对象
要使其他对象也能用需添加类属性:类名.属性 = xxx
②为类动态添加方法
class Person(object): def __init__(self,name = None,age = None): self.name = name self.age = age def eat(self): print(*eat food*) >>>def run(self,speed): print('%s在移动,速度是%d km/h'%(self.name,self,speed)) >>>P1 = Person('小丽','25') >>>import types >>>P1.run = types.MethodType(run,P1) >>>P1.run(180) 小丽在移动,速度是180km/h
注意上述方法添加的方法仅适用于该对象
要使其他对象也能用需添加类属性:@classmethod 或 @staticmethod
(十三)限制访问__slots__
要注意,__slots__定义的属性仅对当前类实例起作用,对继承的子类是不起作用的。除非在子类中也定义__slots__,这样,子类实例允许定义的属性就是自身的__slots__加上父类的__slots__
限制修改对象的属性:
(十四)定制类、枚举类、元类