python之面向对象那点事
一、类与对象
1、什么是类?
类,顾名思义,就是具体相同属性的同一类事物的统称及抽象。
对象,指是就是具体的抽象类的实例
以上的说法是不是看起来有点云里来雾里去呢。没错,专业的解释总是让人难以理解,这就是专家。其实举个简单的例子大家就能理解了
如:牛马羊鸡鸭鹅,这些都是统称为 动物,没错吧。那动物就是上面所谓的类,而牛马羊鸡鸭鹅就是类中对应的实例,也就是对象。牛是对象,羊是对象,。。。现在明白了吧
python类是怎么定义和使用的,废话少说,上图,一目了然
2、类的成员:从上图可以看到,类包含了很多成员,那类中成员的分类是怎样的呢,看下图
3、类的三大特性:封装,继承,多态(python多态用得非常少)
何为封装:先来看个小问题,比如说要对数据库进行增删改查操作,那么我们可以定义4个函数用于实现这些功能。但每次调用这些函数时我们就必须给这些函数传参数,必须告诉这些函数要所边的数据库实例,用户名,密码,端口号等信息。这样一个,每一次的调用都是传这些相同的信息。1、是不是有更好的方法来使用这个重复的操作呢?2、另对于面向函数的调用,事实我们并不知道到底是谁用了函数。
对于面向对象来说,封装的概念实际上就是用于解决此类场景所产生的问题的。事实上我们可以这些公用的信息都放在构造函数中的参数中,即当实例化一个对象时就给这个对象赋予了这些信息,然后方法的调用就不用再重复在函数中传入这些参数了。调用方法时用指定的对象去调用这些方法,就知道是谁调用了,举个例子就清楚了
1 >>> #函数实现 2 ... 3 >>> def fetch(conn_info): 4 ... print "use %s conn to db for fetch" % conn_info 5 ... 6 >>> def modify(conn_info): 7 ... print "use %s conn to db for modify" % conn_info 8 ... 9 >>> #函数调用,每调用一次都需要传入参数 10 ... fetch('scott 123 127.0.0.1') 11 use scott 123 127.0.0.1 conn to db for fetch 12 >>> modify('scott 123 127.0.0.1') 13 use scott 123 127.0.0.1 conn to db for modify 14 >>> 15 >>> #类实现 16 ... class A: 17 ... def __init__(self,conn_info): 18 ... self.conn_info = conn_info 19 ... def fetch(self): 20 ... print "use %s conn to db for fetch" % self.conn_info 21 ... def modify(self): 22 ... print "use %s conn to db for modify" % self.conn_info 23 ... 24 >>> #类调用 25 ... #实例化一个对象,指明了谁(obj)调用,且公用参数只需要在实例化时传一次就行了 26 ... obj = A('scott 123 127.0.0.1') 27 >>> obj.fetch() 28 use scott 123 127.0.0.1 conn to db for fetch 29 >>> obj.modify() 30 use scott 123 127.0.0.1 conn to db for modify 31 >>>
4、类的继承
什么是继承?比如说两个人A和B,A可以行走吃喝,B也可以行走吃喝,且B还可以画画,而A却不会,那么我们就可以说B继承于A
#继承的定义 class A: def func1(self): print "func1" class B(A): def func2(self): print "func2" ##实例化对象 obj2 = B() ##调用父类方法 obj2.func1()
以上代码就指明了B类继承于A类,是不是很简单,且继承了A类(父类后就可以通过对象调用你类的方法了)
5、多继承:那么一个类只能继承于另一个类吗,是否可以继承于多个类,答案是肯定了,这个是python特有,其它语言并没有这个特性。问题来了,如果一个类D继承于B,C两个类,B,C两个类均继承于A类,B类没有方法func,C类有方法func,A类也有方法func,那D类实例化后调用func方法到底是调用哪个类的方法呢?
举个例子就清楚了,在看例子之前,先说下python中类的分类(为什么?因为以上问题分两种情况,经典类与新式类是有所不同的),在python中类分为经典类和新式类,定义新式类只需要在定义指明该类继承于object类即可,如下
#经典类 class A: pass #新式类 class B(object): pass
##经典类的多继承 class A: def func(self): print "funcA" class B(A): pass class C(A): def func(self): print "funcC" class D(B,C): pass #实例化对象 obj = D() #函数调用,打印funcA obj.func() ##新式类的多继承 class A(object): def func(self): print "funcA" class B(A): pass class C(A): def func(self): print "funcC" class D(B,C): pass #实例化对象 obj = D() #新式类函数调用,打印funcC obj.func()
执行结果:
1 >>> ##经典类的多继承 2 ... class A: 3 ... def func(self): 4 ... print "funcA" 5 ... 6 >>> class B(A): 7 ... pass 8 ... 9 >>> class C(A): 10 ... def func(self): 11 ... print "funcC" 12 ... 13 >>> class D(B,C): 14 ... pass 15 ... 16 >>> #实例化对象 17 ... obj = D() 18 >>> #函数调用,打印funcA 19 ... obj.func() 20 funcA 21 >>> 22 >>> ##新式类的多继承 23 ... class A(object): 24 ... def func(self): 25 ... print "funcA" 26 ... 27 >>> class B(A): 28 ... pass 29 ... 30 >>> class C(A): 31 ... def func(self): 32 ... print "funcC" 33 ... 34 >>> class D(B,C): 35 ... pass 36 ... 37 >>> #实例化对象 38 ... obj = D() 39 >>> #新式类函数调用,打印funcC 40 ... obj.func() 41 funcC
#从以上结果可以看出
经典类的查找是以深度优先为原则的,查询顺序:D->B->A,如果找不到,就报错,找到就调用
新式类的查询是以广度优先为原则的,查询顺序:D->B->C->A,如果找不到,就报错,找到就调用
6、类中常用的特殊成员
类名.__doc__ :打印类的注释信息(指用'''/"""引起来的注释信息)
类名/对象.__dict__: 返回类或对象包含的成员字典
__call__:在类中定义这个方法,事实上就是执行 对象() 调用的方法
__str__:如果一个类中定义了__str__方法,那么在打印 对象 时,默认输出该方法的返回值
7、其它相关
isinstance(obj, cls):检查是否obj是否是类 cls 的对象
issubclass(sub, super):检查sub类是否是 super 类的派生类
8、类的常用操作示例
class Person: class_v = 'beautiful' #静态字段/类变量 salary = 10000 __private_v = 'you can\'t read me from outside' #私有类变量 def __init__(self,name,age): self.name = name ##普通字段 self.age = age __male = 'girl' #静态私有字段 self.favorite = 'cat' def speak(self,des): ##普通方法 print "I'm {0},age {1},today is a {2} day!,so {3}".format(self.name,self.age,Person.class_v,des) @staticmethod def static_m(): #静态方法 print "This is a static method!" @classmethod #类方法 def class_m(cls,*args,**kwargs): print "This is a class method!" @property def attr_m(self): #属性,其实就是方法的变种 return self.favorite #这里只是个例子,实际应用中一般是通过一定的逻辑处理得到相应的值 @attr_m.setter #设置属性值 def attr_m(self,value): self.favorite = value return self.favorite @attr_m.deleter #删除属性值 def attr_m(self): del self.favorite def read_private(self): ##普通方法 print Person.__private_v class wo(Person): #继承 def __init__(self,name): self.name = name def des(self): print "%s is a lovely girl!" % self.name #类的实例化 obj = Person('min',18) #访问类变量 print obj.salary print Person.salary obj.salary += 2000 print obj.salary print Person.salary Person.salary += 50000 print obj.salary print Person.salary ##从上述结果可看出通过对象访问类变量并对其做修改并不影响在变量的值 #普通方法调用 obj.speak('nice') #调用静态方法,必须通过类调用 Person.static_m() #调用类方法,必须通过类调用 Person.class_m() #访问属性 obj.attr_m obj.attr_m = 'always cat!' print obj.attr_m del obj.attr_m #测试私有类变量的打印 obj.read_private() #访问继承类的方法 min = wo('min') min.des() #访问类变量 Person.class_v #访问私有类变量 Person.__private_v ##无法访问 obj._Person__private_v #强制访问私有成员
执行结果:
1 >>> class Person: 2 ... class_v = 'beautiful' #静态字段/类变量 3 ... salary = 10000 4 ... __private_v = 'you can\'t read me from outside' #私有类变量 5 ... def __init__(self,name,age): 6 ... self.name = name ##普通字段 7 ... self.age = age 8 ... __male = 'girl' #静态私有字段 9 ... self.favorite = 'cat' 10 ... def speak(self,des): ##普通方法 11 ... print "I'm {0},age {1},today is a {2} day!,so {3}".format(self.name,self.age,Person.class_v,des) 12 ... @staticmethod 13 ... def static_m(): #静态方法 14 ... print "This is a static method!" 15 ... @classmethod #类方法 16 ... def class_m(cls,*args,**kwargs): 17 ... print "This is a class method!" 18 ... @property 19 ... def attr_m(self): #属性,其实就是方法的变种 20 ... return self.favorite #这里只是个例子,实际应用中一般是通过一定的逻辑处理得到相应的值 21 ... @attr_m.setter #设置属性值 22 ... def attr_m(self,value): 23 ... self.favorite = value 24 ... return self.favorite 25 ... @attr_m.deleter #删除属性值 26 ... def attr_m(self): 27 ... del self.favorite 28 ... def read_private(self): ##普通方法 29 ... print Person.__private_v 30 ... 31 >>> class wo(Person): #继承 32 ... def __init__(self,name): 33 ... self.name = name 34 ... def des(self): 35 ... print "%s is a lovely girl!" % self.name 36 ... 37 >>> #类的实例化 38 ... obj = Person('min',18) 39 >>> #访问类变量 40 ... print obj.salary 41 10000 42 >>> print Person.salary 43 10000 44 >>> obj.salary += 2000 45 >>> print obj.salary 46 12000 47 >>> print Person.salary 48 10000 49 >>> Person.salary += 50000 50 >>> print obj.salary 51 12000 52 >>> print Person.salary 53 60000 54 >>> ##从上述结果可看出通过对象访问类变量并对其做修改并不影响在变量的值 55 ... 56 >>> #普通方法调用 57 ... obj.speak('nice') 58 I'm min,age 18,today is a beautiful day!,so nice 59 >>> #调用静态方法,必须通过类调用 60 ... Person.static_m() 61 This is a static method! 62 >>> #调用类方法,必须通过类调用 63 ... Person.class_m() 64 This is a class method! 65 >>> #访问属性 66 ... obj.attr_m 67 'cat' 68 >>> obj.attr_m = 'always cat!' 69 >>> print obj.attr_m 70 always cat! 71 >>> del obj.attr_m 72 >>> #测试私有类变量的打印 73 ... obj.read_private() 74 you can't read me from outside 75 >>> #访问继承类的方法 76 ... min = wo('min') 77 >>> min.des() 78 min is a lovely girl! 79 >>> 80 >>> #访问类变量 81 ... Person.class_v 82 'beautiful' 83 >>> #访问私有类变量 84 ... Person.__private_v ##无法访问 85 Traceback (most recent call last): 86 File "<stdin>", line 2, in <module> 87 AttributeError: class Person has no attribute '__private_v' 88 >>> obj._Person__private_v #强制访问私有成员 89 "you can't read me from outside" 90 >>>