oop、try_except、单例模式

本节大纲:



面向对象特性:封装、继承、多态。
一:多态:python本身是多态,他的参数可以多种类型。可以是字符串、数字、列表等。当传入参数的时候,python可以判断参数的数据类型。
而在java C#中不是。需要指定参数的类型。实现多态,需要指定类型为父类、参数类型可以是父类和子类的类型来实现多态特性。
由于python本身的多态导致,由于类型的不确定,到时候在读源码的时候增加难度。这也算是python本身的一个缺点。
二:
类的成员
字段:分普通字段(动态字段)和静态字段。
1 class test:
2     def __init__(self,name,age):
3         self.name=name
4         self.age=age
5     def show(self):
6         print(self.name,self.age)
7 evil 30

 1 class test:
 2     job='IT'
 3     def __init__(self,name,age):
 4         self.name=name
 5         self.age=age
 6     def show(self):
 7         print(self.name,self.age)
 8 
 9 
10 
11 obj=test('evil',30)
12 obj.show()
13 print(test.job)

a:访问方式:

默认是自己访问自己字段的。

普通字段属于对象,需要通过对象去访问。

静态字段属于类的(万不得已情况下,可以用对象通过类对象指针间接访问静态字段)。

b:

静态字段在程序加载的时候,就创建。

而普通字段(动态字段)在对象未创建的时候,该字段不会被创建和加载到内存中。

普通字段只能通过对象访问。

1 class province:
2     country='China'
3     def __init__(self,name):
4         self.name=name
5     def  show(self):
6         print(self.name)
7 
8 print(province.country)
9 China

 

说明:普通字段是属于对象的,每个对象的创建的时候,自动创建这个字段。

静态字段是属于类的,在类的创建的时候只需一份,每次调用都是调用类的中的静态字段。

也就是普通字段在对象的创建的时候生成,创建多少个对象,就创建多少普通字段,并保存在对象中。

而静态字段无论对象创建多少份,他只调用类中一份静态字段。

练习:

 1 class province:
 2     country='China'
 3     def __init__(self,name):
 4         self.name=name
 5     def  show(self):
 6         print(self.name)
 7 
 8 
 9 obj=province('Liaoning')
10 obj.show()
11 print(province.country)
12 Liaoning
13 China

c:使用场景

当对象有一个共同默认值的时候,可以使用静态字段来代替普通字段(动态字段)避免重复创建字段,浪费内存。

 

三:方法

静态方法、普通方法、类方法

 1 class co:
 2     name='ack'
 3     def __init__(self,name):#普通方法必须要有self参数
 4         self.name=name
 5     def show(self):#普通方法
 6         print(self.name)
 7     @staticmethod##静态方法,参数可以自己指定没有必要参数
 8     def look(name,age):
 9         print(name,age)
10     @classmethod#类方法,必需参数cls
11     def cat(cls):
12         print(cls.name)
13 co.look('evil',23)
14 obj=co('tom')
15 obj.show()
16 co.cat()
17 evil 23
18 tom
19 ack

 

注意:

普通方法:必需参数:self  对象调用  obj. methodname()

静态方法:无必需参数。直接用类调用 类名.方法()

类方法:必需参数:cls 属于静态方法的特殊一种。也是直接用类调用。

 总结:

也就是说,对象想调用非自己的字段和方法,需要通过类对象指针去类或者父类中找相应的方法和字段。

而类的字段(静态字段)和方法(静态方法、类方法)可以用类本身去调用,但是对象的普通字段无法调用。

三:属性。

个人理解:把方法用字段的形式进行访问。也就是说把方法去掉括号。

也就是说方法通过属性的方式伪造成字段访问形式。

通过类似字段的设置:重新赋值、删除动作触发执行相应属性的setter、deleter函数,至于函数的内容我们自定义,当用户执行这样的操作的时候,我们执行相应的动作。

