虽然Python是解释性语言,但是它是面向对象的,能够进行对象编程。下面就来了解一下如何在Python中进行对象编程。
一.如何定义一个类:
在进行python面向对象编程之前,先来了解几个术语:类,对象,函数和方法。
类是对现实世界中一些事物的封装(比较抽象的定义),定义一个类可以采用下面的方式来定义:
1 class className: 2 block
注意类名后面有个冒号,在block块里面就可以定义属性和方法了。当一个类定义完之后,就产生了一个类对象。类对象支持两种操作:引用和实例化。引用操作是通过类对象去调用类中的属性或者方法,而实例化是产生出一个类对象的实例,称作实例对象。比如定义了一个people类(通过这个示例,你应该了解了怎么定义个类和类中的方法,对象的封装以及调用等知识):
1 class people: 3 #定义了一个方法 4 def printName(self,*args): 5 print self.name
6 obj = people() #类名后面加(),就生成一个对象obj
7 obj.name = 'alex' #把alex这个值封装在obj的name属性中
8 obj.printName() #对象调用类中的方法,方法也只能通过对象去调用
9 #输出
10 alex
二.面向对象的中的成员:
1、字段:
在一个类里面可以定义两种字段,一个是静态字段,一个是普通字段,下面来写一个示例,分别阐述下什么是静态字段,什么是普通字段:
1 class TestClass(): 2 static_dd = '123' 3 def __init__(self,name): 4 self.name = name 5 def f1(self): 6 print(self.name) 7 8 obj = TestClass('alex') 9 obj.f1() 10 11 #输出结果 12 alex
解释说明:
在TestClass类中,static_dd就是静态字段,该字段需要通过类名.static_dd来调用执行输出字段的结果;在静态字段的下面定义了一个构造方法__init__,在这里说明一下,构造方法在创建类对象(obj = TestClass('alex'))的时候就会调用执行,在你创建类对象的时候传递一个字符串参数alex,那么构造方法中的(name=alex,self=obj);那么在使用对象调用f1方法的时候,就会输出alex;通过我的一番细心悠长的讲解之后,相信现在你已经知道什么是静态字段,什么是普通字段了。方法你不懂没关系,因为下面讲的就是!!!
2、方法:
先以上面那个TestClass类做说明:上面写的那个f1方法就是一个普通的方法,除了普通方法外,还有静态方法、类方法,下面就写一个例子,来说明一下这三个方法:
1 class TestClass: 2 name = 'alex' 3 def f1(self): 4 pass 5 @staticmethod 6 def f2(): 7 print('static method') 8 @classmethod 9 def f3(cls): 10 print(cls.name) 11 12 obj = TestClass() 13 obj.f2() 14 obj.f3() 15 16 #输出结果 17 static method 18 alex
解释说明:
在f2方法的上面加个@staticmethod,表示f2就是一个静态方法,你会发现静态方法里面可以没有参数,那这个方法就跟以前学的函数有几分相似了,直接通过对象去调用即可。f3方法里面的参数也不认识,上面加个@classmethod,就形成一个类方法,类方法的作用,可以看我们的这段代码,里面是cls参数,name是一个静态字段,在上面的内容中我们知道,静态字段只能通过类去调用,那这里就容易理解了,cls其实就相当于TestClass类,soeasy吧!!!
三、成员修饰符:
说完类中的成员,下面再来说下这些成员的修饰,怎么个修饰发呢?下面看一个例子:
1 class TestClass: 2 name = 'alex' 3 __name = 'eric' 4 def __init__(self,count1,count2): 5 self.count1 = count1 6 self__count2 = count2 7 8 obj = TestClass(1,2) 9 print(TestClass.name) 10 print(obj.count1) 11 12 #输出结果 13 alex 14 1
解释说明:
这个例子中输出的alex值是类调用类中的name字段来输出的;数字1封装在了对象obj中,所以直接就可以输出;那么问题来了,我为啥不用类调用__name这个静态字段呢?我为啥不用对象取出count2的值呢?,,,,这就牵涉到了,私有和公有的说法了,那么下面就来聊聊私有和公有。
像上面__name就是传说中的私有字段,self.__count2 = count2也是以私有的方式封装在了对象中,不管是私有的静态字段、还是私有的普通字段,都只能在自己的类中的去调用,在外面调用会报错,不信咱就来看看:
1 class TestClass: 2 name = 'alex' 3 __name = 'eric' 4 def __init__(self,count1,count2): 5 self.count1 = count1 6 self__count2 = count2 7 def f1(self): 8 print(self.__count2) 9 @classmethod 10 def f2(cls): 11 print(cls.__name) 12 13 14 15 obj = TestClass(1,2) 16 obj.f1() 17 obj.f2() 18 19 输出结果 20 Traceback (most recent call last): 21 File "D:Program Files (x86)JetBrainsPyCharm 5.0.3helperspycharmutrunner.py", line 121, in <module> 22 modules = [loadSource(a[0])] 23 File "D:Program Files (x86)JetBrainsPyCharm 5.0.3helperspycharmutrunner.py", line 41, in loadSource 24 module = imp.load_source(moduleName, fileName) 25 File "D:python35libimp.py", line 172, in load_source 26 module = _load(spec) 27 File "<frozen importlib._bootstrap>", line 693, in _load 28 File "<frozen importlib._bootstrap>", line 673, in _load_unlocked 29 File "<frozen importlib._bootstrap_external>", line 662, in exec_module 30 File "<frozen importlib._bootstrap>", line 222, in _call_with_frames_removed 31 File "D:PycharmProjectss13 estday08_test.py", line 180, in <module> 32 obj.f1() 33 File "D:PycharmProjectss13 estday08_test.py", line 172, in f1 34 print(self.__count2) 35 AttributeError: 'TestClass' object has no attribute '_TestClass__count2'
上面报的错误,就是没有权限去调用的意思,因为你所调用的都是私有的变量,无法在类外面去调用,那么,如果我们换成下面这种,就没有问题(这也证明了我们刚才论点),这样你就明白了私有和公有了:
1 class TestClass: 2 name = 'alex' 3 __name = 'eric' 4 def __init__(self,count1,count2): 5 self.count1 = count1 6 self__count2 = count2 7 print(TestClass.__name) 8 print(self__count2) 9 def f1(self): 10 print(self.__count2) 11 @classmethod 12 def f2(cls): 13 print(cls.__name) 14 15 16 17 obj = TestClass(1,2) 18 # obj.f1() 19 # obj.f2() 20 21 #输出结果 22 eric 23 2
三.类中内置的方法
在Python中有一些内置的方法,这些方法命名都有比较特殊的地方(其方法名以2个下划线开始然后以2个下划线结束)。类中最常用的就是构造方法(封装)。
构造方法__init__(self,....)在生成对象时调用,可以用来进行一些初始化操作,不需要显示去调用,系统会默认去执行。构造方法支持重载,如果用户自己没有重新定义构造方法,系统就自动执行默认的构造方法,看下面这个示例:
1 class first_test: 2 def __init__(self,name,obj): 3 self.name = name 4 self.obj = obj 5 def fetch(self): 6 print(self.obj.age) 7 8 class second_test: 9 def __init__(self,name,age): 10 self.name = name 11 self.age = age 12 def show(self): 13 print(self.age) 14 return True 15 16 class three_test: 17 def __init__(self,aa): 18 self.aa = aa 19 def show(self): 20 print(self.aa.obj.age) 21 c1 = second_test('alex',18) 22 c2 = first_test('madq',c1) 23 c3 = three_test(c2) 24 print(c3.aa.obj.name) 25 print(c3.aa.obj.show())
上面说了__init__是构造方法,在创建对象的时候就会调用,除了构造方法,还有一些其它的一些特殊方法,比如析构方法,像下面的都是析构方法,先简单说下析构的作用,然后再举一个例子说下每个方法的不同用法:
__call__ : 对象后面加()的时候会调用
__getitem__ : 对象后面加[]时调用,相当于字典的取值
__setitem__ : obj['k1'] = 111,相当于字典的赋值
__delitem__ : del obj['k1'],相当于字典的删值
__dict__ : 获取对象中封装的数据(非常重要),这个用的比较多,而且也比较重要
__str__ : print(obj)的时候会调用
1 class TestClass: 2 def __call__(self, *args, **kwargs): 3 print(args) 4 def __getitem__(self, item): 5 print(item) 6 def __setitem__(self, key, value): 7 print(key,value) 8 def __delitem__(self, key): 9 print(key) 10 11 obj = TestClass() 12 obj(1,2) 13 obj['k1'] 14 obj['k1'] = 'v1' 15 del obj['k1'] 16 17 #输出的顺序跟析构方法的顺序是一样的 18 (1, 2) 19 k1 20 k1 v1 21 k1
解释说明:
这个几个最基本的析构方法表明了,对象后面加不同的符号,就会调用不同的方法,从而输出不同的值。我们都知道字典是无序的, 那我们是不是可以借助这几个关于字典的析构方法做出一个有序的字典,下面我们试试:
1 class mydict(dict): 2 def __init__(self): 3 self.li = [] 4 super(mydict,self).__init__() 5 6 def __setitem__(self, key, value): 7 self.li.append(key) 8 super(mydict,self).__setitem__(key,value) 9 10 def __str__(self): 11 temp_list = [] 12 for key in self.li: 13 value = self.get(key) 14 temp_list.append("'%s':%s"%(key,value)) 15 temp_str = "{"+",".join(temp_list)+"}" 16 return temp_str 17 18 obj = mydict() 19 obj['k1'] = 123 20 obj['k2'] = 456 21 #print一个对象的时候,会调用类中的__str__方法 22 print(obj) 23 24 #输出结果 25 {'k1':123,'k2':456}
有序字典的输出,是借助于列表的有序性,存放key;然后使用这些有序的key再去字典里去value,然后再存放在列表中输出即可。在这段代码里面你不太明白的可能就是那个super()了,它后面调用的方法是父类的方法。其次是mydict(dict)里面的dict了,这个会在下面讲解,这个得意思是mydict类继承了dict类,也就是说mydict是dict的子类,有了这个继承的关系,才有了下面的调用的关系。
四、继承
在Python中,一个类可以是其它类的子类,也可以是其它类的父类(跟其它语言不太相同的地方是Python是多继承的,也就是说一个子类可以有多个父类)。
五、异常处理
先看下Python异常处理的完整语法:
try:
statement
#要执行的程序
except Exception:
#报错的时候执行
else:
#没有报错会执行
finally:
#最后不管程序执行对错,都会执行个
看过这个完整的语法,我们再看下这个完整语法的实例(通过这个实例你可以看到整个语法的用法,try下面定义的raise的意义在于自定义一个错误,它下面的都不会执行,这个错误只是一个子类,它们的父类是Exception):
1 def f1(): 2 try: 3 raise MemoryError 4 except MemoryError: 5 print('This a defined error!') 6 else: 7 print('haha') 8 finally: 9 print('END') 10 11 f1() 12 13 #输出结果 14 This a defined error! 15 END