python爬虫开发教程-02-学习python简单语法

上一篇  python爬虫开发教程-01-环境搭建

我们来看看其它网站的学习流程

来源:Python3 教程 | 菜鸟教程

Python教程 - 廖雪峰的官方网站

可以跟着流程走一遍,但是还不够高效。

简单看一下上面的目录,入门一种编程语言,究竟学的是什么。我记得我第一种编程语言,是visual basic 6.0

而第一次系统学一门语言。是C语言,在我看来,c语言比我学过的java python php js ts shell sql,不知道要高到哪里去了。我们不用关注那么多细节,入门最快的一种方法是写一个排序算法。因为声明变量,声明和使用列表,循环,判断,全都用到了。所以我也会从这里入手,教大家快速上手python,看完这篇文章后,再回过头来,去看我上面发的链接。

那么开始吧。打开我们的pycharm软件,新建一个项目innerSort

 点击右下角的create,出现下列界面

 右键项目名innerSort,创建新文件

回车,如下:

将下面代码拷贝到代码编辑区

A=[3,2,1]
j=0
temp=0
n=len(A)
for i in range(1,n):
    j=i
    temp=A[i]
    while(j>0 and A[j-1]>temp):
        A[j]=A[j-1]
        j=j-1
    A[j]=temp
print(A)

效果如下:

按ctrl+shift+F10执行,结果如下:

执行完毕正常了,再删掉,自己手动敲一遍,里面的空格是按TAB键产生的

现在回到这段代码,

A=[3,2,1]

创建了一个数组对象,里面有三个元素3,2,1,A=[3,2,1],好比[3,2,1]是一个一辆车,车名称就叫A。

一个数组我们关注的是

1.如何创建数组

2.如何增加一个元素

3.如何访问数组的元素

4.如何获取数组长度

5.如何修改数组的值

我们在innerSort项目内创建一个新文件test,用来测试用法

1.如何创建一个数组

创建了一个最简单的空数组

2.如何增加一个元素

就像一列火车,A.append表示A这列火车带有挂车厢的方法,我直接往后面挂一个车厢,车厢里的值是3

3.如何访问数组的元素

我们使用print()方法打印出来了A数组,如果打印第一个元素,则使用下面的方法

就把3打印成功了,而为什么0是第一个呢,按我C语言的理解,一个数组会分配是连续的内存地址,所以我们只要知道第一个元素的内存地址,加上每个元素的内存大小,就能随机访问所有的元素,比如三个元素的数组,每个元素的大小是10,数组的内存地址是100,那么第一个元素也就是数组内存地址,也就是100+0*10=100,同理第二个是100+1*10=110,第三个元素是100+2*10=120,这样。所以约定成俗,第一个元素我们就用下标0去访问。

看到第三行代码,为什么append()方法用起来需要A.append,而print()方法可以直接使用?

因为数组是一个对象,对象含有自己的方法,要使用该方法,就是得用点号操作符去操作该变量名A。

而print(),我初步判断它是一个全局方法,也就是全局对象X,然后X.print(),由于是全局对象,所以省略了这个.号

但是这样解释又太不准确,因为我也可以直接解释print()是一个全局方法,不用声明就可以使用。

最后我能给出的一个解释就是,print()是python内置函数。

4.如何获取数组长度

len()方法

5.如何修改数组的值

接下来看

j=0
temp=0

就是声明了两个变量 j temp,并赋值0,print(j,temp)可以打印这两个变量,如下

n=len(A)

len()也相当于内置方法,输出数组长度,也就是存储的元素个数

 接下来看

for i in range(1,n):

首先看这个range()方法,传入了两个参数,关于range()本质,我认识有限所以无法阐释清除,range的效果有点类似迭代器。

为什么range不是迭代器?range到底是什么类型?

使用list(range(1,3))可以生成一个数组[1,2],如下

使用list(range(3))可以生成一个[0,1,2]数组,各位可以尝试一下,相当于左开右闭区间

可以使用for 循环遍历这个数组,如下

接下来往下看

    j=i
    temp=A[i]

就是把i复制给j,把A数组的第i+1个元素(因为A[0]是第一个,A[1]是第二个)赋值给temp变量。

这里的=与我们数学上的=不同。

数学上是设y=2x+1 y=3x,列一个方程,求出x,y的值,这里的“=”相当于等价的意思,对应python的符号是“==”,两个等号

