面向过程指完成函数细节本身 面向对象即将面向过程的成果以函数的形式进行使用,不涉及细节
类和实例: 类是抽象的模板 实例是根据类创建出来的一个个具体对象 每个对象拥有相同的方法 但各自数据可能不同
数据封装:实例本书就拥有数据 要访问这些数据 不需要外面函数(如print) 可以直接在类的内部使用函数访问数据 这样 数据就被封装起来了 封装数据的函数和类本身是关联起来的 我们称之为 类的方法 定义一个方法 第一个参数必须是self 其他和普通函数一样
和静态语言不同,Python允许对实例变量绑定任何数据,即,对于两个变量,虽然它们同属于一个类,但拥有的变量名称都可能不同 若未加限制 实例的变量可以随意添加或修改
访问限制:为了不让外部代码随意操作实例变量操作数据,可以在属性名称前加上双下划线 如__name __score 使之变成私有变量(private),只有内部可以访问,用类的方法访问 外部若想访问 就必须给类增加方法(函数) 例如get_name get_score这种方法 外部若想修改 也得给类添加方法 例如 set_score 本来 可以直接从外部修改 如bart.score = 99 这种 结果现在必须定义方法 是变麻烦了点 但也因此 在方法中 我们可以添加代码检查参数 避免无效参数
__init__方法,是类与实例中必备的函数,每次添加一个新实例,必然自动运行
也有一些变量形式类似__init__,即__xxx__,他们是特殊变量,可以直接访问 所以 最好别用 双下划线开头 双下划线结尾
也有一些变量名 以单下划线开头 如_name _score 可被外部访问 但是按照约定俗成的规定,看到这种变量 把它当成 “我可以被访问 但请把我看成私有变量 不能随意访问”
双下划线开头变量的本质 __name被python解释器改为_类的名字__name 所以 可以通过_类的名字__name 访问实例内部 请勿这么操作
继承:新定义的类(class)可以从某个现有的class继承,新定义的类会被称作子类(subclass),被继承的类被称作基类 父类 或超类 (Base class,Super class)
继承的好处是 1.子类获得父类的所用功能 所有方法 2.当子类和父类存在相同(名字的)方法时 子类的方法自动覆盖父类的方法 代码会调用子类的方法 这被称作多态
多态 在继承关系中 如果一个实例的数据类型时某个子类 那它的数据类型也可被看作父类
多态的好处就是,当我们需要传入任意子类时,我们只需要接受父类就可以了,因为子类都是父类,然后按照父类进行操作 父类所拥有的方法对于传入的任意父类或子类,都可以调用 对于一个变量 我们只需要知道它属于父类 无需知道其子类 就可以放心的调用方法,而具体调用的方法是作用在父类还是子类上,由运行时该对象的确切类型决定
即 多态真正的好处 调用方只管调用 不管细节 当我们新增一子类时,只要确保方法编写正确 不用管原来的代码时怎么调用的 这就是 “开闭”原则
对拓展开放:允许新增Animal子类
对修改封闭:不需要修改依赖父类的外部调用函数
鸭子类型 file-like object 对真正的文件对象 它有一个read()方法放回其内容 但,许多对象只要有read()方法都可以被视为file-like object 许多函数接收的参数就是file-like object 不一定要传入真正的文件对象 完全可以传入任何实现read()的方法
继承可以把父类的所有功能都直接拿过来,不必从零做起,子类只需要新增自己的新方法,还可以覆盖重写父类不合适的方法
type() 判断对象类型 返回对应的Class类型 判断基本数据类型可以直接写int,str等,但如果要判断一个对象是否是函数,就要使用types模块中定义的常量:
1 >>> import types 2 >>> def fn(): 3 ... pass 4 ... 5 >>> type(fn)==types.FunctionType 6 True 7 >>> type(abs)==types.BuiltinFunctionType 8 True 9 >>> type(lambda x: x)==types.LambdaType 10 True 11 >>> type((x for x in range(10)))==types.GeneratorType 12 True
isinstance() 专门判断class的继承关系,也可取代type()判断基本类型 还可以判断一个变量是否是某些类型中的一种 应优先于type使用
dir() 可获得一个对象的所有属性和方法 它返回一个包含字符串的list
>>> dir('ABC') ['__add__', '__class__',..., '__subclasshook__', 'capitalize', 'casefold',..., 'zfill']
类似__xxx__的属性和方法在Python中是有特殊用途的 如,__len__方法返回长度。如果调用len()函数获取一个对象的长度,实际上就是在len()函数内部自动调用该对象的__len__()方法 下列代码等价:
>>> len('ABC') 3 >>> 'ABC'.__len__() 3
我们自己写的类,如果也想用len()
的话,就自己写一个__len__()
方法
仅仅把属性和方法列出来是不够的,配合getattr()
、setattr()
以及hasattr()
,我们可以直接操作一个对象的状态
实例属性和类属性
由于Python是动态语言,根据类创建的实例可以任意绑定属性。 给实例绑定属性的方法是通过实例变量,或者通过self
变量
如果Student本身需要绑定一个属性 可以直接在class中定义属性,即类属性,归类所有:
class Student(object): name = 'Student'
我们定义了类属性后,这个属性虽然归类所有,但类的所有实例都可以访问
在编写程序的时候,千万不要对实例属性和类属性使用相同的名字,因为相同名称的实例属性将屏蔽掉类属性,但是当你删除实例属性后,再使用相同的名称,访问到的将是类属性。