Python面试题(面试部分)

一、什么是ajax?

  • AJAX = 异步 JavaScript 和 XML
  • ajax是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术。
  • ajax是一种用于快速创建动态网页的技术。通过在后台与服务器进行少量数据交换。ajax可以使网页实现异步更新。

二、ajax的优缺点:

- 优点:
1、最大的一点是页面无刷新,用户的体验非常好。   
2、使用异步方式与服务器通信,具有更加迅速的响应能力。   
3、可以把以前一些服务器负担的工作转嫁到客户端,利用客户端闲置的能力来处理,减轻服务器和带宽的负担,节约空间和宽带租用成本。并且减轻服务器的负担,ajax的原则是“按需取数据”,可以最大程度的减少冗余请求,和响应对服务器造成的负担。   
4、基于标准化的并被广泛支持的技术,不需要下载插件或者小程序。   
5、ajax可使因特网应用程序更小、更快,更友好。
- 缺点:
1、ajax不支持浏览器back按钮。   
2、安全问题 AJAX暴露了与服务器交互的细节。   
3、对搜索引擎的支持比较弱。   
4、破坏了程序的异常机制。   
5、不容易调试。

三、什么是进程、线程、协程?以及它们的优缺点?

进程: 资源分配的最小单位 ,资源消耗大, 系统整体开销大, 数据通信不方便 

线程: 程序执行的最小单位,资源消耗小, 可共享数据。上下文开销大。 按时间片强制切换,
不够灵活 。

协程: 内存开销更小, 上下文切换开销更小。可根据事件切换, 更加有效的利用 CPU

四、什么是HTTP协议?他有哪些特点?

  • 超文本传输协议(HTTP,HyperText Transfer Protocol)是互联网上应用最为广泛的一种网络协议。
  • HTTP 协议的主要特点可概括如下:
    1、支持客户 /服务器模式。
    2、.简单快速:客户向服务器请求服务时,只需传送请求方法和路径。请求方法常用
    的有 GET、HEAD 、POST。每种方法规定了客户与服务器联系的类型不同。由于
    HTTP 协议简单,使得 HTTP 服务器的程序规模小,因而通信速度很快。
    3、灵活: HTTP 允许传输任意类型的数据对象。正在传输的类型由 Content-Type
    加以标记
    4、无连接:无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请
    求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。
    5.无状态: HTTP 协议是无状态协议。无状态是指协议对于事务处理没有记忆能力。
    缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次
    连接传送的数据量增大。另一方面,在服务器不需要先前信息时它的应答就较快。

五、解释下 Http 请求头和常见响应状态码

请求头:

1、Accept: 指浏览器或其他客户可以接爱的 MIME 文件格式。可以根据它判断并返回

适当的文件格式。

**2、Accept-Charset :**指出浏览器可以接受的字符编码。英文浏览器的默认值是

ISO-8859-1.

**3、Accept-Language :**指出浏览器可以接受的语言种类,如 en 或 en-us ,指英语。

**4、Accept-Encoding :**指出浏览器可以接受的编码方式。编码方式不同于文件格式,

它是为了压缩文件并加速文件传递速度。浏览器在接收到 Web 响应之后先解码,

然后再检查文件格式。

**5、Cache-Control :**设置关于请求被代理服务器存储的相关选项。一般用不到。

**6、Connection :**用来告诉服务器是否可以维持固定的 HTTP 连接。 HTTP/1.1 使用

Keep-Alive 为默认值,这样,当浏览器需要多个文件时 (比如一个 HTML 文件和相

关的图形文件 ),不需要每次都建立连接。

**7、Content-Type :**用来表名 request 的内容类型。可以用 HttpServletRequest 的

getContentType() 方法取得。

**8、Cookie :**浏览器用这个属性向服务器发送 Cookie 。Cookie 是在浏览器中寄存的小

型数据体,它可以记载和服务器相关的用户信息,也可以用来实现会话功能。

状态码:

状态代码有三位数字组成,第一个数字定义了响应的类别,且有五种可能取值:

**1xx:**指示信息–表示请求已接收,继续处理

**2xx:**成功–表示请求已被成功接收、理解、接受

**3xx:**重定向–要完成请求必须进行更进一步的操作

