{ "cells": [ { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "skip" }, "toc": "true" }, "source": [ "# Table of Contents\n", "

1  Python 面向对象进阶
1.1  类成员
1.2  字段
1.3  方法
1.4  属性
1.5  类特殊成员
1.6  扩展
1.7  异常处理
1.7.1  常用异常:
1.7.2  其他异常:
1.7.3  异常处理结构:
1.7.4  主动触发异常:
1.7.5  自定义异常:
1.7.6  断言:
1.8  反射
1.9  设计模式
1.9.1  单例
" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Python 面向对象进阶" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## 类成员\n", "\n", "类的成员可以分为三大类:字段、方法和属性" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "![类成员信息](class_info.png)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "注:所有成员中,只有普通字段的内容保存对象中,即:根据此类创建了多少对象,在内存中就有多少个普通字段。而其他的成员,则都是保存在类中,即:无论对象的多少,在内存中只创建一份。" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## 字段\n", "\n", "字段包括:普通字段和静态字段,他们在定义和使用中有所区别,而最本质的区别是内存中保存的位置不同,\n", "\n", "- 普通字段属于对象\n", "- 静态字段属于类" ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "湖南\n" ] }, { "data": { "text/plain": [ "'中国'" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "class Province:\n", "\n", " # 静态字段(属于类)\n", " country = '中国'\n", "\n", " def __init__(self, name):\n", "\n", " # 普通字段(属于对象)\n", " self.name = name\n", "\n", "\n", "# 直接访问普通字段\n", "obj = Province('湖南')\n", "print(obj.name) \n", "\n", "# 直接访问静态字段\n", "Province.country" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "由上述代码可以看出【普通字段需要通过对象来访问】【静态字段通过类访问】,在使用上可以看出普通字段和静态字段的归属是不同的。其在内容的存储方式类似如下图:" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "![类字段](class_field.png)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "由上图可是:\n", "\n", "- 静态字段在内存中只保存一份\n", "- 普通字段在每个对象中都要保存一份\n", "\n", "应用场景: 通过类创建对象时,如果每个对象都具有相同的字段,那么就使用静态字段" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## 方法\n", "\n", "方法包括:普通方法、静态方法和类方法,三种方法在内存中都归属于类,区别在于调用方式不同。\n", "\n", "- 普通方法:由对象调用;至少一个self参数;执行普通方法时,自动将调用该方法的对象赋值给self;\n", "- 类方法:由类调用; 至少一个cls参数;执行类方法时,自动将调用该方法的类复制给cls;\n", "- 静态方法:由类调用;无默认参数;" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "class Foo:\n", "\n", " def normal_func(self):\n", " \"\"\" 定义普通方法,至少有一个self参数 \"\"\"\n", "\n", " # print self.name\n", " print('普通方法')\n", "\n", " @classmethod\n", " def class_func(cls):\n", " \"\"\" 定义类方法,至少有一个cls参数 \"\"\"\n", "\n", " print('类方法')\n", "\n", " @staticmethod\n", " def static_func():\n", " \"\"\" 定义静态方法 ,无默认参数\"\"\"\n", "\n", " print('静态方法')\n", "\n", "\n", "\n", "# 调用普通方法\n", "f = Foo()\n", "f.normal_func()\n", "\n", "# 调用类方法\n", "Foo.class_func()\n", "\n", "# 调用静态方法\n", "Foo.static_func()" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "**相同点:** 对于所有的方法而言,均属于类(非对象)中,所以,在内存中也只保存一份。\n", "\n", "**不同点:** 方法调用者不同、调用方法时自动传入的参数不同。" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## 属性\n", "\n", "如果你已经了解Python类中的方法,那么属性就非常简单了,因为Python中的属性其实是普通方法的变种,像使用字段那样简单的使用,但是又能像方法一样做一些运算。\n", "\n", "对于属性,有以下两个知识点:\n", "\n", "- 属性的基本使用\n", "- 属性的两种定义方式" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "**属性的基本使用:**" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "data": { "text/plain": [ "'normal'" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" }, { "data": { "text/plain": [ "'property'" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# ############### 定义 ###############\n", "class Foo:\n", "\n", " def func(self):\n", " return \"normal\"\n", "\n", " # 定义属性\n", " @property\n", " def prop(self):\n", " return \"property\"\n", " \n", " \n", "# ############### 调用 ###############\n", "foo_obj = Foo()\n", "\n", "foo_obj.func()\n", "foo_obj.prop #调用属性" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "由属性的定义和调用要注意一下几点:\n", "\n", "定义时,在普通方法的基础上添加 @property 装饰器;\n", "\n", "定义时,属性仅有一个self参数\n", "\n", "调用时,无需括号\n", "- 方法:foo_obj.func()\n", "- 属性:foo_obj.prop\n", "\n", "注意:属性存在意义是:访问属性时可以制造出和访问字段完全相同的假象,属性由方法变种而来,如果Python中没有属性,方法完全可以代替其功能。" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "**实例:**对于主机列表页面,每次请求不可能把数据库中的所有内容都显示到页面上,而是通过分页的功能局部显示,所以在向数据库中请求数据时就要显示的指定获取从第m条到第n条的所有数据(即:limit m,n),这个分页的功能包括:\n", "\n", "- 根据用户请求的当前页和总数据条数计算出 m 和 n\n", "- 根据m 和 n 去数据库中请求数据 " ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "data": { "text/plain": [ "0" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" }, { "data": { "text/plain": [ "10" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# ############### 定义 ###############\n", "class Pager:\n", "\n", " def __init__(self, current_page):\n", " # 用户当前请求的页码(第一页、第二页...)\n", " self.current_page = current_page\n", " # 每页默认显示10条数据\n", " self.per_items = 10\n", "\n", "\n", " @property\n", " def start(self):\n", " val = (self.current_page - 1) * self.per_items\n", " return val\n", "\n", " @property\n", " def end(self):\n", " val = self.current_page * self.per_items\n", " return val\n", "\n", "# ############### 调用 ###############\n", "\n", "p = Pager(1)\n", "p.start # 就是起始值,即:m\n", "p.end # 就是结束值,即:n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "> 从上述可见,Python的属性的功能是:属性内部进行一系列的逻辑计算,最终将计算结果返回。(比字段灵活)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "**属性的两种定义方式**\n", "\n", "属性的定义有两种方式:\n", "\n", "- 装饰器 即:在方法上应用装饰器\n", "- 静态字段 即:在类中定义值为property对象的静态字段" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "**装饰器方式:**在类的普通方法上应用 **@property** 装饰器:" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "11\n", "11\n", "13\n", "del all_pager\n" ] } ], "source": [ "class Pager:\n", "\n", " def __init__(self, all_count):\n", " self.all_count = all_count\n", "\n", " @property\n", " def all_pager(self):\n", " a1, a2 = divmod(self.all_count, 10)\n", " if a2 == 0:\n", " return a1\n", " else:\n", " return a1 + 1\n", "\n", " @all_pager.setter\n", " def all_pager(self, value):\n", " self.all_count = value\n", "\n", " \n", " @all_pager.deleter\n", " def all_pager(self):\n", " del self.all_count\n", " print('del all_pager')\n", "\n", "\n", "\n", "p = Pager(101)\n", "ret = p.all_pager # 仿字段一样操作,获取值\n", "print(ret)\n", "\n", "print(p.all_pager)\n", "p.all_pager = 121 # 仿字段一样操作,设置值\n", "print(p.all_pager)\n", "\n", "del p.all_pager # 仿字段一样操作,删除值" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "**静态字段方式**: 创建值为property对象的静态字段" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Kevin\n" ] } ], "source": [ "class Foo:\n", "\n", " def get_bar(self):\n", " return 'Kevin'\n", "\n", " BAR = property(get_bar)\n", "\n", "obj = Foo()\n", "reuslt = obj.BAR # 自动调用get_bar方法,并获取方法的返回值\n", "print(reuslt)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "property的构造方法中有个四个参数\n", "\n", "- 第一个参数是方法名,调用 对象.属性 时自动触发执行方法\n", "- 第二个参数是方法名,调用 对象.属性 = XXX 时自动触发执行方法\n", "- 第三个参数是方法名,调用 del 对象.属性 时自动触发执行方法\n", "- 第四个参数是字符串,调用 对象.属性.__doc__ ,此参数是该属性的描述信息" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Help on class property in module builtins:\n", "\n", "class property(object)\n", " | property(fget=None, fset=None, fdel=None, doc=None) -> property attribute\n", " | \n", " | fget is a function to be used for getting an attribute value, and likewise\n", " | fset is a function for setting, and fdel a function for del'ing, an\n", " | attribute. Typical use is to define a managed attribute x:\n", " | \n", " | class C(object):\n", " | def getx(self): return self._x\n", " | def setx(self, value): self._x = value\n", " | def delx(self): del self._x\n", " | x = property(getx, setx, delx, \"I'm the 'x' property.\")\n", " | \n", " | Decorators make defining new properties or modifying existing ones easy:\n", " | \n", " | class C(object):\n", " | @property\n", " | def x(self):\n", " | \"I am the 'x' property.\"\n", " | return self._x\n", " | @x.setter\n", " | def x(self, value):\n", " | self._x = value\n", " | @x.deleter\n", " | def x(self):\n", " | del self._x\n", " | \n", " | Methods defined here:\n", " | \n", " | __delete__(self, instance, /)\n", " | Delete an attribute of instance.\n", " | \n", " | __get__(self, instance, owner, /)\n", " | Return an attribute of instance, which is of type owner.\n", " | \n", " | __getattribute__(self, name, /)\n", " | Return getattr(self, name).\n", " | \n", " | __init__(self, /, *args, **kwargs)\n", " | Initialize self. See help(type(self)) for accurate signature.\n", " | \n", " | __new__(*args, **kwargs) from builtins.type\n", " | Create and return a new object. See help(type) for accurate signature.\n", " | \n", " | __set__(self, instance, value, /)\n", " | Set an attribute of instance to value.\n", " | \n", " | deleter(...)\n", " | Descriptor to change the deleter on a property.\n", " | \n", " | getter(...)\n", " | Descriptor to change the getter on a property.\n", " | \n", " | setter(...)\n", " | Descriptor to change the setter on a property.\n", " | \n", " | ----------------------------------------------------------------------\n", " | Data descriptors defined here:\n", " | \n", " | __isabstractmethod__\n", " | \n", " | fdel\n", " | \n", " | fget\n", " | \n", " | fset\n", "\n" ] } ], "source": [ "help(property)" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "class Foo:\n", "\n", " def __init__(self):\n", " self.value = None\n", " \n", " def get_bar(self):\n", " return self.value\n", "\n", " def set_bar(self, value):\n", " self.value = value\n", "\n", " def del_bar(self):\n", " del self.value\n", " \n", " # property(fget=None, fset=None, fdel=None, doc=None)\n", " BAR = property(get_bar, set_bar, del_bar, 'description...')\n", "\n", "obj = Foo()\n", "\n", "obj.BAR # 自动调用第一个参数中定义的方法:get_bar\n", "obj.BAR = \"liang\" # 自动调用第二个参数中定义的方法:set_bar方法,并将“liang”当作参数传入\n", "del obj.BAR # 自动调用第三个参数中定义的方法:del_bar方法" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "由于静态字段方式创建属性具有三种访问方式,我们可以根据他们几个属性的访问特点,分别将三个方法定义为对同一个属性:**获取、修改、删除**" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "160.0" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "class Goods(object):\n", "\n", " def __init__(self):\n", " # 原价\n", " self.original_price = 100\n", " # 折扣\n", " self.discount = 0.8\n", "\n", " def get_price(self):\n", " # 实际价格 = 原价 * 折扣\n", " new_price = self.original_price * self.discount\n", " return new_price\n", "\n", " def set_price(self, value):\n", " self.original_price = value\n", "\n", " def del_price(self):\n", " del self.original_price\n", "\n", " PRICE = property(get_price, set_price, del_price, '价格属性描述...')\n", "\n", "obj = Goods()\n", "obj.PRICE = 200 # 修改商品原价\n", "obj.PRICE # 获取商品价格\n", "del obj.PRICE # 删除商品原价" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## 类特殊成员\n", "\n", "上文介绍了Python的类成员以及成员修饰符,从而了解到类中有字段、方法和属性三大类成员,并且成员名前如果有两个下划线,则表示该成员是私有成员,私有成员只能由类内部调用。无论人或事物往往都有不按套路出牌的情况,Python的类成员也是如此,存在着一些具有特殊含义的成员,详情如下:" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "1、 \\__doc__\n", "\n", "表示类的描述信息" ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " 描述类信息,这是用于看片的神器\n" ] } ], "source": [ "class Foo:\n", " \"\"\" 描述类信息,这是用于看片的神器\"\"\"\n", "\n", " def func(self):\n", " pass\n", "\n", "print(Foo.__doc__)\n", "#输出:类的描述信息" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "2、 \\__module\\__ 和 \\__class__ \n", "\n", "- \\__module__ 表示当前操作的对象在哪个模块\n", "- \\__class__ 表示当前操作的对象的类是什么" ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "__main__\n", "\n" ] } ], "source": [ "class C:\n", "\n", " def __init__(self):\n", " self.name = 'Kevin'\n", " \n", "obj = C()\n", "print(obj.__module__) # 输出 lib.aa,即:输出模块\n", "print(obj.__class__) # 输出 lib.aa.C,即:输出类" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "3、 \\__init__\n", "\n", "- 构造方法,通过类创建对象时,自动触发执行。" ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Kevin 18\n" ] } ], "source": [ "class Foo:\n", "\n", " def __init__(self, name, age):\n", " self.name = name\n", " self.age = age\n", "\n", "\n", "obj = Foo('Kevin', 18) # 自动执行类中的 __init__ 方法\n", "print(obj.name, obj.age)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "4、 \\__del__\n", "\n", " 析构方法,当对象在内存中被释放时,自动触发执行。\n", "\n", "注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。" ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "class Foo:\n", "\n", " def __del__(self):\n", " pass" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "5、 \\__call__\n", "\n", "  对象后面加括号,触发执行。\n", "\n", "注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()" ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "__call__\n" ] } ], "source": [ "class Foo:\n", "\n", " def __init__(self):\n", " pass\n", " \n", " def __call__(self, *args, **kwargs):\n", "\n", " print('__call__')\n", "\n", "\n", "obj = Foo() # 执行 __init__\n", "obj() # 执行 __call__" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "6、 \\__dict__\n", "\n", "  类或对象中的所有成员\n", "\n", "上文中我们知道:类的普通字段属于对象;类中的静态字段和方法等属于类,即:" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "![类字段](class_field.png)" ] }, { "cell_type": "code", "execution_count": 14, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "{'__module__': '__main__', 'country': 'China', '__init__': , 'func': , '__dict__': , '__weakref__': , '__doc__': None}\n", "{'name': 'HeBei', 'count': 10000}\n", "{'name': 'HeNan', 'count': 3888}\n" ] } ], "source": [ "class Province:\n", "\n", " country = 'China'\n", "\n", " def __init__(self, name, count):\n", " self.name = name\n", " self.count = count\n", "\n", " def func(self, *args, **kwargs):\n", " print('func')\n", "\n", "# 获取类的成员,即:静态字段、方法、\n", "print(Province.__dict__)\n", "# 输出:{'country': 'China', '__module__': '__main__', 'func': , '__init__': , '__doc__': None}\n", "\n", "obj1 = Province('HeBei',10000)\n", "print(obj1.__dict__)\n", "# 获取 对象obj1 的成员\n", "# 输出:{'count': 10000, 'name': 'HeBei'}\n", "\n", "obj2 = Province('HeNan', 3888)\n", "print(obj2.__dict__)\n", "# 获取 对象obj1 的成员\n", "# 输出:{'count': 3888, 'name': 'HeNan'}" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "7、 \\__str__\n", "\n", "  如果一个类中定义了__str__方法,那么在打印 对象 时,默认输出该方法的返回值。" ] }, { "cell_type": "code", "execution_count": 15, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "There are some describings...\n" ] } ], "source": [ "class Foo:\n", "\n", " def __str__(self):\n", " return 'There are some describings...'\n", "\n", "\n", "obj = Foo()\n", "print(obj)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "8、\\__getitem\\__、\\__setitem\\__、\\__delitem__\n", "\n", "用于索引操作,如字典。以上分别表示获取、设置、删除数据" ] }, { "cell_type": "code", "execution_count": 16, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "__getitem__ k1\n", "__setitem__ k2 Kevin\n", "__delitem__ k1\n" ] } ], "source": [ "class Foo(object):\n", " \n", " def __getitem__(self, key):\n", " print('__getitem__',key)\n", " \n", " def __setitem__(self, key, value):\n", " print('__setitem__',key,value)\n", " \n", " def __delitem__(self, key):\n", " print('__delitem__',key)\n", " \n", " \n", "obj = Foo()\n", " \n", "result = obj['k1'] # 自动触发执行 __getitem__\n", "obj['k2'] = 'Kevin' # 自动触发执行 __setitem__\n", "del obj['k1'] # 自动触发执行 __delitem__" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "是不是感觉自己可以写一个字典的类了,接下来我们手动写一个有序得字典:" ] }, { "cell_type": "code", "execution_count": 17, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "{'k2':456}\n" ] } ], "source": [ "class MyDict(dict): # 继承dict类\n", "\n", " def __init__(self):\n", " self.li = [] # 设置一个有序list\n", " super(MyDict, self).__init__() # 调用基础类的构造(__init__)方法\n", "\n", " def __setitem__(self, key, value):\n", " self.li.append(key) # 每次创建key,value, 将key 加入到有序list\n", " super(MyDict, self).__setitem__(key,value)\n", " \n", " def __delitem__(self, key):\n", " del self.li[self.li.index(key)]\n", " super(MyDict, self).__delitem__(key)\n", "\n", " def __str__(self):\n", " dict_list = []\n", "\n", " for key in self.li:\n", " value = self.get(key)\n", " dict_list.append(\"'%s':%s\" % (key,value))\n", " dict_str = \"{\" + \",\".join(dict_list) + \"}\"\n", " return dict_str\n", "\n", "obj = MyDict()\n", "obj['k1'] = 123\n", "obj['k2'] = 456\n", "del obj['k1']\n", "print(obj)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "9、 \\__iter__ \n", "\n", "用于迭代器,之所以列表、字典、元组可以进行for循环,是因为类型内部定义了 \\__iter__ " ] }, { "cell_type": "code", "execution_count": 18, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "11\n", "22\n", "33\n", "44\n" ] } ], "source": [ "class Foo(object):\n", "\n", " def __init__(self, sq):\n", " self.sq = sq\n", "\n", " def __iter__(self):\n", " return iter(self.sq)\n", "\n", "obj = Foo([11, 22, 33, 44])\n", "\n", "for i in obj:\n", " print(i)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "以上步骤可以看出,for循环迭代的其实是 iter([11,22,33,44]) ,所以执行流程可以变更为:\n", "\n", "for 内部其实做的是:" ] }, { "cell_type": "code", "execution_count": 19, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "11\n", "22\n", "33\n", "44\n" ] }, { "ename": "StopIteration", "evalue": "", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mStopIteration\u001b[0m Traceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0;32mwhile\u001b[0m \u001b[0;32mTrue\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 4\u001b[0;31m \u001b[0mval\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mobj\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__next__\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 5\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mval\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;31mStopIteration\u001b[0m: " ] } ], "source": [ "obj = iter([11,22,33,44])\n", "\n", "while True:\n", " val = obj.__next__()\n", " print(val)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "10、 \\__new\\__ 和 \\__metaclass__\n", "\n", "阅读以下代码:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "class Foo(object):\n", " \n", " def __init__(self):\n", " pass\n", " \n", "obj = Foo() # obj是通过Foo类实例化的对象" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "上述代码中,obj 是通过 Foo 类实例化的对象,其实,不仅 obj 是一个对象,Foo类本身也是一个对象,因为在Python中一切事物都是对象。\n", "\n", "如果按照一切事物都是对象的理论:obj对象是通过执行Foo类的构造方法创建,那么Foo类对象应该也是通过执行某个类的 构造方法 创建。" ] }, { "cell_type": "code", "execution_count": 20, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "\n" ] } ], "source": [ "print(obj.__class__) # 输出: 表示,obj 对象由Foo类创建\n", "print(Foo.__class__) # 输出: 表示,Foo类对象由 type 类创建" ] }, { "cell_type": "code", "execution_count": 21, "metadata": { "scrolled": true, "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "data": { "text/plain": [ "int" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" }, { "data": { "text/plain": [ "str" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" }, { "data": { "text/plain": [ "function" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" }, { "data": { "text/plain": [ "__main__.Bar" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ "age = 35\n", "age.__class__\n", "\n", "name = 'Kevin'\n", "name.__class__\n", "\n", "def foo(): pass\n", "foo.__class__\n", "\n", "class Bar(object): pass\n", "b = Bar()\n", "b.__class__" ] }, { "cell_type": "code", "execution_count": 22, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "data": { "text/plain": [ "type" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" }, { "data": { "text/plain": [ "type" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" }, { "data": { "text/plain": [ "type" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" }, { "data": { "text/plain": [ "type" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "age.__class__.__class__\n", "name.__class__.__class__\n", "foo.__class__.__class__\n", "b.__class__.__class__" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "所以,obj对象是Foo类的一个实例,Foo类对象是 type 类的一个实例,即:Foo类对象 是通过type类的构造方法创建。\n", "\n", "那么,创建类就可以有两种方式:" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "**a). 普通方式**" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "class Foo(object):\n", " \n", " def func(self):\n", " print('hello Kevin')" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "**b).特殊方式(type类的构造函数)**" ] }, { "cell_type": "code", "execution_count": 23, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "hello Kevin\n" ] } ], "source": [ "def func(self):\n", " print('hello Kevin')\n", " \n", "Foo = type('Foo',(object,), {'func': func})\n", "obj = Foo()\n", "obj.func()\n", " \n", "#type第一个参数:类名\n", "#type第二个参数:当前类的基类\n", "#type第三个参数:类的成员" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "** 类 是由 type 类实例化产生 **\n", "\n", "那么问题来了,类默认是由 type 类实例化产生,type类中如何实现的创建类?类又是如何创建对象?\n", "\n", "答:type 是一个元类,所有的类都是由这个元类来实例的,关于元类更多这里不涉及,感兴趣的可自行查找了解。" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## 扩展" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "** 1、 isinstance **\n", "\n", "检查对象是否是某个类实例出来的" ] }, { "cell_type": "code", "execution_count": 24, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 24, "metadata": {}, "output_type": "execute_result" } ], "source": [ "class Foo(object):\n", " pass\n", " \n", "obj = Foo()\n", " \n", "isinstance(obj, Foo)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "** 2、 issubclass **\n", "\n", "检查某个类是不是这个另外一个类的子类" ] }, { "cell_type": "code", "execution_count": 25, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ "class Foo(object):\n", " pass\n", " \n", "class Bar(Foo):\n", " pass\n", " \n", "# 检查Bar类是否是 Foo 类的派生类\n", "issubclass(Bar, Foo)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## 异常处理\n", "\n", "在编程过程中为了增加友好性,在程序出现bug时一般不会将错误信息显示给用户,而是现实一个提示的页面,通俗来说就是不让用户看见大黄页!!!" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "try:\n", " pass\n", "except Exception,ex:\n", " pass" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "需求:将用户输入的两个数字相加:\n", "\n", "如果用户输入的有误,则提示用户" ] }, { "cell_type": "code", "execution_count": 26, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "num1:123\n", "num2:abc\n", "出现异常,信息如下:\n", "invalid literal for int() with base 10: 'abc'\n" ] } ], "source": [ "while True:\n", " num1 = input('num1:')\n", " num2 = input('num2:')\n", " try:\n", " num1 = int(num1)\n", " num2 = int(num2)\n", " result = num1 + num2\n", " except Exception as e:\n", " print('出现异常,信息如下:')\n", " print(e)\n", " break" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "python中的异常种类非常多,每个异常专门用于处理某一项异常!!!\n", "\n", "### 常用异常:\n", "\n", "- AttributeError 试图访问一个对象没有的树形,比如foo.x,但是foo没有属性x\n", "- IOError 输入/输出异常;基本上是无法打开文件\n", "- ImportError 无法引入模块或包;基本上是路径问题或名称错误\n", "- IndentationError 语法错误(的子类) ;代码没有正确对齐\n", "- IndexError 下标索引超出序列边界,比如当x只有三个元素,却试图访问x[5]\n", "- KeyError 试图访问字典里不存在的键\n", "- KeyboardInterrupt Ctrl+C被按下\n", "- NameError 使用一个还未被赋予对象的变量\n", "- SyntaxError Python代码非法,代码不能编译(个人认为这是语法错误,写错了)\n", "- TypeError 传入对象类型与要求的不符合\n", "- UnboundLocalError 试图访问一个还未被设置的局部变量,基本上是由于另有一个同名的全局变量,导致你以为正在访问它\n", "- ValueError 传入一个调用者不期望的值,即使值的类型是正确的" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "### 其他异常:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "ArithmeticError\n", "AssertionError\n", "AttributeError\n", "BaseException\n", "BufferError\n", "BytesWarning\n", "DeprecationWarning\n", "EnvironmentError\n", "EOFError\n", "Exception\n", "FloatingPointError\n", "FutureWarning\n", "GeneratorExit\n", "ImportError\n", "ImportWarning\n", "IndentationError\n", "IndexError\n", "IOError\n", "KeyboardInterrupt\n", "KeyError\n", "LookupError\n", "MemoryError\n", "NameError\n", "NotImplementedError\n", "OSError\n", "OverflowError\n", "PendingDeprecationWarning\n", "ReferenceError\n", "RuntimeError\n", "RuntimeWarning\n", "StandardError\n", "StopIteration\n", "SyntaxError\n", "SyntaxWarning\n", "SystemError\n", "SystemExit\n", "TabError\n", "TypeError\n", "UnboundLocalError\n", "UnicodeDecodeError\n", "UnicodeEncodeError\n", "UnicodeError\n", "UnicodeTranslateError\n", "UnicodeWarning\n", "UserWarning\n", "ValueError\n", "Warning\n", "ZeroDivisionError" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "对于上述实例,异常类只能用来处理指定的异常情况,如果非指定异常则无法处理。" ] }, { "cell_type": "code", "execution_count": 27, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "ename": "ValueError", "evalue": "invalid literal for int() with base 10: 'hello'", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0ms1\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m'hello'\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 4\u001b[0;31m \u001b[0mint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0ms1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 5\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0mIndexError\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0me\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 6\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0me\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;31mValueError\u001b[0m: invalid literal for int() with base 10: 'hello'" ] } ], "source": [ "# 未捕获到异常,程序直接报错\n", "s1 = 'hello'\n", "try:\n", " int(s1)\n", "except IndexError as e:\n", " print(e)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "所以,写程序时需要考虑到try代码块中可能出现的任意异常,可以这样写:" ] }, { "cell_type": "code", "execution_count": 28, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "invalid literal for int() with base 10: 'hello'\n" ] } ], "source": [ "s1 = 'hello'\n", "try:\n", " int(s1)\n", "except IndexError as e:\n", " print(e)\n", "except KeyError as e:\n", " print(e)\n", "except ValueError as e:\n", " print(e)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "万能异常 在python的异常中,有一个万能异常:Exception,他可以捕获任意异常,即:" ] }, { "cell_type": "code", "execution_count": 29, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "invalid literal for int() with base 10: 'hello'\n" ] } ], "source": [ "s1 = 'hello'\n", "try:\n", " int(s1)\n", "except Exception as e:\n", " print(e)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "接下来你可能要问了,既然有这个万能异常,其他异常是不是就可以忽略了!\n", "\n", "答:当然不是,对于特殊处理或提醒的异常需要先定义,最后定义Exception来确保程序正常运行。" ] }, { "cell_type": "code", "execution_count": 30, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "错误\n" ] } ], "source": [ "s1 = 'hello'\n", "try:\n", " int(s1)\n", "except KeyError as e:\n", " print('键错误')\n", "except IndexError as e:\n", " print('索引错误')\n", "except Exception as e:\n", " print('错误')" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "### 异常处理结构:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "try:\n", " # 主代码块\n", " pass\n", "except KeyError as e:\n", " # 异常时,执行该块\n", " pass\n", "else:\n", " # 主代码块执行完,执行该块\n", " pass\n", "finally:\n", " # 无论异常与否,最终执行该块\n", " pass" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "### 主动触发异常:" ] }, { "cell_type": "code", "execution_count": 31, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "错误了。。。\n" ] } ], "source": [ "try:\n", " raise Exception('错误了。。。')\n", "except Exception as e:\n", " print(e)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "### 自定义异常:" ] }, { "cell_type": "code", "execution_count": 32, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "我的异常\n" ] } ], "source": [ "class MyException(Exception):\n", " \n", " def __init__(self, msg):\n", " self.message = msg\n", " \n", " def __str__(self):\n", " return self.message\n", " \n", "try:\n", " raise MyException('我的异常')\n", "except MyException as error:\n", " print(error)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "### 断言:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "assert 1 == 1 #如果条件满足就不报错,如果条件不满足就会报错\n", "\n", "assert 1 == 2 " ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## 反射\n", "\n", "python中的反射功能是由以下四个内置函数提供:** hasattr、getattr、setattr、delattr,** 这四个函数分别用于对对象内部执行:\n", "- 检查是否含有某成员\n", "- 获取成员\n", "- 设置成员\n", "- 删除成员。" ] }, { "cell_type": "code", "execution_count": 33, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 33, "metadata": {}, "output_type": "execute_result" }, { "data": { "text/plain": [ "True" ] }, "execution_count": 33, "metadata": {}, "output_type": "execute_result" }, { "data": { "text/plain": [ "'Kevin'" ] }, "execution_count": 33, "metadata": {}, "output_type": "execute_result" }, { "data": { "text/plain": [ ">" ] }, "execution_count": 33, "metadata": {}, "output_type": "execute_result" } ], "source": [ "class Foo(object):\n", " \n", " def __init__(self):\n", " self.name = 'Kevin'\n", " \n", " def func(self):\n", " return 'func'\n", " \n", "obj = Foo()\n", " \n", "# #### 检查是否含有成员 ####\n", "hasattr(obj, 'name')\n", "hasattr(obj, 'func')\n", " \n", "# #### 获取成员 ####\n", "getattr(obj, 'name')\n", "getattr(obj, 'func')\n", " \n", "# #### 设置成员 ####\n", "setattr(obj, 'age', 18)\n", "setattr(obj, 'show', lambda num: num + 1)\n", " \n", "# #### 删除成员 ####\n", "delattr(obj, 'name')" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## 设计模式\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "### 单例\n", "\n", "单例,顾名思义单个实例。" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "学习单例之前,首先来回顾下面向对象的内容:\n", "\n", "python的面向对象由两个非常重要的两个“东西”组成:类、实例(对象)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "如:创建对数据库操作的公共类\n", "\n", "- 增\n", "- 删\n", "- 改\n", "- 查" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "class Database(object):\n", "\n", " def __init__(self):\n", " self.hostname = '127.0.0.1'\n", " self.port = 3306\n", " self.password = 'pwd'\n", " self.username = 'root'\n", "\n", " def fetch(self):\n", " # 连接数据库\n", " # 拼接sql语句\n", " # 操作\n", " pass\n", "\n", " def create(self):\n", " # 连接数据库\n", " # 拼接sql语句\n", " # 操作\n", " pass\n", "\n", " def remove(self):\n", " # 连接数据库\n", " # 拼接sql语句\n", " # 操作\n", " pass\n", "\n", " def modify(self):\n", " # 连接数据库\n", " # 拼接sql语句\n", " # 操作\n", " pass\n", "\n", "\n", "db = Database() # 实例一个对象\n", "db.create() # 对象调用方法" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "############ 单例类定义 ###########\n", "class Database(object):\n", "\n", " __instance = None\n", "\n", " def __init__(self):\n", " self.hostname = '127.0.0.1'\n", " self.port = 3306\n", " self.password = 'pwd'\n", " self.username = 'root'\n", "\n", " def fetch(self):\n", " # 连接数据库\n", " # 拼接sql语句\n", " # 操作\n", " pass\n", "\n", " def create(self):\n", " # 连接数据库\n", " # 拼接sql语句\n", " # 操作\n", " pass\n", "\n", " def remove(self):\n", " # 连接数据库\n", " # 拼接sql语句\n", " # 操作\n", " pass\n", "\n", " def modify(self):\n", " # 连接数据库\n", " # 拼接sql语句\n", " # 操作\n", " pass\n", "\n", "\n", "import tornado.ioloop\n", "import tornado.web\n", "\n", "\n", "class MainHandler(tornado.web.RequestHandler):\n", " def get(self):\n", " obj = Database()\n", " print(id(obj))\n", " obj.create()\n", " self.write(\"Hello, world\")\n", "\n", "\n", "application = tornado.web.Application([\n", " (r\"/index\", MainHandler),\n", "])\n", "\n", "if __name__ == \"__main__\":\n", " application.listen(8000)\n", " tornado.ioloop.IOLoop.instance().start()" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "对于上述实例,每个请求到来,都需要在内存里创建一个实例,再通过该实例执行指定的方法。\n", "\n", "那么问题来了...如果并发量大的话,内存里就会存在非常多功能上一模一样的对象。存在这些对象肯定会消耗内存,对于这些功能相同的对象可以在内存中仅创建一个,需要时都去调用,也是极好的!!!这时单例模式出马,单例模式用来保证内存中仅存在一个实例!!!" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "通过面向对象的特性,构造出单例模式:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "############# 单例类定义 ###########\n", "class Foo(object):\n", " \n", " __instance = None\n", " \n", " @staticmethod\n", " def singleton():\n", " if Foo.__instance:\n", " return Foo.__instance\n", " else:\n", " Foo.__instance = Foo() # 实例化自己\n", " return Foo.__instance\n", "\n", "############ 获取实例 ###########\n", "obj = Foo.singleton()" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "对于Python单例模式,创建对象时不能再直接使用:obj = Foo(),而应该调用特殊的方法:**obj = Foo.singleton() 。**\n", "\n", "类实例化一个对象,然后对象调用其方法,但是这样就会用很多对象了,在上面我们知道静态方法是由类调用的,不需要实例化对象。上面写了一个静态方法,实例化自己,然后再给调用者,这样来来回回调用者们只不过是反复再调用类的一个静态方法。而这个方法只实例化了一个对象。这样达到单例的效果。" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "############ 单例类定义 ###########\n", "class Database(object):\n", "\n", " __instance = None\n", "\n", " def __init__(self):\n", " self.hostname = '127.0.0.1'\n", " self.port = 3306\n", " self.password = 'pwd'\n", " self.username = 'root'\n", "\n", " @staticmethod\n", " def singleton():\n", " if Database.__instance:\n", " return Database.__instance\n", " else:\n", " Database.__instance = Database()\n", " return Database.__instance\n", "\n", " def fetch(self):\n", " # 连接数据库\n", " # 拼接sql语句\n", " # 操作\n", " pass\n", "\n", " def create(self):\n", " # 连接数据库\n", " # 拼接sql语句\n", " # 操作\n", " pass\n", "\n", " def remove(self):\n", " # 连接数据库\n", " # 拼接sql语句\n", " # 操作\n", " pass\n", "\n", " def modify(self):\n", " # 连接数据库\n", " # 拼接sql语句\n", " # 操作\n", " pass\n", "\n", "\n", "import tornado.ioloop\n", "import tornado.web\n", "\n", "\n", "class MainHandler(tornado.web.RequestHandler):\n", " def get(self):\n", " obj = Database.singleton()\n", " print(id(obj))\n", " obj.create()\n", " self.write(\"Hello, world\")\n", "\n", "\n", "application = tornado.web.Application([\n", " (r\"/index\", MainHandler),\n", "])\n", "\n", "if __name__ == \"__main__\":\n", " application.listen(8000)\n", " tornado.ioloop.IOLoop.instance().start()" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "总结:单例模式存在的目的是保证当前内存中仅存在单个实例,避免内存浪费!!" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.6.4" }, "toc": { "colors": { "hover_highlight": "#DAA520", "navigate_num": "#000000", "navigate_text": "#333333", "running_highlight": "#FF0000", "selected_highlight": "#FFD700", "sidebar_border": "#EEEEEE", "wrapper_background": "#FFFFFF" }, "moveMenuLeft": true, "nav_menu": { "height": "102px", "width": "252px" }, "navigate_menu": true, "number_sections": false, "sideBar": true, "threshold": 4, "toc_cell": true, "toc_section_display": "block", "toc_window_display": false, "widenNotebook": false } }, "nbformat": 4, "nbformat_minor": 2 }