2.爬虫的Python基础

本篇-基础内容部分可参考Python笔记本

基础内容

Python需要强制缩进,利用缩进表示语句块的开始和退出,通常使用4个空格表示每一级缩进。

Python是弱类型语言,当声明变量时不需要声明变量的类型。

Python的for循环只能作用于容器(Python的容器包括了大部分数据结构:数组,列表,元组,集合,字典。),for循环没有以下写法:

for (i=0; i<100; ++i){...}

想要实现上述效果应该用while,比如:

i=0
while i<=100:
    i += 1
print(i) # 101

i=0
while i<=100:
    if i == 6:
        break # 直接跳出当前循环层
    i += 1
print(i) # 6

i=0
while i<=100:
    if i == 6:
        continue # 跳过当前循环层内的一次操作
    i += 1
print(i) 
# 会进入无限循环, 因为在i==6时没有执行+1操作, 最后i=100, 导致永远在循环内

Python一切皆对象,函数也是对象,我们可以将函数作为参数传递,比如分解公式: f ( x ) = 5 x + 100 f(x)=5x+100 f(x)=5x+100 g ( x ) = 5 x g(x)=5x g(x)=5x因此: f ( x ) = g ( x ) + 100 , f ( x ) = f ( g , x ) = 5 x + 100 f(x)=g(x)+100,f(x)=f(g,x)=5x+100 f(x)=g(x)+100,f(x)=f(g,x)=5x+100

def g(x):
	return x*5
# f就是一个高阶函数
def f(g,x):
	return g(x)+100

# 直接写函数名得到的是对象本身,调用需要加括号与参数()
# 比如g就是得到函数本身,g(x)就是调用
print(f(g,100)) #600

匿名函数指的是没有函数名的函数对象,其作用在于减少代码量,正好体现了Python的简洁优美,匿名函数用于简单函数的表达,用关键字lambda开头,在冒号‘:’前是参数,后面则是返回值,举个例子:

#将匿名函数对象赋值给lambdaf,以便进行调用
lambdaf=lambda x,y:x**2+y**2
#等价于
def func(x,y):
    return x**2+y**2

由上看出,匿名函数确实将一个函数简写到1行,调用lambdaf(2,3)等价于调用func(2,3),此外,其类型type(lambdaf)同样是class ‘function’

匿名函数的便捷性更多体现在高阶函数中,因为高阶函数需要以函数作为参数,匿名函数的简洁正好很适合直接写成参数。

Python的字典是键-值对应的,字典可以添加元素,可遍历(字典中的元素顺序不固定):

di={'k1':'v1', 'k2':'v2'}
di['k3']='v3'
di['k4']='v4'

for k in di:
	print(di[k])
"""
v1
v2
v3
v4
"""

for k,v in di.items():
	print(k,v)
"""
k1 v1
k2 v2
k3 v3
k4 v4
"""

字符串是一个数组,其操作有:

string='abcdefg'
# 不能直接修改字符串
try:
    str[0]='x'
except Exception as e:
    print(e)
# 'type' object does not support item assignment

li=list(string)
li[0]='x'
s=''.join(li)
print(s) # xbcdefg
s='-'.join(li)
print(s) # x-b-c-d-e-f-g

# 字符串的切割
s='abc,def,ghi'
p1,p2,p3=s.split(',')
print(p1,p2,p3) # abc def ghi

# 下标访问和切片
s='abcdefg'
print(s[0],s[-1],s[2:5]) # a g cde

关于Python的面向对象,有以下基本内容:

# 用type查看对象类型
print(type([1,2,3])) # <class 'list'>

# 用dir查看属性和方法
print(dir([list]))
"""
['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', 
'__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', 
'__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', 
'__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', 
'__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', 
'__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 
'remove', 'reverse', 'sort']
"""

# 定义类
class A(object):
    def __init__(self,x,y):
        self.x=x
        self.y=y
    def display(self):
        print(self.x,self.y)

a=A(1,2)
a.display() # 1 2

# 继承
class Base:
    def run(self):
        print('base run')

class Tom(Base):
    def run(self):
        print('tom run')

t=Tom()
t.run() # tom run

Python中有鸭子类型的概念:一个对象,如果它看起来像鸭子,行为也像鸭子,我们就认为它是鸭子。鸭子类型是指Python强调接口的泛化,而不在于各种对象间严格的输入输出关系:

def runapi(runner):
    return runner.run()