而python中的“=”表示赋值操作,也就是,x=1,是把右边的值,赋给左右,相当于复制右边的值,粘贴给左边的变量。

要更深一点,就是1是一个对象/数值,内存地址用变量x存储。使用内存地址就能操作该对象/值。

接下来看

  while(j>0 and A[j-1]>temp):

while表示循环过程,我们来做一个测试,打印输出1到100,怎么做(代码最好自己手打一遍,因为里面很多细节,可能对着敲都不能正确执行并得到结果,这里不提供源码供大家复制)

while (循环条件):

               循环体

当循环条件的结果是"真",则执行一遍循环体,对应上图的代码,就是执行到第四行的时候,就表示一遍执行完毕,然后继续检查循环条件结果是否为"真"

如果为真,继续执行循环体,然后继续检查循环条件……

如果为假,则结束循环

这里i=1,满足循环条件,则打印1,然后i=2,检查也满足循环条件……

直到i=100,执行第三行的打印操作,然后执行第四行i自加1,现在i=101,然后回到开头,检查循环条件,不满足i<=100的条件,于是退出循环,所以只打印出来1到100。

如果要同时满足两个条件,需要怎么做,如下图:

这里的if后面跟着的括号,也是循环条件,同while括号的内容

使用循环需要注意的一点,一定要有退出循环的可能

比如下面的代码,结束不了,就会有问题

while True虽然不会自己退出,我们需要使用break主动退出

接下来往下看

 A[j]=A[j-1]
 j=j-1

把数组后面的值赋给前面的

然后j的值减一

这里有一点是python比较特别的地方,就是它没有括号,你是如何判断那些代码是循环体呢,就是靠缩进

红色部分是对齐的(按TAB键对齐),就是for循环体中的内容,蓝色方框内的内容,就属于while循环体

最后一部分,打印数组A,整个代码语法部分就讲解完毕了。

接下来我们想知道,为什么这串代码,可以实现排序的功能,这个代码的逻辑,叫插入排序算法。你可以理解成算法就是协议,写出来的代码,就是其实现。

其实讲现实中排队的例子,可能交换排序更直观一点,但是写都写到这里了,就讲插入排序把

有3个数3,2,1 如何按从小到大的顺序排列,插入排序的思想如下:

考虑第1个数3,找到3在前面序列的实际位置,将3放到该位置上

由于3前面没有数字,所以不做任何操作

考虑第二个数字2.找到2在前面的序列的实际位置,将2放在该位置上

2前面的序列就是有3,2比3小,所以3要往它前面挪动(前面指下标增加的方向)所以A数组变成这样

331,然后把2放在最后的位置,于是数组变成231

然后考虑第三个数1,1比3小,于是3要往前面挪,变成

233,然后1和2比,1也比2小,变成

223,最后把1放到最后的位置

变成123。

感觉说不清楚,至少得配个动图大家能更好的理解

那么总结一下把,插入排序的核心就是,有一个大小为i-1的有序序列n1,n2,n3,……ni-1

(翻译成白话就是,现在有一个大小为2的有序序列2,3,需要把第三个数1,插入到这个有序序列中,结果就是这三个数有序)

这时需要把ni插入到这个有序序列中,于是ni需要和ni-1相比,如果ni比它前面的数小,就把ni-1往前挪一位

(翻译一下就是,1比3小,于是3要往前移动一位,变成233,中间的3不变,当然你可以先临时把1放在这个位置,因为这个位置不是1的最终位置,还是要看左边的数是不是也大于1,为了节省操作,就没有让数组的状态变成213)

然后ni继续和ni-2相比,如果仍旧比ni-2小,则ni-2的值挪动到ni-1的位置上,ni再与ni-3相比,最后一直到n1,经过这一系列操作后,就得到了i个有序序列。

但是整个数组的元素可能大于i个,这是问题就变成了如何将ni+1,插入到这i个有序序列中

所以同理,有序序列n1,n2,n3,……ni-1也是这么来的。

如果还是不清楚插入排序的原理,我给大家一个教科书的解释吧

我觉得比我的废话讲的清晰明了,所以python编程语言什么时候出一个教科书?

这里我给出一个图解

一个有序数列 7 9 12如下

这时新增一个数8,如何才能让四个数有序

8先和12比

发现比12小,于是12要自己把空位挪出来