方法一:

 1 class Get_page:
 2     def __init__(self,page_count):
 3         self.page_count=page_count
 4     @property
 5     def get_page(self):
 6         a,b=divmod(self.page_count,10)
 7         if b==0:
 8             return a
 9         else:
10             return a+1
11 obj=Get_page(101)
12 res=obj.get_page
13 print(res)
14 11

 

 1 class Get_page:
 2     def __init__(self,page_count):
 3         self.page_count=page_count
 4     @property
 5     def get_page(self):
 6         a,b=divmod(self.page_count,10)
 7         if b==0:
 8             return a
 9         else:
10             return a+1
11     @get_page.setter
12     def get_page(self,value):
13         print(value)
14     @get_page.deleter
15     def get_page(self):
16         print('del')
17 
18 obj=Get_page(101)
19 res=obj.get_page
20 print(res)
21 obj.get_page=111
22 del obj.get_page
23 
24 
25 11
26 111
27 del

方法二:

通过方法property来实现属性。这种方式在源码里出现较多。

 1 class Get_page:
 2     def __init__(self,page_count):
 3         self.page_count=page_count
 4     def f1(self):
 5         print('f1')
 6     def f2(self,value):
 7         print('f2')
 8     def f3(self):
 9         print('f3')
10     a=property(fget=f1,fset=f2,fdel=f3)
11 
12 obj=Get_page(111)
13 obj.a
14 obj.a=1
15 del obj.a
16 f1
17 f2
18 f3

四:成员修饰符

只有(public)和私有(private)两种。

a:作用域:共有在类中、类外都可以进行调用。

私有只能类中调用,外部想引用必须通过内部方法进行调用。

b:语法:

私有:两个下划线:__

字段:

1 class  Test:
2     def __init__(self,name):
3         self.__name=name#私有属性
4     def show(self):
5         print(self.__name)#只能内部方法进行调用
6 obj=Test('tom')
7 obj.show()
8 tom

 

不可以这样:

class  Test:
    def __init__(self,name):
        self.__name=name
    def show(self):
        print(self.__name)
obj=Test('tom')
print(obj.__name)
会报:AttributeError: 'Test' object has no attribute '__name'

 共有:

1 class  Test:
2     def __init__(self,name):
3         self.name=name#就是共有字段。
4     def show(self):
5         print(self.name)
6 obj=Test('tom')
7 print(obj.name)
8 tom

 方法:

 1 class  Test:
 2     def __init__(self,name):
 3         self.name=name
 4     def __show(self):##私有方法
 5         print(self.name)
 6     def cat(self):
 7         self.__show()
 8 
 9 obj=Test('evil')
10 obj.cat()

 外部想调用内部属性只能通过内部函数的间接调用实现外部的调用。

1 class  Test:
2     def __init__(self,name):
3         self.name=name
4     @staticmethod
5     def __show(user):##私有静态方法。
6         print(user)
7     def cat(self):
8         Test.__show('tom')
9 tom

在其他语言中私有无法访问,但是python可以强制访问,最好不要这么操作,不符合python代码规范。方法:单下划线,对象._类名__属性名双下划线,没有属性. 。

 1 class  Test:
 2     def __init__(self,name):
 3         self.__name=name
 4     @staticmethod
 5     def __show(user):
 6         print(user)
 7     def cat(self):
 8         Test.__show('tom')
 9 
10 obj=Test('evil')
11 obj._Test__show('op')
12 print(obj._Test__name)
13 op
14 evil

 五:python特殊成员:

a:__del__ 析构方法。在类的对象回收之前,会执行该函数,如果该函数如果存在的话。

 1 class  Test:
 2     def __init__(self,name):##构造方法。
 3         self.__name=name
 4     @staticmethod
 5     def __show(user):
 6         print(user)
 7     def cat(self):
 8         Test.__show('tom')
 9     def __del__(self):###析构方法,在对象回收之前会执行该函数。
10         pass

 

b: __call__方法,执行方式:object()即对象后面加个括号。会自动调用该函数。