class R1(object):
    def run(self):
        print('r1 run')

class R2(object):
    def run(self):
        print('r2 run')

r1,r2=R1(),R2()
runapi(r1)
runapi(r2)
# r1 run
# r2 run

文件读取操作如下:

# 传统读文件方式
f=open('text.txt','r')
# 读一行
print(f.readline())
# 读剩下所有
print(f.read())
# 关闭句柄
f.close()

# 自动关闭句柄方式
with open('text.txt','r') as f:
    # readlines不同于readline,readlines返回的是一个列表,每个元素就是一行
    for line in f.readlines():
        print(line)

多线程

进程可以简单的理解为一个可以独立运行的程序单位,它是线程的集合,进程就是有一个或多个线程构成的。而线程是进程中的实际运行单位,是操作系统进行运算调度的最小单位。可理解为线程是进程中的一个最小运行单元。多线程就是指一个进程中同时有多个线程正在执行

在一个程序(进程)中,有很多的操作是非常耗时的,如数据库的读写操作,IO操作等,如果使用单线程,那么程序就必须等待这些操作执行完成之后才能执行其他操作。使用多线程,可以将耗时任务放在后台继续执行,同时执行其他操作。


多线程是异步的,多线程不代表真的是几个线程是在同时进行,实际上是系统不断地在各个线程之间来回的切换(因为系统切换的速度非常的快,所以给我们在同时运行的错觉)


当运行一个程序,就启动了一个进程。凡是用于完成操作系统的各种功能的进程就是系统进程,而所有由我们启动的进程都是用户进程。同理,多进程就是指计算机同时执行多个进程,比如同时运行多个软件。

关于多进程与多线程的比喻:

  • 单进程单线程:一个人在一个桌子上吃菜。
  • 单进程多线程:多个人在同一个桌子上一起吃菜。
  • 多进程单线程:多个人每个人在自己的桌子上吃菜。

多线程的问题是多个人同时吃一道菜的时候容易发生争抢,例如两个人同时夹一个菜,一个人刚伸出筷子,结果伸到的时候已经被夹走菜了。此时就必须等一个人夹一口之后,在还给另外一个人夹菜,也就是说资源共享就会发生冲突争抢。

对于 Windows 系统来说,"开桌子"的开销很大,因此 Windows 鼓励大家在一个桌子上吃菜。因此 Windows 多线程学习重点是要大量面对资源争抢与同步方面的问题。

对于 Linux 系统来说,"开桌子"的开销很小,因此 Linux 鼓励大家尽量每个人都开自己的桌子吃菜。这带来新的问题是:坐在两张不同的桌子上,说话不方便。因此,Linux 下的学习重点是研究进程间通讯的方法。


可以做个实验:创建一个进程,在进程中往内存写若干数据,然后读出该数据,然后退出。此过程重复 1000 次,相当于创建/销毁进程 1000 次。测试结果是:

  • UbuntuLinux:耗时 0.8 秒 ,Windows7:耗时 79.8 秒,两者开销大约相差一百倍。

某些服务器框架依靠大量创建进程来干活,甚至是对每个用户请求就创建一个进程,这些服务器在 Windows 下运行的效率就会很差。这可能也是Linux 服务器远远多于 Windows 服务器的原因。


关于并行,并发和高并发:

  • 并行:多个CPU实例或多台机器同时执行一段处理逻辑,是真正的同时;
  • 并发:通过CPU调度算法,让用户看上去同时执行,实际上CPU操作层面不是真正的同时;
  • 高并发:是一种系统运行过程中遇到的一种"短时间内遇到大量操作请求"的情况,主要发生在web系统集中大量访问或者socket端口集中性收到大量请求(例如:12306的抢票情况;天猫双十一活动)。该情况的发生会导致系统在这段时间内执行大量操作,例如对资源的请求,数据库的操作等。

高并发与并发需要对同一个资源进行操作,所以不能用完全并行的方式解决


多线程与高并发的关系:多线程在高并发问题中的作用就是充分利用计算机资源,使计算机的资源在每一时刻都能达到最大的利用率,不至于浪费计算机资源使其闲置。

多线程的简单实例如下:

import threading

def thread_func(x):
    print(x*100)

# 创建5个线程
threads=[]
for i in range(5):
    threads.append(threading.Thread(target=thread_func,args=(100,)))

# 启动线程
for thread in threads:
    thread.start()
# 等待线程结束
for thread in threads:
    thread.join()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值