但是在计算机中,做出这个操作需要有两步

1.A[3]=A[2]

2.A[2]=null

为了让程序执行的操作最少,我们省略第二步操作

12比完了,继续移动8,和9比

发现8还是比9小,于是做同样的操作,把9往右移动

继续和7比,发现比7大,于是不移动了,8直接插入进来

就完成了4个数的插入排序

1.这个操作的前提是,待插入的序列必须有序,所以你要得到7 9 12,你得先从1个数开始排,假如刚开始只有一个9,9本身就是有序的,新增一个7,就是9和7之间的插入排序,得到7、9。然后在把12插入到这个有序数列中。

2.假设总共需要排列的数是n,当前子序列长度是m,需要交换的最大趟数是m,所以每次新增一个数,总共最大的交换次数就是n(n-1)/2,也就是n的平方的复杂度。为了减小时间复杂度,我们不用每次都要一个一个比,然后交换,直接用折半查找,找到8最终的位置,然后直接插入,这个方法叫折半插入排序。

扩展一下关键词,有兴趣的可以自行搜索

线性表:(顺序表,链表)

时间复杂度,空间复杂度

排序的稳定性

插入排序,交换排序,选择排序

内部排序,外部排序

以及最核心,数据结构是什么,算法又是什么。

现在我们得到了一个插入排序算法代码,但是就像我们使用的文具一样,我们想有一个文具盒,带着这个文具盒,把这堆代码装进去,于是我们得到了函数。

先全选

然后按TAB键,得到下面的样子(按shift+tab可以缩进回去)

在上面加上一行代码,如下

这就完成一个打包(区别于前端的打包)过程,把这个排序的功能,定义成了一个函数insertSort,

然后我们只需要调用这个函数,就能实现排序功能,按crtl+shift+F10运行,结果如下:

 这个函数只能对321进行排序,我们也想对54321排序,可以这么做

源码:

def insertSort(A):
    j = 0
    temp = 0
    n = len(A)
    for i in range(1, n):
        j = i
        temp = A[i]
        while (j > 0 and A[j - 1] > temp):
            A[j] = A[j - 1]
            j = j - 1
        A[j] = temp
    print(A)
A=[5,4,3,2,1]
insertSort(A)

可以看到我们在insertSort()括号里面增加了一个A,代表局部变量

然后在函数体外声明了一个全局变量A,这个A和函数体内的A不是同一个

然后传入到函数insertSort()中。

这里我们做两个测试:

出现这个结果,是跟变量作用域有关

一个变量名,会先从函数体内查找,查找不到,再会去函数体外查找该变量。

所以上图的结果是5,4,3,2,1

如下图

在函数内查找到了,则不会去函数体外查找

有办法找函数体外的吗,有办法,强制声明A为全局变量,如下

用global修饰的变量是全局变量,在函数体内修改该变量的值,打印函数体外的A,发现值改变了。

各位可以去掉第二行的gloal A,然后执行看看结果

说明函数变量声明中的A就是一个符号而已,不会检测A的变量类型。

讲完了函数,我们在讲讲类。

class Cat():
    def __init__(self):
        self.name="小猫"
    def sound(self):
        print(self.name+"喵喵叫")
oneCat=Cat()
oneCat.sound()

class Cat定义了一个类,一个类有属性name,还有方法sound。

方法想要访问属性,需要使用self.name。

oneCat=Cat(),表示用类实例化了一个对象,对象名称叫oneCat。然后该对象就可以使用类Cat创建的属性和方法。

上面代码运行结果如下

那如果我们想要在方法中使用方法呢,如下:

同样要加上self关键词

回到代码中来,我可以做如下修改

我修改了对象的name属性,这时候就出错了,小狗不是汪汪叫么,所以为了防止有人修改某些属性导入意料之外的错误,我们限定name为私有变量,如下

加上两个横线后,类外部就无法修改了,甚至无法访问

那组合在一起,发生了什么?

看到这里,是不是很疑惑,不是不能访问以两个横线标志的私有变量__name么。怎么成功访问了?

请往下看

原来这个在类里面定义的私有变量__name,python解释器会自动补全成为_Cat__name。所以我直接访问__name,是不存在这个属性的。

而oneCat.__name="小狗",这一行代码则帮我们新建了一个属性,赋值为小狗,所以

输出结果变成了小狗。