**4xx:**客户端错误–请求有语法错误或请求无法实现

**5xx:**服务器端错误–服务器未能实现合法的请求

常见状态代码、状态描述、说明:

常见状态码状态描述说明
200OK客户端请求成功
400Bad Request客户端请求有语法错误,不能被服务器所理解
401Unauthorized请求未经授权,这个状态代码必须和 WWW-Authenticate
403Forbidden服务器收到请求,但是拒绝提供服务
404Not Found请求资源不存在, eg:输入了错误的 URL
500Internal Server Error服务器发生不可预期的错误
503Server Unavailable服务器当前不能处理客户端的请求, 一段时间后可能恢

六、http请求包含哪三个部分?http响应哪三个部分?

请求:

1.请求方法URI协议/版本

2.请求头(Request Header)

3.请求正文

响应:

1.状态行

2.响应头(Response Header)

3.响应正文

七、http的三次握手和四次挥手

官方解释:

三次握手:

**第一次握手:**客户端发送了一个带有SYN(建立连接)的Tcp报文到服务器,这个三次握手中的开始。表示客户端想要和服务端建立连接。

**第二次握手:**服务端接收到客户端的请求,返回客户端报文,这个报文带有SYN(建立连接)和ACK(确认)标志,询问客户端是否准备好。

**第三次握手:**客户端再次响应服务端一个ACK(确认),表示我已经准备好。

四次挥手:

**第一次握手:**TCP发送一个FIN(结束),用来关闭客户到服务端的连接。

**第二次握手:**服务端收到这个FIN,他发回一个ACK(确认),确认收到序号为收到序号+1,和SYN一样,一个FIN将占用一个序号。

**第三次握手:**服务端发送一个FIN(结束)到客户端,服务端关闭客户端的连接。

**第四次握手:**客户端发送ACK(确认)报文确认,并将确认的序号+1,这样关闭完成。

类比解释:

三次握手:

用打电话类比的话就是:
小明拨打小红的电话
小红按下通话键并说了声,喂 (一次握手)
小明听到小红的回应,也说了声,喂 (二次握手)
小红接收到小明的回应 (三次握手)

四次挥手:

还是用小明和小红打电话来类比:
小明:我这没事儿了,你还有事儿吗? (1次挥手)
小红:我也没事儿了,你确定没事儿了吗? (2次挥手)
小红:我要挂电话了。 (3次挥手)
小明:好吧,你挂吧。 (4次挥手)

八、爬虫框架的运行机制

工作原理:
工作原理
工作原理

Scrapy运行流程大概如下:

  1. 引擎从调度器中取出一个链接(URL)用于接下来的抓取
  2. 引擎把URL封装成一个请求(Request)传给下载器
  3. 下载器把资源下载下来,并封装成应答包(Response)
  4. 爬虫解析Response
  5. 解析出实体(Item),则交给实体管道进行进一步的处理
  6. 解析出的是链接(URL),则把URL交给调度器等待抓取

九、Redis的数据类型有哪些?

类型简介特性场景
String(字符串)二进制安全可以包含任何数据,比如jpg图片或者序列化的对象,一个键最大能存储512M
Hash(字典)键值对集合,即编程语言中的Map类型适合存储对象,并且可以像数据库中update一个属性一样只修改某一项属性值(Memcached中需要取出整个字符串反序列化成对象修改完再序列化存回去)存储、读取、修改用户属性
List(列表)链表(双向链表)增删快,提供了操作某一段元素的API1,最新消息排行等功能(比如朋友圈的时间线) 2,消息队列
Set(集合)哈希表实现,元素不重复1,添加、删除,查找的复杂度都是O(1) 2,为集合提供了求交集、并集、差集等操作1,共同好友 2,利用唯一性,统计访问网站的所有独立ip 3,好用推荐时,根据tag求交集,大于某个阈值就可以推荐
Sorted Set(有序集合)将Set中的元素增加一个权重参数score,元素按score有序排列数据插入集合时,已经进行天然排序1,排行榜 2,带权重的消息队列

十、正则基本规则

单个字符:

普通字符:就是一对一的完全匹配
[]:中间的任意一个字符
	[a-z]:表示a到z的任意字符
	[0-9]:表示0到9的任意字符
	[^abc]:除abc之外的字符
