阿布云

你所需要的,不仅仅是一个好用的代理。

Python面向对象基础:自动化系列(二)

阿布云 发表于

21.png

1.2面向对象三大特征

面向对象的三大特性:封装、继承、多态。

1.2.1封装

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

1.封装

# 创建类

classF2:

 

#init构造函数,在实例化时做一些类的初始化的工作

def__init__(self,name,age):

self.name=name

self.age=age

 

# 根据类F2创建对象

# 自动执行F2类的__init__方法

obj1=F2('xulaingwei', 18)

#将xuliangwei和18分别封装到obj1和self的name、age属性中

 

# 根据类F2创建对象

# 自动执行F2类的__init__方法

obj2=F2('jack', 58)

#将Jack和58分别封装到obj2和self的name、age属性中

2.调用封装的内容时,有两种调用情况:

  • 1.通过对想直接调用

 # 创建类

classF2:

def__init__(self,name,age):

self.name=name

self.age=age

 

obj1=F2('xulaingwei', 18)

print(obj1.name,obj1.age) #直接调用obj1对象的name age属性

 

obj2=F2('jack', 58)

print(obj2.name,obj2.age) #直接调用obj2对象的name age属性

2.通过self间接调用

执行类中的方法时,需要通过self间接调用被封装的内容

# 创建类

classF2():

  def__init__(self,name,age):

  self.name=name

  self.age=age

 

defdetail(self):

print (self.name)

print (self.age)

 

obj1=F2('xuliangwei',18)

 

obj1.detail() # Python默认会将obj1传给self参数,即:obj1.detail(obj1),所以,此时方法内部的 self = obj1,即:self.name 是 xuliangwei ;self.age 是 18

 

obj2=F2('jack',58)

obj2.detail() # Python默认会将obj2传给self参数,即:obj2.detail(obj2),所以,此时方法内部的 self = obj2,即:self.name 是 jack ;self.age 是 58

综上所述,对于面向对象的封装来说,其实就是使用构造方法将内容封装到对象中,然后通过对象直接或者self间接获取被封装的内容。

练习题:在终端输出如下信息

小明,10岁,男,上山去砍柴

小明,10岁,男,开车去东北

小明,10岁,男,最爱大保健

 

老李,90岁,男,上山去砍柴

老李,90岁,男,开车去东北

老李,90岁,男,最爱大保健

函数式编程方法:

defkanchai(name,age,gender):

print ("%s,%s岁,%s,上山砍柴" %(name,age,gender))

 

defqudongbei(name,age,gender):

print ("%s,%s岁,%s,开车去东北" %(name,age,gender))

 

defdabaojian(name,age,gender):

print ("%s,%s岁,%s,最爱大保健" %(name,age,gender))

 

kanchai('小明', 10, '男')

qudongbei('小明', 10, '男')

dabaojian('小明', 10, '男')

 

kanchai('老李', 90, '男')

qudongbei('老李', 90, '男')

dabaojian('老李', 90, '男')

面向对象编程方法:

#!/usr/bin/env python

# Author:xuliangwei

classF1:

#init构造函数

#在实例化时做一些类的初始化的工作

def__init__(self,name,age,gender):

self.name=name

self.age=age

self.gender=gender

 

defkanchai(self):

print("%s,%s岁,%s,上山砍柴" %(self.name, self.age, self.gender))

defqudongbei(self):

print("%s,%s岁,%s,开车去东北" %(self.name,self.age,self.gender))

defdabaojian(self):

print("%s,%s岁,%s,最爱大保健" %(self.name, self.age, self.gender))

 

obj1=F1('小明', 10, '男')

obj1.kanchai()

obj1.qudongbei()

obj1.dabaojian()

 

obj2=F1('老李', 90, '男')

obj2.kanchai()

obj2.qudongbei()

obj2.dabaojian()

 

#上述对比可以看出,如果使用函数式编程,需要在每次执行函数时传入相同的参数,如果参数多的话,又需要粘贴复制了... ;而对于面向对象只需要在创建对象时,将所有需要的参数封装到当前对象中,之后再次使用时,通过self间接去当前对象中取值即可。

1.2.2继承

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

例如:

猫可以:喵喵叫、吃、喝、拉、撒

狗可以:汪汪叫、吃、喝、拉、撒

classmao:

  def 喵喵叫(self):

  print ("喵喵叫")

  def(self):

  print ("吃")

  def(self):

  print ("喝")

  def(self):

  print ("拉")

  def(self):

  print ("撒")

 

classgou:

  def 汪汪叫(self):

  print ("汪汪叫")

  def(self):

  print ("吃")

  def(self):

  print ("喝")

  def(self):

  print ("拉")

  def(self):

  print ("撒")

