Python从设计之初就已经是一门面向对象的语言,在python里所有东西皆是对象。

下面通过一个实例来说明什么是面向对象。

引子

你是一家公司的员工,公司现在要开发一款“人狗战争”的游戏,人狗战争肯定有人和狗两种角色。两种角色都有名字、性别,但是技能不同比如人可以用棍子打狗,狗可以咬人...

在不会面向对象之前倾尽所学知识写出下面代码。

def hit(name):
print('%s发动了打技能' % name) def bite(name):
print('%s发动了咬技能' % name) def Person(name,sex,hit):
data = {
'name': name,
'sex': sex,
'skill':hit
}
return data def Dog(name,sex,dog_type,bite):
data = {
'name': name,
'sex': sex,
'dog_type':dog_type,
'skill':bite
}
return data person = Person('林道明','男',hit) person.get('skill')(person.get('name'))
dog.get('skill')(dog.get('name')) """
执行结果:
林道明发动了打技能
哈士奇小狗发动了咬技能
"""

这样写发现程序有很多相同的代码,而且拓展性不是很好(要是里面还出现其他n种动物类型,是不是要全部重写?),那么要这么写出拓展性好的代码呢?下面进入正题:

面向对象编程

Class 类
一个类即是对一类拥有相同属性的对象的抽象、蓝图、原型。在类中定义了这些对象的都具备的属性(variables(data))、共同的方法

Object 对象 
一个对象即是一个类的实例化后实例,一个类必须经过实例化后方可在程序中调用,一个类可以实例化多个对象,每个对象亦可以有不同的属性,就像人类是指所有人,每个人是指具体的对象,人与人之前有共性,亦有不同

Encapsulation 封装
在类中对数据的赋值、内部调用对外部用户是透明的,这使类变成了一个胶囊或容器,里面包含着类的数据和方法

Inheritance 继承
一个类可以派生出子类,在这个父类里定义的属性、方法自动被子类继承

Polymorphism 多态
多态是面向对象的重要特性,简单点说:“一个接口,多种实现”,指一个基类中派生出了不同的子类,且每个子类在继承了同样的方法名的同时又对父类的方法做了不同的实现,这就是同一种事物表现出的多种形态。
编程其实就是一个将具体世界进行抽象化的过程,多态就是抽象化的一种体现,把一系列具体事物的共同点抽象出来, 再通过这个抽象的事物, 与不同的具体事物进行对话。
对不同类的对象发出相同的消息将会有不同的行为。比如,你的老板让所有员工在九点钟开始工作, 他只要在九点钟的时候说:“开始工作”即可,而不需要对销售人员说:“开始销售工作”,对技术人员说:“开始技术工作”, 因为“员工”是一个抽象的事物, 只要是员工就可以开始工作,他知道这一点就行了。至于每个员工,当然会各司其职,做各自的工作。
多态允许将子类的对象当作父类的对象使用,某父类型的引用指向其子类型的对象,调用的方法是该子类型的方法。这里引用和调用方法的代码编译前就已经决定了,而引用所指向的对象可以在运行期间动态绑定

OOP面向对象编程介绍

开发正规的程序跟那种写个运行一次就扔了的小脚本一个很大不同就是,你的代码总是需要不断的更改,不是修改bug就是添加新功能等,所以为了日后方便程序的修改及扩展,你写的代码一定要遵循易读、易改的原则(专业数据叫可读性好、易扩展)。
 
如果你把一段同样的代码复制、粘贴到了程序的多个地方以实现在程序的各个地方调用 这个功能,那日后你再对这个功能进行修改时,就需要把程序里多个地方都改一遍,这种写程序的方式是有问题的,因为如果你不小心漏掉了一个地方没改,那可能会导致整个程序的运行都 出问题。 因此我们知道 在开发中一定要努力避免写重复的代码,否则就相当于给自己再挖坑。
 
还好,函数的出现就能帮我们轻松的解决重复代码的问题,对于需要重复调用的功能,只需要把它写成一个函数,然后在程序的各个地方直接调用这个函数名就好了,并且当需要修改这个功能时,只需改函数代码,然后整个程序就都更新了。
 