. :匹配'\n'以外的任意字符
\d:所有的数字字符,等价于[0-9]
\D:所有的非数字字符,等价于[^0-9]
\w:所有的数字、字母、中文、下划线等 (就是字的意思)
\W:\w之外的所有字符
\s:所有的空白字符,如:空格、\t、\n、\r
\S:\s之外的所有字符
\b:词边界,如:开头、结尾、标点、空格等
\B:非词边界

次数控制:

*:前面的字符可以是任意次
+:前面的字符至少出现一次
?:至多一次,0次或1次
{m}:匹配固定的m次
{m,}:至少m次
{m,n}:m到n次

边界限定:

^:以指定内容开头
$:以指定内容结尾

    import re
    
    # 以指定内容开头
    # c = re.compile(r'^abc')
    # 以指定内容结尾
    # c = re.compile(r'abc$')
    # 同时限制开头和结尾
    c = re.compile(r'^abc$')
    
    s = c.search('abc')
    
    if s:
        print('ok')
        print(s.group())

分组匹配:

|:表示或,具有最低的优先级

():用于表示一个整体,可以确定优先级

    import re
    
    # | 表示或,具有最低的优先级
    # () 用于表示一个整体,可以确定优先级
    c = re.compile(r'a(hello|world)d')
    
    s = c.search('aworldd')
    
    if s:
        print('ok')
        print(s.group())

十一、MySQL分区

**range分区:**基于属于一个给定连续区间的列值,把多行分配给分区。

**list分区:**类似于按RANGE分区,区别在于LIST分区是基于列值匹配一个离散值集合中的某个值来进行选择。

**hash分区:**基于用户定义的表达式的返回值来进行选择的分区,该表达式使用将要插入到表中的这些行的列值进行计算。这个函数可以包含MySQL 中有效的、产生非负整数值的任何表达式。

**key分区:**类似于按HASH分区,区别在于KEY分区只支持计算一列或多列,且MySQL服务器提供其自身的哈希函数。必须有一列或多列包含整数值。

十二、Python优化

当我们提到一门编程语言的效率时:通常有两层意思,第一是开发效率,这是对程序员而言,完成编码所需要的时间;另一个是运行效率,这是对计算机而言,完成计算任务所需要的时间。编码效率和运行效率往往是鱼与熊掌的关系,是很难同时兼顾的。不同的语言会有不同的侧重,python语言毫无疑问更在乎编码效率,life is short,we use python。

Python效率低得原因:

  • 第一:python是动态语言
  • 第二:python是解释执行
  • 第三:python中一切都是对象 ,每个对象都需要维护引用计数,增加了额外的工作。
  • 第四:python GIL ,因为GIL,python中的多线程并不能真正的并发 。
  • 第五:垃圾回收 ,python采用标记和分代的垃圾回收策略,每次垃圾回收的时候都会中断正在执行的程序(stop the world),造成所谓的顿卡。

Python优化策略:

  • 基于profile的优化:

第一:减少函数的调用层次: 每一层函数调用都会带来不小的开销,特别对于调用频率高,但单次消耗较小的calltree,多层的函数调用开销就很大,这个时候可以考虑将其展开。

**第二:优化属性查找:**python 的属性查找效率很低,如果在一段代码中频繁访问一个属性(比如for循环),那么可以考虑用局部变量代替对象的属性。

第三:关闭GC:
第四:setcheckinterval: 如果程序确定是单线程,那么修改checkinterval为一个更大的值 。

第五:使用__slots__: slots最主要的目的是用来节省内存,但是也能一定程度上提高性能。

  • python C扩展:

C扩展就是把部分python代码用C或者C++重新实现,然后编译成动态链接库,提供接口给其它python代码调用。大约比Python快10倍左右。

第一:注意引用计数的正确管理

第二:C扩展与多线程

**第三:C扩展应用场景:**仅适合与业务代码的关系不那么紧密的逻辑,如果一段代码大量业务相关的对象 属性的话,是很难C扩展的

  • beyond CPython:
    • cython

Cython的主要目的是加速python的运行效率,但是又不像上一章节提到的C扩展那么复杂。
Cython是python语言的超集,增加了对C语言函数调用和类型声明的支持。从这个角度来看,cython将动态的python代码转换成静态编译的C代码,这也是cython高效的原因。

  • pypy