1 class  Test:
2     def __init__(self,name):
3         self.name=name
4     def __call__(self, *args, **kwargs):
5         print('call')
6 obj=Test('OK')
7 obj()##执行方式  或者Test()()也是调用__call__方法。

 

c:__str__方法。执行方法是比如:print(obj)或者str(obj)会自动调用__strr__方法,如果没有该方法对象将返回对象在内存在地址。

注意:__str__返回的是字符串表达式。不是字符串形式,用str()转换。

1 class  Test:
2     def __init__(self,name):
3         self.name=name
4     def __call__(self, *args, **kwargs):
5         print('call')
6 obj=Test('OK')
7 print(obj)
8 <s4.Test object at 0x00000000019B9D68>
 1 class  Test:
 2     def __init__(self,name):
 3         self.name=name
 4     def __call__(self, *args, **kwargs):
 5         print('call')
 6     def __str__(self):
 7         return self.name
 8 
 9 obj=Test('evil')
10 print(obj)
11 evil

 根据这个特性可以不用直接使用obj.name访问obj的name普通字段。可以用__str__方法,直接返回相应的属性。或者返回多个数据用字符串的拼接。

 1 class  Test:
 2     def __init__(self,name,age,job):
 3         self.name=name
 4         self.age=age
 5         self.job=job
 6     def __call__(self, *args, **kwargs):
 7         print('call')
 8     def __str__(self):
 9         return '%s_%s_%s'%(self.name,self.age,self.job)
10 
11 obj=Test('evil',22,'IT')
12 print(obj)
13 evil_22_IT

d:__class__获取类名字:

1 class Test:
2     def show(self):
3         print('OK')
4 obj=Test()
5 print(obj.__class__)
6 <class '__main__.Test'>##main表示调用是在本程序内。

 

e:__dict__方法:如果是对象,获取对象的封装的数据以字典形式展示,如果是类获取类有的方法自带和自定义的方法,该方法比较重要,以后再form认证的时候会用到该方法。

 1 class Test:
 2     def __init__(self,name,job):
 3         self.name=name
 4         self.job=job
 5     def show(self):
 6         print('OK')
 7 obj=Test('tom','IT')
 8 print(obj.__dict__)
 9 print(Test.__dict__)
10 {'job': 'IT', 'name': 'tom'}
11 {'__dict__': <attribute '__dict__' of 'Test' objects>, 'show': <function Test.show at 0x0127F468>, '__init__': <function Test.__init__ at 0x0127F420>, '__module__': 's2', '__doc__': None, '__weakref__': <attribute '__weakref__' of 'Test' objects>}
12 <class 's2.Test'>

 f:__setitem__、__getitem__、__delitem__:操作对象,不同的动作会触发相应的方法,在写session的时候会用到这几个方法。

 1 class Test:
 2     def __init__(self,name,job):
 3         self.name=name
 4         self.job=job
 5     def show(self):
 6         print('OK')
 7     def __setitem__(self, key, value):
 8         print(key,value)
 9     def __getitem__(self, item):
10         print(item)
11     def __delitem__(self, key):
12         print(key)
13 obj=Test('tom','IT')
14 obj['get']
15 obj['tom']=123
16 del obj['del']
17 get
18 tom 123
19 del

字典就是用上述的方法进行相应的操作的。来实现赋值、查看、删除等操作。

python3中,当对象操作切片的时候也会调用__setitem__、__getitem__、__delitem__。如果是切片动作传进去实参是切片对象。

 1 class Test:
 2     def __getitem__(self, item):
 3         print(type(item))
 4         print('get')
 5     def __setitem__(self, key, value):
 6         print(type(key),type(value))
 7 
 8     def __delitem__(self, key):
 9         print(type(key))
10 
11 
12 obj=Test()
13 obj[1:3]
14 obj[1:4]=[1,2,3,]
15 del obj[1:3]
16 <class 'slice'>
17 get
18 <class 'slice'> <class 'list'>
19 <class 'slice'>

 