既然可以新增属性,那么可以新增方法吗,我们来试一下

跟新增属性用法一样。

那么从猫到汤姆猫,该如何实现呢(当然TomCat也是一个Web应用服务器)

只要使用一行代码,在创建TomCat类的时候,将Cat当作参数传递进去。

这里Cat我们叫做父类,TomCat叫做子类,有父类产生子类的过程我们叫继承。

当然我们的汤姆猫,我们可以重写名称和方法

小猫和汤姆猫,都喜欢吃饭的时间发出声音,如下

这种行为叫多态。更多的解释请参考:继承和多态 - 廖雪峰的官方网站

我们是在test文件下编写的代码,现在我们需要创建一个Cat.py文件,并把我们的有关Cat类的代码复制到里面

class Cat():
    def __init__(self,name):
        self.__name=name
    def sound(self):
        print(self.__name+"喵喵叫")
oneCat=Cat("大猫")
oneCat.sound()

那么假如我需要在test文件中使用这个大猫的类,该如何去做

我们先删除掉下面两行代码

然后回到test界面

我们可以使用import语句导入Cat模块,这个模块就是Cat.py文件。

当然我们也可以使用下面的写法

采用from  import写法可以不用写Cat模块名,上一张图出现了Cat.Cat,第一个Cat是模块名称,第二个Cat是我声明的一个类。

所以尽量取不同的名称。各位可以在Cat.py文件中再增加一些函数,变量,类等,然后看看怎么在test中调用声明的这些变量、方法。这里我就不演示了。

还是演示一下吧

Cat.py

class Cat():
    def __init__(self,name):
        self.__name=name
    def sound(self):
        print(self.__name+"喵喵叫")
#函数
def eatWhat():
    print("吃小鱼干")
#变量
weight="5kg"

test.py

from Cat import *
oneCat=Cat("大猫")
oneCat.sound()
eatWhat()
print(weight)

结果如下

各位可以尝试改回import Cat,看看test.py应该如何修改

最后回忆一下我们是如何创建test.py和inserSort.py的,我们创建了一个项目innerSort,在该项目下创建了两个文件。这里我要提到一个“包”的概念。

比如我写的猫的中华田园猫,国外也有一个程序员,写的是品种猫,如下

class Cat():
    def __init__(self,name):
        self.__name=name
    def sound(self):
        print(self.__name+" mews")

现在我的test里面想要引入这两个类,应该这么写

import Cat
import EuramericanCat
cat1=Cat.Cat("小猫")
cat2=EuramericanCat.Cat("little cat")
cat1.sound()
cat2.sound()

结果如下

那么假如国外的程序员,模块名称也叫Cat,也就是文件名称也叫Cat.py,这时候test.py里的代码应该怎么写呢?

这时我们借助“包”也就是package,来解决这个命令冲突的问题,如下

回车后如下:

将EuramericanCat.py移动到Eur包下

操作方式就是鼠标拖动该项到上面,然后点击Refactor,效果如下

选择EuramericanCat.py后,按SHIFT+F6修改文件名为Cat(也可直接鼠标点击该项,然后右键菜单中选择Refactor选项)

结果如下

那么现在test.py代码可以这这样编写

也可以这样写

总结一下,看如下两个例子

import agent.base
a=agent.base.Agent()



from agent.base import Agent
a = Agent()

import agent.base 可以翻译成 import agent.base.py 将文件base.py导入进来,这个文件位于agent文件夹下, base.py也对应模块名,最终你要使用Agent类,则每次使用Agent都需要写完整Agent类在那个文件夹下,哪个模块(文件)内

所以为了方便,可以换成第二种写法:

from agent.base import Agent,可以翻译成,从agent.base.py导入Agent类,导入完毕之后抹去了命名空间的信息,因此使用的时候直接使用Agent,缺点是假如另一个类同样也叫Agent,但是位于不同的模块,则会造成命名冲突,a = Agent(),这个Agent是哪个模块的Agent.所以你也可以这样改

from agent.base import Agent as Agent1,然后调用的时候 a=Agent1()

除此之外,还有一种import方式, base是模块名,base.py,调用的时候必须加上模块名

from agent import base 

a=base.Agent()

 看到这里后,请再次浏览一遍网站上提高的python教程,这时候你应该游刃有余了吧

Python 基础教程

Python教程

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值