pypy大概比cpython要快3到5倍! pypy占用的内存更少,而且支持stackless,基本等同于协程。
pypy的缺点在于对C扩展方面支持的不太好,需要使用CFFi来做binding。对于使用广泛的library来说,一般都会支持pypy,但是小众的、或者自行开发的C扩展就需要重新封装了。

十三、Python高并发

1.Nginx要做负载均衡

2.程序层面做多线程,锁等机制

3 .数据库层面处理

4.服务器配置要尽量高

5.可能还有其他的方案

十四、数据库事务的四大特性以及事务的隔离级别

事物特性:

⑴ 原子性(Atomicity)

原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚 。

⑵ 一致性(Consistency)

一致性是指事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态。

⑶ 隔离性(Isolation)

持久性是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。

不考虑的隔离性出现的问题:

1,脏读

脏读是指在一个事务处理过程里读取了另一个未提交的事务中的数据。

2,不可重复读

不可重复读是指在对于数据库中的某个数据,一个事务范围内多次查询却返回了不同的数据值,这是由于在查询间隔,被另一个事务修改并提交了。

3,虚读(幻读)

幻读和不可重复读都是读取了另一条已经提交的事务(这点就脏读不同),所不同的是不可重复读查询的都是同一个数据项,而幻读针对的是一批数据整体(比如数据的个数)。

四种隔离级别:

① Serializable (串行化):可避免脏读、不可重复读、幻读的发生。

② Repeatable read (可重复读):可避免脏读、不可重复读的发生。

③ Read committed (读已提交):可避免脏读的发生。

④ Read uncommitted (读未提交):最低级别,任何情况都无法保证。

十五、 python 网络爬虫所用到的网络数据包

requests 、urllib 、urllib2 、httplib2

十六、 python 网络爬虫所用到的解析数据包

BeautifulSoup 、pyquery 、Xpath 、lxml

十七、爬虫爬取数据的过程中, 遇到的防爬虫问题的解决方案

1、通过 headers 反爬虫:解决策略,伪造 headers

2、动态变化去爬取数据,模拟普通用户的行为

3、基于动态页面的反爬虫:跟踪服务器发送的 ajax 请求,模拟 ajax 请求

十八、如果对方网站可以反爬取,封 ip 怎么办?

1、放慢抓取速度,减小对于目标网站造成的压力。但是这样会减少单位时间内的抓取量

2、第二种方法是通过设置代理 IP 等手段,突破反爬虫机制继续高频率抓取。但 是这样需要多个稳定的代理 IP

代理 IP 可以搜索到免费的,但是可能不太稳定,也有收费的,但是不一定划算, 也可能不是长久之计

3、普通的基于 ADSL拨号的解决办法

通常,在抓取过程中遇到禁止访问,可以重新进行 ADSL 拨号,获取新的 IP, 从而可以继续取。 但是这样在多网站多线程抓取的时候, 如果某一个网站的抓取被禁止了, 同时也影响到了其他网站的抓取,整体来说也会降低抓取速度。

4、另一种基于ADSL拨号的解决方法

假设有 A、B 两台可以进行 ADSL 拨号的服务器。爬虫程序在 C 服务器上运行, 使用 A 作为代理访问外网,如果在抓取过程中遇到禁止访问的情况,立即将代 理切换为 B,然后将 A 进行重新拨号。 如果再遇到禁止访问就切换为 A 做代理, B 再拨号,如此反复。

十九、是否了解 Python中的单例模式。有哪几种实现?

单例模式是一种常用的软件设计模式。 在它的核心结构中只包含一个被称为单例类的特殊类。通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约系统资源。 如果希望在系统中某个 类的对象只能存在一个,单例模式是最好的解决方案。

单例模式的要点有三个; 一是某个类只能有一个实例; 二是它必须自行创建这个实例;三是它必须自行向整个系统提供这个实例

单例模式的实现方法:

