感谢前辈们的指导,http://www.cnblogs.com/yupeng/p/3414736.html
http://www.cnblogs.com/alex3714/articles/5188179.html
http://www.cnblogs.com/wupeiqi/p/4493506.html
深度优先:https://www.cnblogs.com/yupeng/p/3414736.html
广度优先:https://www.cnblogs.com/zhaof/p/7092400.html
个人将五篇博客里面的优点总结到一起,并怀着对前辈们的尊敬,以下均是纯手打,代码已经过验证
可以在python3.6.3中运行
面向对象是一种编程方式,需要类和对象来实现,面向对象编程其实就是对类和对象的使用
类就是指一个模板,模板里的的函数可以有多个,函数里实现一些功能
对象根据模板创建实例,通过实例对象执行类中的函数
面向对象;【创建对象】【通过对象执行方法】
class Foo:
def Bar(self):
print("Bar")
def Hello(self,name):
print("i am %s"%(name))
obj=Foo()
obj.Bar()
obj.Hello("wupeiqi")
面向对象三大特点:封装,继承,多态
一,封装:将内容放在某个地方,以后如果有需要,可以用某种函数调用此内容
第一步:将内容封装到某处:
第二步:从某处调用被封装的内容
第一步详解:
class Foo:
def __init__(self,name,age):
self.name=name
self.age=age
#根据类对象Foo创建对象
#自动执行Foo类的__init__方法
obj1=Foo('狂',18)#将狂和18分别封装到name和age属性中
第二步详解:
从某处调用相关函数:
有两种方案(所有语言中的特性)
1,通过对象直接调用
2,通过self间接调用
我们先来看第一种
class Foo:
def __init__(self,name,age):
self.name=name
self.age=age
obj1=Foo('wupeiqi',18)
print(obj1.name)
print(obj1.age)
obj2=Foo('alex',73)
print(obj2.name)
print(obj2.age)
第二种介绍:
class Foo:
def __init__(self,name,age):
self.name=name
self.age=age
def detail(self):
print(self.name)
print(self.age)
obj1=Foo('wupeiqi',18)
obj1.detail()
obj2=Foo('alex',73)
obj2.detail()
由此可见,第二种通过self的间接调用指的是通过函数去访问
练习一:在终端输出如下信息
小明,10岁,男,上山去砍柴
小明,10岁,男,开车去东北
小明,10岁,男,最爱大保健
老李,90岁,男,上山去砍柴
老李,90岁,男,开车去东北
老李,90岁,男,最爱大保健
class Foo:
def __init__(self,name,age,sex):
self.name=name
self.age=age
self.sex=sex
def kanchai(self):
print("%s,%s岁,%s,上山去砍柴" % (self.name, self.age, self.sex))
def qudongbei(self):
print("%s,%s岁,%s,开车去东北" % (self.name, self.age, self.sex))
def dabaojian(self):
print("%s,%s岁,%s,最爱大保健" % (self.name, self.age, self.sex))
xiaoming = Foo('小明',10, '男')
xiaoming.kanchai()
xiaoming.qudongbei()
xiaoming.dabaojian()
laoli = Foo('老李',90, '男')
laoli.kanchai()
laoli.qudongbei()
laoli.dabaojian()
二,继承:
继承,面向对象中的继承和现实生活中的继承相同,即:子可以继承父的内容
比如说 人 ,学生,工作者
学生和工作者就是人的两个扩展子类
class Animal:
def eat(self):
print('%s 吃'%self.name)
def drink(self):
print('%s 喝'%self.name)
def shit(self):
print('%s 拉'%self.name)
def pee(self):
print('%s 撒'%self.name)
def pee(self):
print('%s 撒'%self.name)
class Cat(Animal):
def __init__(self,name):
self.name=name
self.bread='猫'
def cry(self):
print('喵喵叫')
class Dog(Animal):
def __init__(self, name):
self.name = name
self.bread = '狗'
def cry(self):
print('汪汪叫')
c1 = Cat('小白家的小黑猫')
c1.eat()
c2 = Cat('小黑的小白猫')
c2.drink()
d1 = Dog('胖子家的小瘦狗')
d1.eat()
所以对于面向对象的继承来讲,其实就是将多个类共有的方法提取到父类中,子类仅需继承父类而不必实现每一种方法
那么一个很关键的问题来了,对于多继承,我们该怎么办呢,如何准备呢
是否可以继承多个类
如果继承多个类每个类中定义了相同的函数,那么哪一个会被使用呢
1、Python的类可以继承多个类,Java和C#中则只能继承一个类
2、Python的类如果继承了多个类,那么其寻找方法的方式有两种,分别是:深度优先和广度优先
对深度优先和广度优先的详解请见附录:
当类是经典类的时候,多继承情况下,会按照深度优先方式查找
当类是新式类的时候,多继承情况下,会按照广度优先方式查找
区分:当前类或者父类继承了object类,那么该类便是新式类,否则是经典类
class C1: #C1是经典类
pass
class C2(object)#C1是经典类
pass
class C1: #C1是新式类
pass
class C2(C1)#C1是新式类
pass
class D:
def bar(self):
print('D bar')
class C(D):
def bar(self):
print('C.bar')
class B(D):
def bar(self):
print('B.bar')
class A(B,C):
def bar(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类中找,如果还是未找到,则报错 class Animal(object): def __init__(self, name): # Constructor of the class self.name = name def talk(self): # Abstract method, defined by convention only raise NotImplementedError("Subclass must implement abstract method") 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('小晴') d1 = Dog('李磊') func(c1) func(d1) 正确代码 Func函数需要接收一个F1类型或者F1子类的类型""" obj.show() s1_obj = S1() Func(s1_obj) # 在Func函数中传入S1类的对象 s1_obj,执行 S1 的show方法,结果:S1.show s2_obj = S2() Func(s2_obj) # 在Func函数中传入Ss类的对象 ss_obj,执行 Ss 的show方法,结果:S2.show 复制代码 class F1: pass class S1(F1): def show(self): print 'S1.show' class S2(F1): def show(self): print 'S2.show' # 由于在Java或C#中定义函数参数时,必须指定参数的类型 # 为了让Func函数既可以执行S1对象的show方法,又可以执行S2对象的show方法,所以,定义了一个S1和S2类的父类 # 而实际传入的参数是:S1对象和S2对象 def Func(F1 obj): """Func函数需要接收一个F1类型或者F1子类的类型""" print(obj.show()) s1_obj = S1() Func(s1_obj) # 在Func函数中传入S1类的对象 s1_obj,执行 S1 的show方法,结果:S1.show s2_obj = S2() Func(s2_obj) # 在Func函数中传入Ss类的对象 ss_obj,执行 Ss 的show方法,结果:S2.show 错误代码,版本不对
深度优先和广度优先会在爬虫等多个领域进行运用
第一详解:
深度优先算法:
(1)访问初始顶点v并标记顶点v已访问。
(2)查找顶点v的第一个邻接顶点w。
(3)若顶点v的邻接顶点w存在,则继续执行;否则回溯到v,再找v的另外一个未访问过的邻接点。
(4)若顶点w尚未被访问,则访问顶点w并标记顶点w为已访问。
(5)继续查找顶点w的下一个邻接顶点wi,如果v取值wi转到步骤(3)。直到连通图中所有顶点全部访问过为止。
广度优先算法:
(1)顶点v入队列。
(2)当队列非空时则继续执行,否则算法结束。
(3)出队列取得队头顶点v;访问顶点v并标记顶点v已被访问。
(4)查找顶点v的第一个邻接顶点col。
(5)若v的邻接顶点col未被访问过的,则col入队列。
(6)继续查找顶点v的另一个新的邻接顶点col,转到步骤(5)。直到顶点v的所有未被访问过的邻接点处理完。转到步骤(2)。
第二详解:
深度优先是指网络爬虫会从起始页开始,一个链接一个链接跟踪下去,处理完这条线路之后再转入下一个起始页,继续追踪链接,通过下图进行理解:
注:scrapy默认采用的是深度优先算法
A-B-D-E-I-C-F-G-H (递归实现)
广度优先,有人也叫宽度优先,是指将新下载网页发现的链接直接插入到待抓取URL队列的末尾,也就是指网络爬虫会先抓取起始页中的所有网页,然后在选择其中的一个连接网页,继续抓取在此网页中链接的所有网页,通过下图进行理解:
A-B-C-D-E-F-G-H-I (队列实现)