面向对象编程
面向对象,把一些数据和处理数据的方法做一个集合。数据是静态的,方法是一个动作。
在python中任何数据类型都可视为对象。
类和实例
定义类 使用 class 关键字
根类 object
#定义类
class ClassA(object): #ClassA类 继承于 object类
pass
#创建实例
a = ClassA()
class Student(): #省略了object
pass
s = Student()
print(isinstance(s,object)) #True Student的父类也是object
特殊的用法,实例a可以任意的添加属性如 a.x = ‘x’;
为实例添加属性,可以在创建之前,在类中的__init__方法里定义
数据封装
类中定义的变量通过该类中的方法进行操作,而不用通过外部的方法来调用具体变量,做好隔离。当然也可以不用隔离,但很容易会显得很乱,也很危险(数据容易被错误的修改)。
访问限制
虽然模块中变量的访问域是约定俗成,但是class中变量是可以通过__前缀实现私有化的(但是不能同时也有__后缀,那样会变成可访问的特殊变量),类中单个下划线_开头的变量我们也想对待模块似的默认为私有变量平时不要随意访问。
__前缀的私有变量,python是通过把该变量名改变成如 _ClassA__VarB的形式实现的(也可能是其它形式),所以真想在外部修改私有变量也是可以通过访问a._ClassA__VarB做到的。(这是脚本语言的普遍问题,不能做到真正的私有)
继承和多态
继承:上文创建的ClassA类是object类的一个子类,object类是ClassA类的父类。
继承,使得子类继承了父类的全部公共功能,
如果我们对父类已有的功能在子类里重写,定制新的计算方式,就是类的多态特性。
判断实例的类型 isinstance(a,ClassA)
开闭原则:对拓展开放(新增子类),对修改封闭(使用该类的方法不用修改)
获取对象信息
判断对象信息 type() 对象可以是基本类型、也可是函数、属于某个自定义类
type() 返回的是Class类型 如 int str
怎么区分出对象是函数呢?
使用types模块
types.FunctionType
types.BuiltinFunctionType
types.LambdaType
types.GeneratorType
import types
def f():
pass
print(type(abs) == types.BuiltinFunctionType) #True
print(type(abs) == types.BuiltinMethodType) #True
print(type(abs) == types.FunctionType) #False 注意
print(type(f) == types.FunctionType) #True
print(type(lambda x:x) == types.FunctionType) #True
print(type(lambda x:x) == types.LambdaType) #True
相比下使用isinstance(a,ClassA)判断类型更方便,还可以判断a是否是某几个类型中的一种 isinstance(a,(ClassA,ClassB,classC));
获得一个对象的所有属性和方法,可以使用dir()函数这个方法听起来就很强大了,可以拆解任何我们想要去了解的对象。也可以对类使用。
import types
class ClassA():
def __play():
pass;
a = ClassA()
print(dir(a)) #_ClassA__play 注意这个私有方法也被打印出来了
#['_ClassA__play', '__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__']
这里除了__play方法外还要很多继承于object类的方法。
以__同时为前后缀的方法都是有特殊用途,比如 len([1,23,4]),就是调用list的__len__方法,我没也可以给没有__len__方法的类里添加这个方法就可以调用len(ClassA)了。
还有一些常用方法getattr() setattr() hasattr()
其中有个点,是 getattr()可以获取对象的方法。
class ClassA():
def __init__(self):
self.act = 'play'
def play(self):
print(self.act);
a = ClassA()
f = getattr(a,'play');
f() #成功打印play,这里跟js有些不同。js 如果直接调用f,play方法里是获取不到self的。这里看来python应该是有把a包装进f里。
实例属性和类属性
实例属性
动态语言的实例可以任意绑定属性,刷新属性。(删除属性呢[赋值为None是不行的可以用del a.x,dict可以用pop 、del和remove()], 增加方法呢,见下章高级编程?)方法:
1.在定义类时,给self绑定属性
2.给创建好的实例直接绑定 a.xx = xx
类属性
在定义类时,直接定义的变量(不绑定给self),该变量可以被类访问到,也可以被该类的所有实例访问到,如果实例又绑定了这个变量名,则会访问实例自身的变量值(类属性的优先级较低)
class ClassA():
act = 'do act'
def __init__(self):
self.act = 'play'
def play(self):
print(self.act);
print(ClassA.act) #do act
a = ClassA()
print(a.act) #play
思考题:
class Student():
count = 0
def __init__(self,name):
self.name = name
__class__.count += 1 #__class__的用途 也可用 Student 替代
a = Student('Mike')
a = Student('Jack')
a = Student('Lucy')
a = Student('Lily')
print(Student.count) # 4
####另一种测试
class Student():
count = 0
def __init__(self,name):
self.name = name
self.count += 1 #__class__的用途 也可用 Student 替代
a = Student('Mike')
a = Student('Jack')
a = Student('Lucy')
a = Student('Lily')
print(Student.count) # 0 说明实例重新绑定的count 变量和 Student的类变量count无关。