方法一 : __new__方法

    class Singleton(object):
    	def __new__(cls, *args, **kwargs):
    		if not hasattr(cls, '_instance'):
    			orig = super(Singleton, cls)
    			cls._instance = orig.__new__(cls, *args, **kwargs)
    		return cls._instance
    class MyClass(Singleton):
    	a = 1
        
    one = MyClass()
    two = MyClass()
    
    #one和 two 完全相同 , 可以用 id(), ==, is 检测 print id(one) # 29097904
    print id(two) # 29097904
    print one == two # True
    print one is two # True

方法二:__metaclass__(元类)

    class Singleton2(type):
    	def __init__(cls, name, bases, dict):
    		super(Singleton2, cls).__init__(name, bases, dict)
    		cls._instance = None
    	def __call__(cls, *args, **kwargs):
    		if cls._instance is None:
    			cls._instance = super(Singleton2, cls).__call__(*args, **kwargs)
    		return cls._instance
    class MyClass2(object):
    	__metaclass__ = Singleton2
    	a = 1
        
    one = MyClass2()
    two = MyClass2()
    
    print id(one) # 31495472
    print id(two) # 31495472
    print one == two # True
    print one is two # True

方法三:装饰器

def singleton(cls, *args, **kwargs):
	instances = {}
	def _singleton():
		if cls not in instances:
			instances[cls] = cls(*args, **kwargs)
		return instances[cls]
    return _singleton
@singleton
class MyClass3(object):
	a = 1
    
one = MyClass3()
two = MyClass3()

print id(one) # 29660784
print id(two) # 29660784 print one == two # True
print one is two # True

二十、Python垃圾回收机制?

1、引用计数:

python内部使用引用计数,来保持追踪内存中的对象,Python内部记录了对象有多少个引用,即引用计数,当对象被创建时就创建了一个引用计数,当对象不再需要时,这个对象的引用计数为0时,它被作为垃圾回收。

2、循环垃圾回收器:

当两个对象相互引用时,确保释放循环引用对象(a引用b, b引用a, 导致其引用计数永远不为0) 。

3、内存池机制:

Python提供了对内存的垃圾收集机制,但是它将不用的内存放到内存池而不是返回给操作系统。

Python中所有小于256个字节的对象都使用pymalloc实现的分配器,而大的对象则使用系统的 malloc。另外Python对象,如整数,浮点数和List,都有其独立的私有内存池,对象间不共享他们的内存池。也就是说如果你分配又释放了大量的整数,用于缓存这些整数的内存就不能再分配给浮点数。

4、分代回收:

Python同时采用了分代(generation)回收的策略。这一策略的基本假设是,存活时间越久的对象,越不可能在后面的程序中变成垃圾。我们的程序往往会产生大量的对象,许多对象很快产生和消失,但也有一些对象长期被使用。出于信任和效率,对于这样一些“长寿”对象,我们相信它们的用处,所以减少在垃圾回收中扫描它们的频率。

二十一、read,readline和 readlines三者的区别是什么?

read 读取整个文件

readline 读取下一行

readlines 读取整个文件到一个迭代器以供我们遍历 (读取到一个list中,以供使用,比较方便)

二十二、 Post和 Get的区别是什么?

1、GET请求的数据放在请求头中;POST请求的数据放置在请求体中。

2、GET 方式提交的数据最多只能是 1024 字节,理论上 POST没有限制,可传较大量的数据。

二十三、 Cookie 和 Session的区别是什么?

(1)cookie 数据存放在客户的浏览器上, session 数据放在服务器上

(2)cookie 不是很安全,别人可以分析存放在本地的 COOKIE并进行OOKIE欺骗, 如果主要考虑到安全应当使用 session

(3)session 会在一定时间内保存在服务器上。 当访问增多,会比较占用你服务器的性能,如果主要考虑到减轻服务器性能方面,应当使用COOKIE

(4) 单个 cookie 在客户端的限制是 3K,就是说一个站点在客户端存放的COOKIE不能超过 3K

(5) 所以:将登陆信息等重要信息存放为 SESSION;其他信息如果需要保留,可以放在 COOKIE中

1,session 在服务器端, cookie 在客户端(浏览器)

2,session 默认被存在在服务器的一个文件里(不是内存)

3,session 的运行依赖 session id,而 session id 是存在 cookie 中的,也就是 说,如果浏览器禁用了 cookie ,同时 session 也会失效(但是可以通过其它方 式实现,比如在 url 中传递 session_id)