其实OOP编程的主要作用也是使你的代码修改和扩展变的更容易,那么小白要问了,既然函数都能实现这个需求了,还要OOP干毛线用呢? 呵呵,说这话就像,古时候,人们打仗杀人都用刀,后来出来了枪,它的主要功能跟刀一样,也是杀人,然后小白就问,既然刀能杀人了,那还要枪干毛线,哈哈,显而易见,因为枪能更好更快更容易的杀人。函数编程与OOP的主要区别就是OOP可以使程序更加容易扩展和易更改。

下面我们用面向对象重新实现一下“人狗战争”:

class Animal(object):
def __init__(self,name,sex):
self.name = name
self.sex = sex class Person(Animal):
def __init__(self,name,sex):
super(Person,self).__init__(name,sex) def hit(self):
print("%s发动了打技能" % self.name) class Dog(Animal):
def __init__(self,name,sex,dog_type):
super(Dog,self).__init__(name,sex)
self.dog_type = dog_type def bite(self):
print("%s发动了咬技能" % self.name) person = Person('林道明','男')
dog = Dog('哈士奇小狗','母','哈士奇') person.hit()
dog.bite() """
执行结果:
林道明发动了打技能
哈士奇小狗发动了咬技能
"""

通过面向对象的方法使程序更容易拓展,下面拓展一个“羊”类:

class Sheep(Animal):
def __init__(self,name,sex,hair_color):
super(Sheep,self).__init__(name,sex)
self.hair_color = hair_color def bray(self):
print("%s发动了咬技能" % self.name)

封装

封装最好理解了。封装是面向对象的特征之一,是对象和类概念的主要特性。封装,也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。

继承:

面向对象编程 (OOP) 语言的一个主要功能就是“继承”。继承是指这样一种能力:它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。

通过继承创建的新类称为“子类”或“派生类”。

被继承的类称为“基类”、“父类”或“超类”。

继承的过程,就是从一般到特殊的过程。

要实现继承,可以通过“继承”(Inheritance)和“组合”(Composition)来实现。

在某些 OOP 语言中,一个子类可以继承多个基类。但是一般情况下,一个子类只能有一个基类,要实现多重继承,可以通过多级继承来实现。

继承概念的实现方式主要有2类:实现继承、接口继承。

实现继承是指使用基类的属性和方法而无需额外编码的能力;
接口继承是指仅使用属性和方法的名称、但是子类必须提供实现的能力(子类重构爹类方法);
在考虑使用继承时,有一点需要注意,那就是两个类之间的关系应该是“属于”关系。例如,Employee 是一个人,Manager 也是一个人,因此这两个类都可以继承 Person 类。但是 Leg 类却不能继承 Person 类,因为腿并不是一个人。
 
抽象类仅定义将由子类创建的一般属性和方法。

OO开发范式大致为:划分对象→抽象类→将类组织成为层次化结构(继承和合成) →用类与实例进行设计和实现几个阶段。

上面那个程序就用到了继承。

多继承

需要注意圆括号中父类的顺序,若是父类中有相同的方法名,而在子类使用时未指定,python从左至右搜索 即方法在子类中未找到时,从左到右查找父类中是否包含方法。

方法重写

解释:多态性(polymorphisn)是允许你将父对象设置成为和一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。简单的说,就是一句话:一个接口,多种形态。
多态实现的一个重要目的——接口重用!为了类在继承和派生的时候,保证使用“家谱”中任一类的实例的某一属性时的正确调用。
Pyhon 很多语法都是支持多态的,比如 len(),sorted(), 你给len传字符串就返回字符串的长度,传列表就返回列表长度。
还是以上面的“人狗战争”作为例子:
class Animal(object):
def __init__(self,name,sex):
self.name = name
self.sex = sex def talk(self):
pass class Person(Animal):
def __init__(self,name,sex):
super(Person,self).__init__(name,sex) def hit(self):
print("%s发动了打技能" % self.name) def talk(self):
print('%s:oh fuck!' % self.name) class Dog(Animal):
def __init__(self,name,sex,dog_type):
super(Dog,self).__init__(name,sex)
self.dog_type = dog_type def bite(self):
print("%s发动了咬技能" % self.name) def talk(self):
print('%s:汪汪汪!' % self.name) class Sheep(Animal):
def __init__(self,name,sex,hair_color):
super(Sheep,self).__init__(name,sex)
self.hair_color = hair_color def bray(self):
print("%s发动了咬技能" % self.name) def talk(self):
print("%s:绵绵绵!" % self.name) person = Person('林道明','男')
dog = Dog('哈士奇小狗','母','哈士奇') person.talk()
dog.talk() """
执行结果:
林道明:oh fuck!
哈士奇小狗:汪汪汪!
"""

