7 - py面向对象一条龙服务

时间:2022-08-28 11:32:56

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__

7 - py面向对象一条龙服务View Code

类的专有方法

  • __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
"""