感谢前辈们的指导,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默认采用的是深度优先算法

python面向对象基础_第1张图片

python面向对象基础_第2张图片

A-B-D-E-I-C-F-G-H (递归实现)

广度优先,有人也叫宽度优先,是指将新下载网页发现的链接直接插入到待抓取URL队列的末尾,也就是指网络爬虫会先抓取起始页中的所有网页,然后在选择其中的一个连接网页,继续抓取在此网页中链接的所有网页,通过下图进行理解:python面向对象基础_第3张图片

A-B-C-D-E-F-G-H-I (队列实现)