类私有&共开

两个下滑线(__)开头的变量和方法就是私有变量和私有方法 。公开和私有的区别就是类外可以访问公开变量和方法,而私有变量只能供类内部访问(子类外部都无法访问)。

class Dog2(object):
def __init__(self,name,type):
self.name = name #共开变量
self.__type = type #私有变量 #共开方法
def talk(self):
print('wang wang wang~~~') #私有方法
def __kneel(self):
print('kneel down')

静态方法

通过@staticmethod装饰器即可把其装饰的方法变为一个静态方法,什么是静态方法呢?其实不难理解,普通的方法,可以在实例化后直接调用,并且在方法里可以通过self.调用实例变量或类变量,但静态方法是不可以访问实例变量或类变量的,一个不能访问实例变量和类变量的方法,其实相当于跟类本身已经没什么关系了,它与类唯一的关联就是需要通过类名来调用这个方法

class mMath(object):                          

    @staticmethod
def add(x,y,z):
print('%d+%d+%d=%d' % (x,y,z,x+y+z)) mMath.add(1,2,3)

属性方法

隐藏实现动作,所以你每次调用时,其实它都要经过一系列的动作才返回你结果,但这些动作过程不需要用户关心, 用户只需要调用这个属性就可以。

class School(object):
def __init__(self):
self.state = 0 @property
def aaa(self):
if self.state == 0:
print('上课')
elif self.state == 1:
print('下课')
elif self.state == 2:
print('返学')
elif self.state == 3:
print('放假') @aaa.setter
def aaa(self,state):
print('修改状态为%s' % state)
self.state = state @aaa.deleter
def schoolState(self):
print('清楚状态')
del self.state s = School()
s.aaa
s.aaa = 2
s.aaa

反射

通过字符串映射或修改程序运行时的状态、属性、方法

class Dog(object):
def __init__(self,name):
self.name = name def execute(self,str):
#判断是否存在字符和方法的映射
if hasattr(self,str):
# 得到字符映射的方法
func = getattr(self,str)
func() def eat(self,food='checken'):
print('%s is eating %s' % (self.name,food)) def drink(self,drink='water'):
print('%s is drinking %s' % (self.name,drink)) dog = Dog('dog')
dog.execute('eat') #设置成员
ret = setattr(dog,'name',19)
print(dog.name) #删除成员
delattr(dog,'name')
#print(dog.name)#报错

类的特殊成员方法

1. __doc__  表示类的描述信息

2. __module__ 和  __class__ 

  __module__ 表示当前操作的对象在那个模块

  __class__     表示当前操作的对象的类是什么

3. __init__ 构造方法,通过类创建对象时,自动触发执行。

4.__del__析构方法,当对象在内存中被释放时,自动触发执行

5. __call__ 对象后面加括号,触发执行。

6. __dict__ 查看类或对象中的所有成员

8.__getitem__、__setitem__、__delitem__

类的专有方法

  • __init__ : 构造函数,在生成对象时调用
  • __del__ : 析构函数,释放对象时使用
  • __repr__ : 打印,转换
  • __setitem__ : 按照索引赋值
  • __getitem__: 按照索引获取值
  • __len__: 获得长度
  • __cmp__: 比较运算
  • __call__: 函数调用
  • __add__: 加运算
  • __sub__: 减运算
  • __mul__: 乘运算
  • __div__: 除运算
  • __mod__: 求余运算
  • __pow__: 乘方

运算符重载实例:

class mClock(object):                                                                          

    def __init__(self,mtime):
self.mtime = mtime def __add__(self, other):
time1 = self.mtime.split(':')
time2 = other.mtime.split(':')
minute = (int(time1[1]) + int(time2[1]))%60
hour = (int(time1[0]) + int(time2[0]))%24 + int((int(time1[1]) + int(time2[1]))/60)
return '%s:%s' % (hour,minute) mclock1 = mClock("12:45")
mclock2 = mClock("9:25")
print(mclock1 + mclock2) """
结果: 22:10
"""