可以根据传进去的对象类型进行相应的操作。当传进去是slice的时候,可以获取起起始、步长、结束。

class Test:
    def __getitem__(self, item):
        print(item.start)
        print(item.stop)
        print(item.step)
    def __setitem__(self, key, value):
        print(type(key),type(value))

    def __delitem__(self, key):
        print(type(key))


obj=Test()
obj[1:3:3]
obj[1:4]=[1,2,3,]
del obj[1:3]
1
3
3
<class 'slice'> <class 'list'>
<class 'slice'>

 g:__iter__方法:当一个对象被迭代:比如放在for循环里的时候,会自动执行对应类中的__iter__方法,元组、字符串、列表等在被迭代的时候,自动执行元组、字符串等类中的__iter__方法。

1 class Test:
2     def __iter__(self):
3         yield  1
4         yield  2
5 obj=Test()
6 for i in obj:
7     print(i)

 __iter__方法 需要返回一个迭代器,而不是一个列表或者元组。。

1 class Test:
2     def __iter__(self):
3         return iter('avcc')
4 obj=Test()
5 for i in obj:
6     print(i)
 h: isinstance判断对象是否是一个类的类型或者是否是该类的父类的类型。issubclass是判断一个类是否是另一个类的父类。
 1 class Test_old:
 2     def f1(self):
 3         print('Test_old.f1')
 4 
 5 class Test(Test_old):
 6     def f1(self):
 7         print('Test.f1')
 8 
 9 
10 obj=Test()
11 print(isinstance(obj,Test))
12 print(isinstance(obj,Test_old))
13 True
14 True

 

 1 class Test_old:
 2     def f1(self):
 3         print('Test_old.f1')
 4 
 5 class Test(Test_old):
 6     def f1(self):
 7         print('Test.f1')
 8 
 9 print(issubclass(Test,Test_old))
10 True

 

六:super()函数的应用以及源码的修改方式
a:super(),在执行子类的方法同时,也执行父类中相同名字的方法。

 1 class Test_old:
 2     def f1(self):
 3         print('Test_old.f1')
 4 
 5 class Test(Test_old):
 6     def f1(self):
 7         super(Test,self).f1()#执行自己类的父类中的f1方法。
 8         print('Test.f1')
 9 
10 obj=Test()
11 obj.f1()
12 Test_old.f1
13 Test.f1

 

super参数可以省略自动去执行该类的父类中相同的方法。参考官网: https://docs.python.org/3.1/library/functions.html#super
1 class C(B):
2     def method(self, arg):
3         super().method(arg)    # This does the same thing as:
4                                # super(C, self).method(arg)
 1 class Test_old:
 2     def f1(self):
 3         print('Test_old.f1')
 4 
 5 class Test(Test_old):
 6     def f1(self):
 7         super().f1()
 8         print('Test.f1')
 9 Test_old.f1
10 Test.f1
使用场景:当我们接触别人代码或者源码的时候,需要对功能的改进的时候,需要遵循不修改源码的规则,使用类的继承以及super()的方法,可以在完全执行源码的功能的基础上,执行我们自己的代码。
如下例子是将无序字典转化成有序字典: 核心思想,在不修改源代码的情况下,进行代码的重构。
 1 class SorDic(dict):
 2     def __init__(self):
 3         super().__init__()
 4         self.lis=[]
 5     def __setitem__(self, key, value):
 6         super(SorDic,self).__setitem__(key,value)
 7         self.lis.append(key)
 8 
 9     def __str__(self):
10         tem_lis=[]
11         for key in self.lis:
12             value=self.get(key)
13             tem_lis.append('%s:%s'%(key,value))
14         return '{'+','.join(tem_lis)+'}'
15 
16 obj=SorDic()
17 obj['m']=2
18 obj['n']=3
19 print(obj)

七:设计模式:单例模式。