4,session 可以放在 文件、数据库、或内存中都可以。

5,用户验证这种场合一般会用 session ,因此维持一个会话的核心就是客户端的唯一标识,即 session id

二十四、Python的数据类型

Python 提供的基本数据类型主要有:布尔类型、整型、浮点型、字符串、列表、 元组、集合、字典等等

二十五、 Python 和多线程( multi-threading )

Python 并不支持真正意义上的多线程。 Python 中提供了多线程包,但是如果你想通过多线程提高代码的速度,使用多线程包并不是个好主意。 Python 中有一个被称为 Global Interpreter Lock (GIL)的东西,它会确保任何时候你的多个线程中,只有一个被执行。 线程的执行速度非常之快, 会让你误以为线程是并行执行的,但是实际上都是轮流执行。 经过 GIL 这一道关卡处理, 会增加执行的开销。这意味着,如果你想提高代码的运行速度,使用 threading 包并不是一个很好的方法。

不过还是有很多理由促使我们使用 threading 包的。如果你想同时执行一些任务,而且不考虑效率问题,那么使用这个包是完全没问题的,而且也很方便。但是大部分情况下, 并不是这么一回事, 你会希望把多线程的部分外包给操作系统完成(通过开启多个进程),或者是某些调用你的 Python 代码的外部程序(例如 Spark 或 Hadoop ),又或者是你的 Python 代码调用的其他代码(例如,你可以在 Python 中调用 C 函数,用于处理开销较大的多线程工作)。

为什么提这个问题因为 GIL 就是个混账东西( A-hole )。很多人花费大量的时间,试图寻找自己多线程代码中的瓶颈,直到他们明白 GIL 的存在

二十六、乐观锁和悲观锁

悲观锁:假定会发生并发冲突,屏蔽一切可能违反数据完整性的操作

乐观锁:假设不会发生并发冲突,只在提交操作时检查是否违反数据完整性

二十七、 urllib 和 urllib2 的区别

  1. urllib 提供 urlencode 方法用来 GET 查询字符串的产生,而 urllib2 没有。这是为何 urllib 常和 urllib2 一起使用的原因。
  2. urllib2 可以接受一个 Request 类的实例来设置 URL 请求的 headers ,urllib仅可以接受 URL。这意味着,你不可以伪装你的 User Agent 字符串等。

二十八、深拷贝和浅拷贝的区别

浅拷贝是将原始对象中的数据型字段拷贝到新对象中去,将引用型字段的“引用”复制到新对象中去,不把“引用的对象”复制进去,所以原始对象和新对象引用同一对象,新对象中的引用型字段发生变化会导致原始对象中的对应字段也发生变化。

深拷贝是在引用方面不同,深拷贝就是创建一个新的和原始字段的内容相同的字段,是两个一样大的数据段,所以两者的引用是不同的,之后的新对象中的引用型字段发生改变,不会引起原始对象中的字段发生改变。

二十九、爬虫分布式部署

scrapy-redis : 基于这个框架开发的一套组件,可以让scrapy实现分布式的爬取

(1)安装: pip install scrapy-redis

(2)样本查看

    https://github.com/rmax/scrapy-redis
    example-project\example\spiders
    dmoz.py : 普通crawlspider,没有参考价值
    myspider_redis.py : 分布式的Spider模板
    mycrawler_redis.py : 分布式的CrawlSpider模板
    Spider       ====》  RedisSpider
    CrawlSpider  ====》  RedisCrawlSpider
    name                 name
    redis_key            start_urls
    __init__()           allowed_domains

【注】init()是一个坑,现在还是使用allowed_domains这种列表的形式

(3)存储到redis中

scrapy-redis组件已经写好往redis中存放的管道,只需要使用即可,默认存储到本机的redis服务中

如果想存储到其它的redis服务中,需要在配置文件中配置

REDIS_HOST = 'ip地址'

REDIS_PORT = 6379

(4)部署分布式

爬虫文件按照模板文件修改 配置文件中添加

    # 使用scrapy-redis组件的去重队列
    DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
    # 使用scrapy-redis组件自己的调度器
    SCHEDULER = "scrapy_redis.scheduler.Scheduler"
    # 是否允许暂停
    SCHEDULER_PERSIST = True