7 - py面向对象一条龙服务的更多相关文章

  1. webpack搭建前端一条龙服务

    作为从grunt.gulp一路走来的老码农,一开始用webpack的时候我是很抗拒的.但由于核心库使用了vue,而webpack又是vue的最佳拍档(vue作者专门为其写了vue-loader),所以 ...

  2. 从app上传图片到php,再上传到java后端服务器的方法一条龙服务

    在现在的网络开发中,上传图片类的需求实在是太普通不过了,但是对于怎么样做到上传图片,对于刚开始建立项目的时候,还是有点不知所措的.也许有幸,我们做的项目是之前已经有人写过类似的用例了,那么我们只需要依 ...

  3. python基础入门教程(一条龙服务)

    一.语言基础 01-1 计算机系统 解释器下载 变量   小整数池 01-2 垃圾回收机制 02 数据类型 运算符(解压赋值等) 03 流程控制 if while for 04 整形 字符串 列表 0 ...

  4. 【NuGet】打包上传一条龙服务

    昨天写了搭建自己的NuGet程序源,但是领导不满意之前的打包上传~~,无奈只能去爬点思路了,这里参考的其他博文,但是还是想写下来. 第一步.建立一个批处理文件 在文件里,有三条命令: nuget pa ...

  5. 《RedHatLinux逻辑卷的管理》——一条龙服务

    首先建2分区 [root@localhost ~]# partx -d /dev/sdb error deleting partition 4: BLKPG: No such device or ad ...

  6. [py]面向对象图解assignment

    python的chained assignment 在python中 a is b is c 等价于 a is b and b is c 所以,猜猜 False is False is False # ...

  7. hisi3559的usb无线网卡驱动(rtl8192cu)(一条龙服务:内核编译、驱动编译、iw等工具编译)

    usb无线网卡驱动(rtl8192cu) 内核编译.驱动编译.iw等工具编译  (哈哈,如果有其他问题,麻烦留言:) 环境 板卡:hi3559av100(arm64) 交叉编译链:aarch64-hi ...

  8. ubuntu 宝塔安装一条龙服务

    ubuntu 安装 1, wget -O install.sh http://download.bt.cn/install/install-ubuntu.sh && sudo bash ...

  9. py面向对象编程基础

    '''类:一类事物的抽象,用于定义抽象类型 实例:类的单个实际描述 如:人是一个类,而单个人是一个实例 用class来创建一个类,调用一个类来创建一个实例'''class Person: passxi ...

随机推荐

  1. web 页面 验证码 实现

    1. 前台页面代码:  页面刷新时会自动请求 ${pageContext.request.contextPath}/yanzheng?yz=&time=-1111 这个action <f ...

  2. once函数,简约不简单的

    module.exports = once once.proto = once(function () { Object.defineProperty(Function.prototype, 'onc ...

  3. WEB图表制作

    https://www.hcharts.cn/demo/highcharts/column-drilldown

  4. kindeditor<=4.1.5文件上传漏洞

    最近发现很多网页篡改与暗链都是利用kindeditor编辑器,于是搜了一下kindeditor的漏洞,发现低于4.1.5版本的存在文件上传的漏洞,可以上传txt,html后缀的文档,许多恶意的文档貌似 ...

  5. select 点击的时候获取 value值

    <select onchange="selectUrl1(this.options[this.options.selectedIndex].value);">      ...

  6. TOJ 4008 The Leaf Eaters(容斥定理)

    Description As we all know caterpillars love to eat leaves. Usually, a caterpillar sits on leaf, eat ...

  7. unity3d发布到安卓平台

    1.首先你得装上JDK并且配置好环境(就像学java配置环境一样) 百度jdk把下载安装成功 找到安装jdk目录的bin目录,复制路径,例如 C:\Program Files (x86)\Java\j ...

  8. VS2010中VC++目录和C/C++之间的区别。VC++ Directories和C/C++的区别。

    首先,这是个历史遗留问题,说起来比较复杂.其次,这个问题在微软的MSDN博客上已经专门被说起过了,英文好的请直接移步到原文:<VC++ Directories>.另外,stack over ...

  9. Basic Data Structures and Algorithms in the Linux Kernel--reference

    http://luisbg.blogalia.com/historias/74062 Thanks to Vijay D'Silva's brilliant answer in cstheory.st ...

  10. mysql存储过程嵌套循环并分页处理数据

    业务背景:公司存证产品升级,随着数据量的增加,存证产品线按业务分表,导致以往的存证关联数据需要做数据同步更新.版本发布前,通过当前存储过程解决数据升级问题. ##创建存证文档关联情况下更新所用存储过程 ...