单例模式:单个实例模式,也就是创建单个对象实例。应用场景:数据库连接池,只需要创建一个连接池既可,无须创建多个。

 1 class Singal:
 2     instance=None
 3     def __init__(self,name):
 4         self.name=name
 5     @classmethod
 6     def get_instance(cls):
 7         if cls.instance:
 8             return cls.instance
 9         else:
10             obj=cls('tom')###注意这个是常量问题。
11             cls.instance=obj
12             return cls.instance
13 
14 obj1=Singal.get_instance()
15 obj2=Singal.get_instance()
16 print(id(obj1),id(obj2))
17 5223568 5223568
注意:1:需要使用类方法,因为在对象未创建的时候可以调用类方法。
2:返回值是一个对象。
   3:初始化__init__参数直接写入一个实参。
八:异常处理:
简单的异常处理:
1 while True:
2     try:
3         num1=input('Entre a number:')
4         num2=input('Entre a number:')
5         res=int(num1)+int(num2)
6         print(res)
7     except Exception as e:
8         print(e)

1:try:存放正常的代码。

2:except存放 Execption类的对象e  e存储的是错误信息。并把错误信息打印输出。

except代码块 可以写Exception 捕捉所有错误,或者多个except来显式的捕获具体的错误。

 

 1 while True:
 2     try:
 3         num1=input('Entre a number:')
 4         num2=input('Entre a number:')
 5         res=int(num1)+int(num2)
 6         print(res)
 7         lis=[1,2]
 8         print(lis[100])
 9     except ValueError as e:
10         print(e)
11     except IndexError as e:
12         print(e)
13     
a:通常做法是:通过except捕获多个具体的异常,最后用Execption捕获我们不需要的异常。注意顺序!
 1 while True:
 2     try:
 3         num1=input('Entre a number:')
 4         num2=input('Entre a number:')
 5         res=int(num1)+int(num2)
 6         print(res)
 7         lis=[1,2]
 8         print(lis[100])
 9     except ValueError as e:
10         print(e)
11     except IndexError as e:
12         print(e)
13     except Exception as e:
14         print(e)

 

b:常见的异常:
AttributeError 试图访问一个对象没有的树形,比如foo.x,但是foo没有属性x
IOError 输入/输出异常;基本上是无法打开文件
ImportError 无法引入模块或包;基本上是路径问题或名称错误
IndentationError 语法错误(的子类) ;代码没有正确对齐
IndexError 下标索引超出序列边界,比如当x只有三个元素,却试图访问x[5]
KeyError 试图访问字典里不存在的键
KeyboardInterrupt Ctrl+C被按下
NameError 使用一个还未被赋予对象的变量
SyntaxError Python代码非法,代码不能编译(个人认为这是语法错误,写错了)
TypeError 传入对象类型与要求的不符合
UnboundLocalError 试图访问一个还未被设置的局部变量,基本上是由于另有一个同名的全局变量,
导致你以为正在访问它
ValueError 传入一个调用者不期望的值,即使值的类型是正确的

 c:完整的异常处理块: 

1 try:
2     pass
3 except Exception as e:
4     print(e)
5 else:
6     pass
7 finally:
8     pass
注意:
try代码块中,在执行过程中如果出现错误,则直接跳到execpt代码块中。
当执行try代码块的时候无报错,则执行else代码块,最后执行finally代码块。
如果执行try代码块的出现错误则直接跳到execpt代码块,最后执行finally代码块。

d:主动错误异常:raise 语句

1 try:
2     raise Exception('Error')
3 except Exception as e:
4     print(e)
5 finally:
6     pass

 1 class Lmd(Exception):
 2 
 3     def __init__(self, msg):
 4         self.message = msg
 5 
 6     def __str__(self):
 7         return self.message
 8 
 9 try:
10     raise Lmd('my error')
11 except Lmd as e:
12     print(e)
e:assert断言,assert  condition   条件成立不报错,不成立报错。
1 assert  1=2
2 AssertionError

 

 

 

 

 




posted @ 2016-06-27 17:58  evil_liu  阅读(330)  评论(0编辑  收藏  举报