(5)跑起来这个项目

【注】分布式爬取的时候,指令不是scrapy crawl xx

而是scrapy runspider xxx.py

三十、什么是闭包?

  • 定义:
    • 外部函数中定义一个内部函数,
    • 内部函数中使用了外部函数的变量,
    • 外部函数将内部函数作为返回值返回。
  • 实例:
    def wai(n):
        def nei():
            return n*n
        return nei
    
    f1 = wai(3)
    f2 = wai(5)
    
    print(f1())
    print(f2())
  • 作用:提高代码的复用度

三十一、什么是装饰器?

  • 作用:当我们想要增强原来已有函数的功能,但不想(无法)修改原函数,可以使用装饰器解决
  • 使用:
    • 先写一个装饰器,就是一个函数,该函数接受一个函数作为参数,返回一个闭包,而且闭包中执行传递进来的函数,闭包中可以在函数执行的前后添加一些内容。
    • 在需要装饰的函数前添加@装饰器名就可以使用了,如:
      @zhuangshiqi
      def show():
      	pass
  • 再使用原函数时,就已经是装饰过的了
  • 示例1:无参无返回值
    def shuai(func):
        def wrapper():
            print('拉风的墨镜')
            func()
            print('脚穿大头鞋')
        return wrapper
    
    @shuai
    def mugai():
        print('木盖,屌丝一枚')
    
    mugai()
  • 示例2:带参函数的装饰器
    # 带参函数的装饰器
    def zhuangshiqi(func):
        def wrapper(*args, **kwargs):
            print('今天天气不错,出门就打到车了')
            func(*args, **kwargs)
        return wrapper
    
    @zhuangshiqi
    def test(n):
        print('我的幸运数字为:{}'.format(n))
    
    test(7)
  • 示例3:带参有返回值的装饰器
    def zhuangshiqi(func):
        def wrapper(*args, **kwargs):
            return func(*args, **kwargs) + 10
        return wrapper
    
    @zhuangshiqi
    def pingfang(n):
        return n*n
    
    print(pingfang(4))

三十二、生成器(generator)

  • 列表生成式,可以快速的生成列表
    # 数据量非常小,内存占用不大
    l = [i for i in range(10)]
    
    # 数据量特别大时,会造成内存占用突然增大
    l2 = [i for i in range(10000)]
  • 为了解决内存突然增大问题,python引入了生成器
  • 产生方式:
    • 将列表生成式的[]改为()
     # 数据量非常小,内存占用不大
      l = [i for i in range(10)]
      
      # 数据量特别大时,会造成内存占用突然增大
      # l2 = [i for i in range(10000)]
      # 生成器
      l2 = (i for i in range(2))
      
      print(type(l))
      print(type(l2))
      
      # 可以转换为列表
      # print(list(l2))
      
      # 使用next获取生成器中值,一次一个,遍历结束会报错StopIteration
      # print(next(l2))
      # print(next(l2))
      # print(next(l2))
      
      # 可以使用for-in遍历
      for i in l2:
          print(i)
  • 通过在函数中使用yield关键字
     def test(n):
          l = []
          for i in range(1, n+1):
              l.append(i)
          return l
      
      # print(test(5))
  - 特性:
  
    - 可以使用next获取数据,一次一个,结束时会报错
    - 只能遍历一遍
    - 可以转换为列表
    - 可以使用for-in遍历

三十三、迭代器(Iterator)

  • 定义:就是可以使用for-in进行遍历,并且可以使用next依次获取元素的对象
  • 说明:
    • 生成器就是一种特殊的迭代器
    • 判断是否是迭代器
     from collections import Iterator
        
        l = (i for i in range(10))
        print(isinstance(l, Iterator))
  • 字符串、列表、元组、集合、字典等都不是迭代器,他们都是可迭代对象。
  • 定义:可以使用for-in遍历的对象,我们都称之为可迭代对象
  • 判断一个对象是否是可迭代对象
     from collections import Iterable
      print(isinstance(l, Iterable))
      print(isinstance(lt, Iterable))

三十四、iter函数

  • 作用:将可迭代对象转换为迭代器
  • 使用:
      lt2 = iter(lt)
      print(isinstance(lt2, Iterator))
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值