{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# python 中的类:\n", "什么是类?\n", "面向对象的设计思想是从自然界中来的,因为在自然界中,类(Class)和实例(Instance)的概念是很自然的。Class是一种抽象概念,比如我们定义的Class——Student,是指学生这个概念,而实例(Instance)则是一个个具体的Student,比如,Bart Simpson和Lisa Simpson是两个具体的Student。\n", "面向对象的抽象程度又比函数要高,因为一个Class既包含数据,又包含操作数据的方法。\n", "数据封装、继承和多态是面向对象的三大特点,我们后面会详细讲解。\n", "\n", "## 类和实例\n", "类(Class)和实例(Instance)是面向对象最重要的概念。\n", "\n", "类是指抽象出的模板。实例则是根据类创建出来的具体的“对象”,每个对象都拥有从类中继承的相同的方法,但各自的数据可能不同。\n", "\n", "在python中定义一个类:\n", "\n", "```python\n", "class Student(object):\n", " pass\n", "```\n", "关键字class后面跟着类名,类名通常是大写字母开头的单词,紧接着是(object),表示该类是从哪个类继承下来的。通常,如果没有合适的继承类,就使用object类,这是所有类最终都会继承下来的类。\n", "当我们定义好了 class ,就可以根据Student类创建实例:" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "class Person():\n", " name=None\n", " ID=None\n", " \"\"\" 描述类信息,可被自动收集 \"\"\"\n", " def __init__(self,name=None,ID=None):\n", " self.name=name\n", " self.ID=ID\n", " def __repr__(self):\n", " return \"my name is {name}, my ID is {ID}\".format(name=self.name,ID=self.ID)\n", " def set_name(self,name):\n", " self.name=name\n", " print(\"updata name\")\n", " return True\n", " def set_ID(self,ID):\n", " self.ID=ID\n", " print(\"updata ID\")\n", " return True" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [], "source": [ "class Student(Person):\n", " school=None\n", " \"\"\"学生应该有学校\"\"\"\n", " def __init__(self,name=None,ID=None,school=None):\n", " super(Student, self).__init__(name,ID)\n", " self.school=school\n", " def __repr__(self):\n", " return \"\"\"\n", "my name is {name},\n", "my ID is {ID},\n", "my school is {school}\n", " \"\"\".format(name=self.name,ID=self.ID,school=self.school)" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [], "source": [ "marcus=Student(\"Marcus\",17150011001,\"OUC\")" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "my name is Marcus,\n", "my ID is 17150011001,\n", "my school is OUC\n", " \n", "None\n" ] } ], "source": [ "print(marcus)\n", "print(marcus.__doc__)" ] }, { "cell_type": "raw", "metadata": {}, "source": [ "__init__ : 构造函数,在生成对象时调用\n", "__del__ : 析构函数,释放对象时使用\n", "__repr__ : 打印,转换\n", "__setitem__ : 按照索引赋值\n", "__getitem__: 按照索引获取值\n", "__len__: 获得长度\n", "__cmp__: 比较运算\n", "__call__: 调用\n", "__add__: 加运算\n", "__sub__: 减运算\n", "__mul__: 乘运算\n", "__div__: 除运算\n", "__mod__: 求余运算\n", "__pow__: 幂\n", "\n", "类的私有属性:\n", "\n", "可以在类内定义类的私有属性和方法,私有的表明只属于类内部的,在类外部是不可以直接访问的,python定义私有属性和私有方法的方法是在名称前加上两个下划线 “__”。\n", "\n", "私有方法\n", "\n", "\n", "\n", "```python\n", "class MyClass(object):\n", " def __init__(self,data1,data2):\n", " self.__data1=data1\n", " self.data2=data2 \n", " \n", " def __func1(self):\n", " print(\"MyClass类的私有方法被调用!\")\n", " \n", " def print_data(self):\n", " self.__func1()\n", " print(self.__data1)\n", " print(self.data2)\n", " \n", "class1=MyClass(66,88)\n", "class1.print_data()\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "属性的__dict__系统.\n", "对象的属性可能来自于其类定义,叫做类属性(class attribute)。\n", "类属性可能来自类定义自身,也可能根据类定义继承来的。\n", "一个对象的属性还可能是该对象实例定义的,叫做对象属性(object attribute)。\n", "\n", "对象的属性储存在对象的__dict__属性中。__dict__为一个词典,键为属性名,对应的值为属性本身。\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "DSP中的例子\n", " 用一个很常见的例子来展现实施一个使用者定义的类是建立一个 Fraction 类来实施抽象数据类型。我们已经知道 Python 提供很多数字的类供我们使用。有时候,然而,可能创建一个“类似”fraction 的数据类型会更有可观性。\n", " \n", " 一个 fraction 如 3 / 5 包括两部分。上面的数字,称为分子,可以是任何整数。下面的数字,称为分母,可以是任何大于 0 的整数(负的 fraction 有负的分子)。虽说我们可以创建一个浮点数近似任何 fraction,但在有的情况下我们还是想用分数表示一个确切的值。\n", " \n", " 对 Fration 运算符应使对 Fraction 数据对象的运算操作像任何其他的数值一样,我们需要能加,减,乘和除。我们也希望能够显示 fraction 使用标准的“分数”的形式,例如 3 / 5。\n", " \n", " 此外,所有 fraction 的运算应该以最简的形式返回结果,这样不管怎样进行计算,我们最后总是以最常见\n", "的形式得出结果。" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "<__main__.Fraction object at 0x105efb208>\n" ] } ], "source": [ "class Fraction:\n", " def __init__(self,top,bottom):\n", " self.num = top\n", " self.den = bottom\n", "myf= Fraction(3,5)\n", "print(myf)" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from IPython.display import Image\n", "Image(url='https://tva1.sinaimg.cn/large/006y8mN6ly1g98d7edw7vj30yw0i2gny.jpg')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "fraction 对象,myf,不知道如何回应这一打印要求。打印功能要求对象转换成字符串以至于该\n", "字符串可以输入输出。myf 唯一的选择是显示该变量中存储的实际引用(本身的地址)。这不是我们\n", "想要的。" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "3 / 5\n" ] } ], "source": [ "class Fraction:\n", " def __init__(self,top,bottom):\n", " self.num = top\n", " self.den = bottom\n", " def show(self):\n", " print(self.num,\"/\",self.den)\n", "myf= Fraction(3,5)\n", "myf.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "实际上我们可以重定义 __repr__() 或__str__()" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "3\n", "-\n", "5\n" ] } ], "source": [ "class Fraction:\n", " def __init__(self,top,bottom):\n", " self.num = top\n", " self.den = bottom\n", " def __repr__(self):\n", " return \"{num}\\n-\\n{den}\".format(num=self.num,den=self.den)\n", "myf= Fraction(3,5)\n", "print(myf)" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "3/5\n" ] } ], "source": [ "class Fraction:\n", " def __init__(self,top,bottom):\n", " self.num = top\n", " self.den = bottom\n", " def __str__(self):\n", " return str(self.num)+\"/\"+str(self.den)\n", "myf = Fraction(3,5)\n", "print(myf)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "我们可以为我们的新 Fraction 类装载许多其他的方法。一些最重要的是基本的算术运算。我们希望能够创建两个分数对象然后他们加在一起使用标准的“+”符号。在这一点上,如果我们试图直\n", "接相加两个分数,则会得到如下:\n" ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "6 / 8\n" ] } ], "source": [ "class Fraction:\n", " def __init__(self,top,bottom):\n", " self.num = top\n", " self.den = bottom\n", " def __repr__(self):\n", " return \"{num} / {den}\".format(num=self.num,den=self.den)\n", " def __add__(self,otherfraction):\n", " newnum = self.num*otherfraction.den + self.den*otherfraction.num\n", " newden = self.den * otherfraction.den\n", " return Fraction(newnum,newden)\n", "f1=Fraction(1,4)\n", "f2=Fraction(1,2)\n", "f3=f1+f2\n", "print(f3)" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "{'__module__': '__main__', '__init__': , '__repr__': , '__add__': , '__dict__': , '__weakref__': , '__doc__': None}\n" ] } ], "source": [ "print(Fraction.__dict__)" ] }, { "cell_type": "code", "execution_count": 42, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "False\n" ] }, { "data": { "text/plain": [ "1 / 8" ] }, "execution_count": 42, "metadata": {}, "output_type": "execute_result" } ], "source": [ "class Fraction:\n", " def __init__(self,top,bottom):\n", " self.num = top\n", " self.den = bottom\n", " def __repr__(self):\n", " return \"{num} / {den}\".format(num=self.num,den=self.den)\n", " def __add__(self,otherfraction):\n", " newnum = self.num*otherfraction.den + self.den*otherfraction.num\n", " newden = self.den * otherfraction.den\n", " return Fraction(newnum,newden)\n", " def __cmp__(self, s):\n", " if self.num/self.den < s.num/s.den:\n", " return -1\n", " elif self.name > s.name:\n", " return 1\n", " else:\n", " return 0\n", " def __eq__(self,other):\n", " return self.num==other.num and self.den==other.den\n", " def __gt__(self,other):\n", " if self.num/self.den>other.num/other.den:\n", " return True\n", " else:\n", " return False\n", " def __lt__(self,other):\n", " if self.num/self.den=other.num/other.den:\n", " return True\n", " else:\n", " return False\n", " def __le__(self,other):\n", " if self.num/self.den<=other.num/other.den:\n", " return True\n", " else:\n", " return False\n", " def gcd(x,y):\n", " if y==0:return x\n", " else:return gcd(y,x%y)\n", " def __add__(self,other):\n", " x=self.num*other.den+self.den*other.num\n", " y=self.den*other.den\n", " gys=gcd(x,y)\n", " return Fraction(x//gys,y//gys)\n", " def __mul__(self,other):\n", " x=self.num*other.num\n", " y=self.den*other.den\n", " gys=gcd(x,y)\n", " return Fraction(x//gys,y//gys)\n", "f1=Fraction(1,4)\n", "f2=Fraction(1,2)\n", "print(f1>=f2)\n", "f3=f1*f2\n", "f3" ] }, { "cell_type": "code", "execution_count": 43, "metadata": {}, "outputs": [], "source": [ "# LIST\n", "class LLNode(object):\n", " \"\"\"链表的结点\"\"\"\n", " def __init__(self, elem, next_=None):\n", " self.elem = elem\n", " self.next = next_\n", "\n", " def __repr__(self):\n", " return '%r' % self.elem\n", "\n", "\n", "class LinkedList(object):\n", " \"\"\"单向链表\"\"\"\n", " def __init__(self, *elems):\n", " self._head = None\n", " if len(elems) == 1:\n", " if isinstance(elems[0], Iterable):\n", " for elem in elems[0]:\n", " self.prepend(elem)\n", " else:\n", " self.prepend(elems[0])\n", " else:\n", " for elem in elems:\n", " self.prepend(elem)\n", "\n", " @property\n", " def is_empty(self):\n", " \"\"\"判断是否是空链表,返回布尔值\"\"\"\n", " return self._head is None\n", "\n", " def prepend(self, elem):\n", " \"\"\"在链表头部插入一个新元素\"\"\"\n", " elem = elem.elem if isinstance(elem, LLNode) else elem\n", " self._head = LLNode(elem, self._head)\n", "\n", " def __repr__(self):\n", " cur_node = self._head\n", " out_str = '['\n", " while cur_node:\n", " out_str += '%r' % cur_node.elem\n", " if cur_node.next:\n", " out_str += ', '\n", " cur_node = cur_node.next\n", " return out_str + ']'\n", "\n", " def __len__(self):\n", " cur_node, length = self._head, 0\n", " while cur_node:\n", " length += 1\n", " cur_node = cur_node.next\n", " return length\n", "\n", " def __getitem__(self, i):\n", " cur_node = self._head\n", "\n", " if isinstance(i, slice):\n", " if not isinstance(i.start, int) and not i.start is None:\n", " raise TypeError('slice indices must be integers or None')\n", " if not isinstance(i.stop, int) and not i.stop is None:\n", " raise TypeError('slice indices must be integers or None')\n", " if not isinstance(i.step, int) and not i.step is None:\n", " raise TypeError('slice indices must be integers or None')\n", " start = i.start or 0\n", " stop = i.stop or len(self)\n", " forward = stop - start\n", " step = i.step or 1\n", " result = LinkedListR()\n", " while start:\n", " try:\n", " cur_node = cur_node.next\n", " except AttributeError:\n", " return result\n", " start -= 1\n", " while forward:\n", " try:\n", " result.append(cur_node.elem)\n", " for i_step in range(step):\n", " cur_node = cur_node.next\n", " except AttributeError:\n", " return result\n", " forward -= step\n", " return result\n", "\n", " if not isinstance(i, int):\n", " raise TypeError('list indices must be integers')\n", " while i:\n", " try:\n", " cur_node = cur_node.next\n", " except AttributeError:\n", " raise IndexError('list index out of range')\n", " i -= 1\n", " if cur_node is None:\n", " raise IndexError('list index out of range')\n", " return cur_node.elem\n", "\n", " def insert(self, i, elem):\n", " \"\"\"插入数据到指定索引位置\"\"\"\n", " cur_node = self._head\n", " if not isinstance(i, int):\n", " raise TypeError('list indices must be integers')\n", " if not i:\n", " self.prepend(elem)\n", " return\n", " i -= 1\n", " while i:\n", " if cur_node.next:\n", " cur_node = cur_node.next\n", " else:\n", " break\n", " i -= 1\n", " new_node = LLNode(elem, cur_node.next)\n", " cur_node.next = new_node\n", "\n", "\n", "class LinkedListR(LinkedList):\n", " \"\"\"有尾部信息的单向链表\"\"\"\n", " def __init__(self, *elems):\n", " super(LinkedListR, self).__init__()\n", " self._rear = None\n", " if len(elems) == 1:\n", " if isinstance(elems[0], Iterable):\n", " for elem in elems[0]:\n", " self.append(elem)\n", " else:\n", " self.append(elems[0])\n", " else:\n", " for elem in elems:\n", " self.append(elem)\n", "\n", " def prepend(self, elem):\n", " \"\"\"在链表头部插入一个新元素\"\"\"\n", " elem = elem.elem if isinstance(elem, LLNode) else elem\n", " if self.is_empty:\n", " self._head = LLNode(elem, self._head)\n", " self._rear = self._head\n", " else:\n", " self._head = LLNode(elem, self._head)\n", "\n", " def append(self, elem):\n", " \"\"\"在链表尾部插入一个新元素\"\"\"\n", " elem = elem.elem if isinstance(elem, LLNode) else elem\n", " if self.is_empty:\n", " self._rear = LLNode(elem)\n", " self._head = self._rear\n", " else:\n", " self._rear.next = LLNode(elem)\n", " self._rear = self._rear.next\n", "\n", " def insert(self, i, elem):\n", " \"\"\"插入数据到指定索引位置\"\"\"\n", " cur_node = self._head\n", " if not isinstance(i, int):\n", " raise TypeError('list indices must be integers')\n", " if not i or not cur_node:\n", " self.prepend(elem)\n", " return\n", " i -= 1\n", " while i:\n", " if cur_node.next:\n", " cur_node = cur_node.next\n", " else:\n", " break\n", " i -= 1\n", " new_node = LLNode(elem, cur_node.next)\n", " cur_node.next = new_node\n", " if not new_node.next:\n", " self._rear = new_node\n", "\n", " def __add__(self, another):\n", " if not isinstance(another, LinkedListR):\n", " raise TypeError('can only concatenate list (not \"%r\") to list' % type(another))\n", " if self.is_empty:\n", " return another\n", " self._rear.next = another._head\n", " self._rear = another._rear\n", " return self" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "VPython", "language": "python", "name": "vpython" }, "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.8" } }, "nbformat": 4, "nbformat_minor": 2 }