上述代码不难看出,吃、喝、拉、撒是猫和狗都具有的功能,而我们却分别的猫和狗的类中编写了两次。

如果使用”继承“的思想,如下实现:

动物:吃、喝、拉、撒

猫:喵喵叫(猫继承动物的功能)

狗:汪汪叫(狗继承动物的功能)

class Animal:

  defeat(self):

  print ("%s 吃 " % (self.name))

 

  defdrink(self):

  print ("%s 喝 " % (self.name))

 

  defshit(self):

  print ("%s 拉 " % (self.name))

 

  defpee(self):

  print ("%s 撒 " % (self.name))

 

class Cat(Animal):

   def__init__(self,name):

  self.name=name

  self.breed= '猫'

 

  defcry(self):

  print ('%s 喵喵叫-->%s' %(self.name,self.breed))

 

class Dog(Animal):

  def__init__(self,name):

  self.name=name

  self.breed= '狗'

 

  defcry(self):

  print ('%s 汪汪叫-->%s' %(self.name,self.breed))

 

# ######### 执行 #########

 

c1= Cat('小黑猫')

c1.cry()

c1.eat()

c1.drink()

 

d1= Dog('小瘦狗')

d1.cry()

d1.eat()

d1.drink()

d1.pee()

##对于面向对性爱那个的继承来说,其实就是将多个类共有的方法提取到父类中,子类仅需继承父类而不必一一实现每个方法.(避免重复造轮子)

注:除了子类和父类的称谓,你可能看到过 派生类 和 基类 ,他们与子类和父类只是叫法不同而已。

1.2.3多级继承

1.Python的类可以继承多个类,Java和C#中则只能继承一个类

2.Python的类如果继承了多个类,那么其寻找方法的方式有两种,分别是: 深度优先和广度优先

1.png

python2经典类,按深度优先来继承的。

python2新式类,按广度有限来继承的。

python3经典类,新式类 是按广度优先来继承的。

  • 经典类(深度优先)

    当类是经典类时,多继承情况下,会按照深度优先方式查找

 #经典类写法

classA1:

  pass

classA2(A1):

  pass

经典类,实践测试

classD:

 

  defbar(self):

  print ('D.bar')

 

classC(D):

  defbar(self):

  print ('C.bar')

classB(D):

  defbar(self):

  print ('B.bar')

classA(B,C):

  defbar(self):

  print ('A.bar')

a=A()

a.bar()

# 执行bar方法时

# 首先去A类中查找,如果A类中没有,则继续去B类中找,如果B类中么有,则继续去D类中找,如果D类中么有,则继续去C类中找,如果还是未找到,则报错

# 所以,查找顺序:A --> B --> D --> C

# 在上述查找bar方法的过程中,一旦找到,则寻找过程立即中断,便不会再继续找了

  • 新式类(广度优先)

          当类是新式类时,多继承情况下,会按照广度优先方式查找

#新式类写法

classN1(object):

  pass

classN2(N1):

  pass

新式类,实践测试

classD(object):

  defbar(self):

  print ('D.bar')

 

classC(D):

  defbar(self):

  print ('C.bar')

 

classB(D):

  defbar(self):

  print ('B.bar')

classA(B,C):

  defbar(self):

  print ('A.bar')

a=A()

a.bar()

# 执行bar方法时

# 首先去A类中查找,如果A类中没有,则继续去B类中找,如果B类中么有,则继续去C类中找,如果C类中么有,则继续去D类中找,如果还是未找到,则报错

所以,查找顺序:A --> B --> C --> D

# 在上述查找bar方法的过程中,一旦找到,则寻找过程立即中断,便不会再继续找了

经典类:首先去A类中查找,如果A类中没有,则继续去B类中找,如果B类中么有,则继续去D类中找,如果D类中么有,则继续去C类中找,如果还是未找到,则报错

新式类:首先去A类中查找,如果A类中没有,则继续去B类中找,如果B类中么有,则继续去C类中找,如果C类中么有,则继续去D类中找,如果还是未找到,则报错

1.2.4广度优先和深度优先

下图,其深度优先遍历顺序为 1->2->4->8->5->3->6->7

2.png

下图,其广度优先算法的遍历顺序为: 1->2->3->4->5->6->7->8

3.png

1.2.5多态

多态是面向对象的重要特性,简单点说:一个接口,多种实现。

classF1:

  pass

 

classS1(F1):

defshow(self):

print ('S1.show')

 

classS2(F1):

defshow(self):

print ('S2.show')

 

def Func(obj):

print (obj.show())

 

s1_obj=S1()

Func(s1_obj)

 

s2_obj=S2()

Func(s2_obj)