Python 面向对象编程详解(8)
Python 的创始人为吉多·范罗苏姆(Guido van Rossum).1989年的圣诞节期间,吉多·范罗苏姆为了在阿姆斯特丹打发时间,决心开发一个新的脚本解释程序,作为ABC语言的一种继承.Python是纯粹的自由软件,源代码和解释器CPython遵循 GPL(GNU General Public License)协议.关于python的哲学:python崇尚:"优雅"、"明确"、"简单",Python是用最简单最优雅最明确的方法来解决问题.
面向对象的程序设计提供了一种新的思维方式,软件设计的焦点不再是程序的逻辑流程,而是软件或程序中的对象以及对象之间的关系,使用面向对象的思想进行程序设计,能够更好地设计软件架构,维护软件模块,并易于框架和组件的重用. Python 支持面向过程、面向对象、函数式编程等多种编程范式,且不强制我们使用任何一种编程范式,我们可以使用过程式编程编写任何程序,在编写小程序时,基本上不会有问题.但对于中等和大型项目来说,面向对象将给我们带来很多优势.接下来将结合面向对象的基本概念和Python语法的特性讲解面向对象的编程. 面向对象编程简介面向对象, 在面向对象的设计中,程序员可以创建任何新的类型,这些类型可以描述每个对象包含的数据和特征,类是一些对象的抽象,隐藏了对象内部复杂的结构和实现,类由变量和函数两部分构成,类中的变量称为 简单点说,"面向对象"是一种编程范式,而编程范式是按照不同的编程特点总结出来的编程方式,俗话说,条条大路通罗马,也就说我们使用不同的方法都可以达到最终的目的,但是有些办法比较快速、安全且效果好,有些方法则效率低下且效果不尽人意.同样,编程也是为了解决问题,而解决问题可以有多种不同的视角和思路,前人把其中一些普遍适用且行之有效的编程模式归结为"范式",常见的编程范式有:
说到这里,我们已经把面向对象的基本作用,特性,应用场景介绍完了,这里只是个人笔记,无法做到面面俱到,如果想要深入了解,请自行去看一些学习手册,以上内容大部分摘抄自书籍中的重点,接下来我们将围绕 面向对象—>封装封装是面向对象的主要特征之一,是对象和类概念的主要特性.简单的说,类就是封装了数据以及操作这些数据的方法的逻辑实体,它向外暴露部分数据和方法,屏蔽具体的实现细节,除此之外,在一个对象内部,某些数据或方法可以是私有的,这些私有的数据或方法是不允许外界访问的.通过这种方式,对象对内部数据提供了不同级别的保护. 封装,也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏,封装一般是通过在类中封装数据,而通过对象或者self获取,和其他面向对象的语言类似,也是通过构造函数来进行数据封装,说白了就是,将一些功能相近的函数写在一起,方便我们的调用与维护. ◆实现简单的类封装◆在Python中,定义类是通过 >>> import sys >>> import os >>> >>> class lyshark(object): ... def __init__(self,name,age,sex): ... self.name = name ... self.age = age ... self.sex = sex ... >>> >>> temp=lyshark("lyshark","22","Man") >>> print("姓名:%s 年龄:%s 性别:%s"%(temp.name,temp.age,temp.sex)) 姓名:lyshark 年龄:22 性别:Man 以上就是创建的一个
创建对象的过程称为实例化,还是看如上代码, ◆使用公有属性封装◆类由属性和方法组成,类的属性是对数据的封装,而类的方法则表示对象具有的行为,类通常由函数(实例方法)和变量(类变量)组成,如下是使用公有属性封装的数据成员,可以看到,在类的外部,我们是可以使用 >>> import sys >>> import os # =====================以下内容是类的定义==================== >>> class lyshark(): ... def __init__(self,age): #构造函数,初始化数据 ... self.name = name #封装的数据成员 ... self.age = age ... ... def my_print(self): #封装的成员函数 ... print("我的名字是:%s 我的年龄是:%s"%(self.name,self.age)) ... # ========================================================= >>> >>> temp=lyshark("wangrui","22") #类的实例化,将参数传入类中 >>> temp.my_print() #调用类中的指定方法,打印数据 我的名字是:wangrui 我的年龄是:22 >>> >>> print(temp.name) #直接调用类中的数据成员 wangrui # ===============改变数据成员,再次调用看看=================== >>> temp.name="xxoo" >>> temp.my_print() 我的名字是:xxoo 我的年龄是:22 # ========================================================= 小总结: 1.公有属性或者静态属性,可以直接通过类直接访问,也可以直接通过实例进行访问.2.通过类的某个实例对公有属性进行修改,实际上对为该实例添加了一个与类的公有属性名称相同的成员属性,对真正的公有属性是没有影响的,因此它不会影响其他实例获取的该公有属性的值.3.通过类对公有属性进行修改,必然是会改变公有属性原有的值,他对该类所有的实例是都有影响的. ◆使用私有属性封装◆在上面的小例子中,我们也发现了一些缺陷问题,接下来则看看私有属性封装的技巧,私有属性和成员属性一样,是在 >>> import os >>> import sys # =====================以下内容是类的定义==================== class lyshark(): name = "lyshark" #定义公有属性(类变量,可共享数据) __age = 22 #定义私有属性(类变量) def __init__(self): #定义构造函数,初始化数据 self.__like = "soccer" #定义私有实例属性(实例变量) self.hobby = "xxoo" #定义公有实例属性 def my_print(self): #定义公有函数,外部可以调用 print("我的名字: %s"%self.name) print("我的年龄: %s"%self.__age) print("我的爱好: %s"%self.__like) print("其他: %s"%self.hobby) def __new_test(self): #定义私有函数,只能内部类调用 print("hello world") def __del__(self): #定义析构函数,清理数据 self.__nobody = "end" #print("函数执行结束,销毁无用的数据. %s"%self.__nobody) # =================(公有/私有)方法的调用==================== >>> temp=lyshark() #实例化对象 >>> temp.my_print() #调用类中方法(公有方法) 我的名字: lyshark 我的年龄: 22 我的爱好: soccer 其他: xxoo >>> temp.__new_test() #调用私有方法,则会报错 # =================(公有/私有)属性的调用==================== >>> print(lyshark.name) #调用公有属性则成功 lyshark >>> print(lyshark.__age) #调用私有属性,则会报错 >>> print(lyshark.__like) # ========================================================= 小总结: 通过对 ◆将类封装进对象中◆除了上面的一些经常用到的封装以外,还有一个比较难理解的封装格式,就是下面这种,它的意思是将一个类实例化后的对象当作一个参数传递到另一个类中,那么在另一个类中我们就可以访问到被传入类中的数据成员以及成员函数的调用啦. import os import sys class main(object): def __init__(self,obj): #OBJ参数用来接收对象 self.name=name self.obj=obj class uuid(object): def __init__(self,uid,sex): self.uid=uid self.age=age self.sex=sex temp=uuid(1001,22,"Man") #首先给UUID类初始化 lyshark=main("lyshark",temp) #将生成的TEMP对象传递给main # ========================================================= >>> lyshark.name 'lyshark' >>> lyshark.obj.uid #最后通过多级指针的方式访问数据 1001 >>> lyshark.obj.sex 'Man' >>> lyshark.obj.age 22 面向对象—>继承面向对象编程(OOP)语言的一个主要功能就是"继承",继承是指这样一种能力,它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展. 继承是面向对象的重要特性之一,通过继承可以创建新类,其目的是使用或修改现有类的行为,原始的类称为父类或超类,新类称为子类或派生类,继承机制可以实现代码的重用,继承的本质是将父类中的方法全部复制一份到子类中,Python里面的继承可以多继承,通过继承,可以获得父类的功能,继承的时候,如果父类中有重复的方法,优先找自己(子类). ◆继承基类普通函数◆以下是个基本小例子,则可说明继承的关系,首先 import os import sys class base(): #这个类是基类 def __init__(self,age): self.name = name self.age = age def printf(self): print("姓名:%s 年龄:%s"%(self.name,self.age)) class expand(base): #新建类expand继承base基类的方法 pass # ========================================================= >>> temp=expand("lyshark","22") >>> temp.printf() 姓名:lyshark 年龄:22 ◆继承基类构造函数◆当然我们也可以继承父类的构造函数,以及给相应的子类添加新的属性字段,还可以直接通过 直接继承构造函数: 新建 import os import sys class base(): def __init__(self,self.age)) class expand(base): def __init__(self,age): super(expand,self).__init__(name,age) #推荐使用本功能实现继承 #base.__init__(self,age) #此处和上面实现的功能相等 def printf(self): print("姓名:%s 年龄:%s"%(self.name,self.age)) # ========================================================= >>> temp=base("lyshark","22") >>> temp.printf() 姓名:lyshark 年龄:22 >>> temp=expand("lyshark","22") >>> temp.printf() 姓名:lyshark 年龄:22 添加新字段: 在父类 import os import sys class base(): #定义的父类 def __init__(self,self.age)) class expand(base): #定义的子类 def __init__(self,sex): super(expand,age) #继承父类的属性 self.sex = sex #新添加的一个属性 def printf(self): print("姓名:%s 年龄:%s 性别:%s "%(self.name,self.age,self.sex)) # ========================================================= >>> temp=base("lyshark","22") #原始基类,没有第三个字段 >>> temp.printf() 姓名:lyshark 年龄:22 >>> temp=expand("lyshark","Man") #在不影响父类情况下,重写新的字段 >>> temp.printf() 姓名:lyshark 年龄:22 性别:Man 继承父类函数(强制): 如果想在子类中使用父类的其中一个方法,可以使用以下的方式来实现. import os import sys class base(object): def printf(self): print("================================") print("执行函数....") print("================================") return 0 class expand(base): def fun(self): ret=super(expand,self).printf() #强制调用父类中的printf方法 return ret #将结果返回给调用者 # ========================================================= >>> temp=base() >>> temp.printf() #调用基类的方法 ================================ 执行函数.... ================================ >>> obj=expand() #在子类中调用基类方法 >>> ret=obj.fun() #将返回值付给ret并打印 >>> print(ret) ================================ 执行函数.... ================================ 0 ◆多类继承与多继承◆简单的多继承: 此处我们实现一个简单的多继承,这里我们会在代码中说明他们的执行顺序,废话不多说,看下图. import os import sys class A: def fun(self): print("我是A类里面的函数") class B: def fun1(self): print("我是B类里面的函数1") def fun2(self): print("我是B类里面的函数2") class C(A,B): def fun(self): print("我是C类里面的函数") # ========================================================= >>> temp=C() >>> temp.fun() #默认调用C类,如果C里面有fun()函数则默认执行自身 我是C类里面的函数 #如果自身没有,才会去基类里面去找fun()函数的存在 >>> temp.fun1() #由于C类中没有这个方法,它会去B或A类里面去找 我是B类里面的函数1 #这也为我们重写函数提供了可能性,我们只需修改C类且名称相同即可实现重写 复杂的多继承: 下面是重点和难点,在其他源码都是这么干的,属于嵌套继承如果开发新程序,则最好不要这么干,最后连自己都懵逼了. import os import sys class A: def bar(self): print('bar') self.f1() class B(A): def f1(self): print('b') class C(): def f1(self): print('c') class D(B): def f1(self): print('d') class E(C,D): pass temp=D() temp.bar() 多类继承(实例): 多继承也是一种解决问题的方式,这里我们通过例子,来演示一下多继承的应用场景,如下我们将添加三个类分别是 1.我们首先创建一个基类 class Person(object): def __init__(self,age): self.name = name self.age = age def walk(self): print('%s is walking...' % self.name) def talk(self): print('%s is talking...' % self.name ) 2.在以上基类的基础上派生一个 class Teacher(Person): def __init__(self,level,salary): super(Teacher,age) self.level = level self.salary = salary def teach(self): print('%s is teaching...' % self.name) 3.最后创建一个学生类 class Student(Person): def __init__(self,class_): Person.__init__(self,age) self.class_ = class_ def study(self): print('%s is studying...' % self.name) 4.最后直接实例化,并传递两个参数,打印看结果,很好理解. >>> t1 = Teacher('张老师',33,'高级教师',20000) >>> s1 = Student('小明',13,'初一3班') >>> t1.talk() >>> t1.walk() >>> t1.teach() >>> s1.talk() >>> s1.walk() >>> s1.study() 张老师 is talking... 张老师 is walking... 张老师 is teaching... 小明 is talking... 小明 is walking... 小明 is studying... 面向对象—>多态多态性(polymorphisn)是允许你将父对象设置成为和一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作,多态的作用:我们知道,封装可以隐藏实现细节,使得代码模块化,继承可以扩展已存在的代码模块,它们的目的都是为了实现 import os import sys class Animal(object): def __init__(self,name): self.name = name class Cat(Animal): def talk(self): print('%s: 喵喵喵!' %self.name) class Dog(Animal): def talk(self): print('%s: 汪!汪!汪!' %self.name) def func(obj): #这里制定一个接口,后期直接调用它 obj.talk() # ========================================================= >>> c1 = Cat("catcat") >>> d1 = Dog("dogdog") >>> func(c1) #这里调用相同的方法,传入的数据不同 catcat: 喵喵喵! >>> func(d1) #这里调用相同的方法,传入的数据不同 dogdog: 汪!汪!汪! 面向对象—>包装在上面的面向对象概念中提到过,通常类中封装的是
◆类的方法◆上面的简单介绍也说明了,通常情况下我们如果在成员函数的上方加上 import os import sys class lyshark(object): name="wangrui" #赋值等待被调用 age="22" sex="Man" def __init__(self,x,y,z): self.x=x self.y=y self.z=z @classmethod #声明下方的函数为类方法 def printf(cls): #此函数只能调用类变量,而不能调用成员属性 print("姓名:%s 年龄:%s 性别:%s"%(cls.name,cls.age,cls.sex)) # ========================================================= >>> temp=lyshark("100","100") >>> temp.printf() 姓名:wangrui 年龄:22 性别:Man 如果我们将以上的打印函数变量修改调用实例变量,则会出现错误,这是因为装饰器 def __init__(self,z): self.x=x self.y=y self.z=z #@classmethod #此装饰器存在,不允许调用实例变量 def printf(self): print("姓名:%s 年龄:%s 性别:%s"%(self.x,self.y,self.z)) # ========================================================= >>> temp=lyshark("lyshark","33","Man") >>> temp.printf() 姓名:lyshark 年龄:22 性别:Man ◆静态方法◆上面的简单介绍也说明了,通常情况下我们如果在成员函数的上方加上 import os import sys class lyshark(object): @staticmethod def sum(x,y): return x+y @staticmethod def sub(x,y): return x-y # ========================================================= >>> #temp=lyshark() #这里无需实例化 >>> text=lyshark.sum(10,20) >>> print("两数之和:%s"%text) 两数之和:30 >>> text=lyshark.sub(100,50) >>> print("两数之差:%s"%text) 两数之差:50 以上的小例子就是一个典型的封装,因为我们无法调用类中的其他数据,所以直接将它作为一个工具箱使用是最恰当不过的啦,当然这个功能至今为止在开发中也没怎末用到过. ◆属性方法◆property是一种特殊的属性,访问它时会执行一段功能(函数)然后返回值,他可以把一个方法变成静态属性,传递参数,它的第一个参数也必须是当前实例对象,且该方法必须要有返回值. import os import sys class lyshark(object): def __init__(self,weight,height): self.name=name self.weight=weight self.height=height @property def foo(self): return self.weight + self.height # ========================================================= >>> temp=lyshark("wangrui",75,1.88) >>> print(temp.foo) #此处我们直接调用这个属性,并没有传递参数 76.88 上面的小例子我们可以看到,实例化一个类以后,在调用内部的foo函数的时候,并没有添加括号,然而还是调用成功了,这种特性的使用方式遵循了统一访问的原则,即对外屏蔽细节,只需要像调用变量一样的使用它即可,给用户的感觉就是调用了一个类中的变量. 由于新式类中具有三种访问方式,我们可以根据他们几个属性的访问特点,分别将三个方法定义为对同一个属性:获取、修改、删除,看下面的代码: import os import sys class lyshark(object): @property def get(self): print("get 函数运行了我...") @get.setter def get(self,value): print("set 设置参数运行了我,传递的参数是: %s"%value) @get.deleter def get(self): print("工作结束了,可以删除数据了") # ========================================================= >>> temp = lyshark() #实例化 >>> temp.get #调用get属性,则会执行get()函数 get 函数运行了我... >>> temp.get = 'hello' #设置属性则会执行get.setter函数 set 设置参数运行了我,传递的参数是: hello >>> del temp.get #删除工作,则会走get.deleter函数 工作结束了,可以删除数据了 下面来看一个具体例子,我们可以直接调用 class Goods(object): def __init__(self): # 原价 self.original_price = 100 # 折扣 self.discount = 0.8 @property def price(self): # 实际价格 = 原价 * 折扣 new_price = self.original_price * self.discount return new_price @price.setter def price(self,value): self.original_price = value @price.deltter def price(self,value): del self.original_price # ========================================================= >>> obj = Goods() >>> obj.price # 获取商品价格 >>> obj.price = 200 # 修改商品原价 >>> del obj.price # 删除商品原价 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |