1. 请解释Python中的模块和包。
回答
在Python中,模块与包是组织代码的关键手段,它们助力代码实现复用与结构化。
模块(Module)
模块是携有Python代码的文件,一般以.py
作为文件扩展名。模块能够定义函数、类以及变量,还能包含可执行代码。借助模块,可将相关功能归类到一个文件内,让代码更为结构化且易维护。
创建与使用模块
-
创建模块 :你能创建一个Python文件(例如
mymodule.py
),并在其中定义函数或变量:# mymodule.py def say_hello(name): return f"Hi, {name}!" pi_value = 3.14159
-
使用模块 :在其他Python文件或解释器中,可运用
import
语句导入模块:import mymodule print(mymodule.say_hello("Bob")) print(mymodule.pi_value)
包(Package)
包是组织多个模块的方式。它本质是包含多个模块的文件夹,且该文件夹下需有一个子文件__init__.py
(可空),此文件告知Python将该文件夹视作包。包有助于分层组织模块,方便管理较大型项目。
创建与使用包
- 创建包 :你可创建一个文件夹,比如
mypackage
,并在其中放入多个模块(如module_a.py
和module_b.py
),同时在文件夹下创建__init__.py
文件:mypackage/ __init__.py module_a.py module_b.py
module_a.py
示例:
def do_something():
return "Performing an action"
module_b.py
示例:
def do_another_thing():
return "Doing another action"
- 使用包 :在其他文件中,可通过
import
语句导入包内模块:from mypackage import module_a, module_b print(module_a.do_something()) print(module_b.do_another_thing())
总结
- 模块 是含Python代码的简单文件,涵盖函数、类与变量。
- 包 是含多个模块的文件夹,需有
__init__.py
文件来被识别。 - 运用模块与包能让代码更具可维护性、可复用性与可读性。
2. 一行代码反转字符串
回答
在Python里,可利用切片来反转字符串。下面是一行代码实现字符串反转的示例:
reversed_str = original_string[::-1]
其中,original_string
是你要反转的字符串。这段代码的含义是从字符串末尾往开头,以步长为 -1 进行切片,从而达成反转目的。
3. [列举面向对象中带双下划线的特殊方法,如:new 、init
?](https://www.bagujing.com/problem-exercise/22?pid=4008)
回答
在Python中,带双下划线的特殊方法(常称“魔法方法”或“dunder方法”)用于定义类的特定行为。以下是一些常见的带双下划线特殊方法:
-
__new__(cls, ...)
:用于创建实例。实例化对象时调用,常与__init__
协同使用。 -
__init__(self, ...)
:用于初始化新创建的对象,是构造函数。 -
__str__(self)
:返回对象的可读字符串表示,常用于print
。 -
__repr__(self)
:返回对象的官方字符串表示,应尽可能可用于重新创建该对象。 -
__len__(self)
:定义对象长度,使用len()
函数时调用。 -
__getitem__(self, key)
:定义对象的索引访问,使用obj[key]
语法时调用。 -
__setitem__(self, key, value)
:定义对象的索引赋值,使用obj[key] = value
语法时调用。 -
__delitem__(self, key)
:定义对象的索引删除,使用del obj[key]
语法时调用。 -
__iter__(self)
:返回迭代器,允许用for
循环遍历对象。 -
__next__(self)
:返回下一个可迭代值,通常与__iter__
配合使用。 -
__contains__(self, item)
:定义成员检查,使用item in obj
语法时调用。 -
__call__(self, ...)
:让类实例可像函数一样被调用。 -
__eq__(self, other)
:定义相等性比较,使用==
运算符时调用。 -
__ne__(self, other)
:定义不相等性比较,使用!=
运算符时调用。 -
__lt__(self, other)
:定义小于比较,使用<
运算符时调用。 -
__le__(self, other)
:定义小于或等于比较,使用<=
运算符时调用。 -
__gt__(self, other)
:定义大于比较,使用>
运算符时调用。 -
__ge__(self, other)
:定义大于或等于比较,使用>=
运算符时调用。 -
__hash__(self)
:定义对象哈希值,常用于集合和字典的键。 -
__enter__(self)
和__exit__(self, exc_type, exc_value, traceback)
:用于上下文管理器,支持with
语句。
4. 数据爬虫中遇到验证码的解决?
回答
在数据爬虫过程中,碰到验证码是常见难题。验证码主要是为阻止自动化程序访问网站,所以解决该问题通常得借助额外手段。以下是一些解决实例与建议:
1. 手动处理验证码
- 针对小规模爬取,可选择手动解决验证码。
- 能在程序中设置暂停,以便人工输入验证码。
2. 借助第三方服务
- 有一些专门破解验证码的第三方服务,例如:
- 2Captcha
- Anti-Captcha
- DeathByCaptcha
- 这类服务一般要求将验证码图像发送至其API,之后会返回识别出的验证码结果。
3. 运用图像识别技术
- 若验证码图像较简单,可尝试用图像识别库(像OpenCV、Pillow和Tesseract)识别验证码:
from PIL import Image import pytesseract img = Image.open('captcha.png') captcha_text = pytesseract.image_to_string(img)
4. 使用Selenium等工具
- Selenium可模拟人类用户行为,有时能通过生成随机但可预测的响应绕过验证码。
- 可通过Selenium打开网页并等待CAPTCHA显示,之后人工解决,或用自动化脚本处理相对简单的验证码。
5. 变换IP或请求头
- 若短时间内发送大量请求,可能遭遇CAPTCHA保护。可通过更换IP(如代理)或请求头降低被限制风险。
6. 使用无头浏览器
- 无头浏览器(如Puppeteer或Selenium)可助力模拟人类行为,通常能规避CAPTCHA。
7. 遵循网站礼仪
- 尽量遵循网站爬虫规范,设置合适抓取速度与请求间隔,减少被判定为爬虫的几率。
8. 检查robots.txt
- 开始爬取前,务必检查网站的
robots.txt
文件,确保行为符合爬虫规范。
示例代码(使用2Captcha)
import requests
import time
# 向2Captcha发送验证码
response = requests.post('http://2captcha.com/in.php', data={
'key': 'YOUR_API_KEY',
'method': 'post',
'json': 1,
'file': open('captcha.png', 'rb'),
})
captcha_id = response.json().get('request')
# 等待验证码处理完成
for _ in range(30): # 最多等30秒
time.sleep(5)
response = requests.get(f'http://2captcha.com/res.php?key=YOUR_API_KEY&action=get&id={captcha_id}&json=1')
if response.json()['status'] == 1:
captcha_text = response.json()['request']
break
print(captcha_text)
5. Scrapy中的pipelines工作原理?
回答
在Scrapy框架中,Item Pipeline是处理爬虫提取数据的重要组件。它能让你对爬取到的数据开展清洗、验证和存储等后处理操作。Item Pipeline由一系列处理器构成,Scrapy会依次把Item传递给这些处理器。
1. Pipeline的定义
在Scrapy里,可在pipelines.py
文件中定义多个Pipeline类。每个类负责处理特定逻辑,例如数据清洗、数据验证、持久化存储等。
2. 启用Pipeline
在项目的设置文件settings.py
中,需通过配置ITEM_PIPELINES
启用相应Pipeline。示例配置如下:
ITEM_PIPELINES = {
'myproject.pipelines.MyPipeline': 300,
}
此处,字典的键是Pipeline类的路径,值是优先级(数字越小,优先级越高)。
3. Pipeline的工作流程
-
数据传递 :爬虫抓取到数据并封装成Item后,这些Item会依次传递到配置中指定的Pipeline类(依优先级)。
-
方法调用 :
每个Pipeline类通常会实现以下几个方法:-
process_item(self, item, spider)
:这是关键方法。Scrapy抓取项时会调用它,可在此对Item进行清洗、验证或存储等处理。该方法必须返回Item。 -
open_spider(self, spider)
:爬虫启动时调用,可用于初始化数据库连接等操作。 -
close_spider(self, spider)
:爬虫结束时调用,用于关闭数据库连接等清理工作。
-
4. 数据处理示例
下面是简单Pipeline示例:
class MyPipeline:
def open_spider(self, spider):
self.file = open('output.json', 'w')
def close_spider(self, spider):
self.file.close()
def process_item(self, item, spider):
# 清洗数据,例如去除字段前后空格
item['field'] = item['field'].strip()
# 将处理后的Item写入文件或数据库
line = json.dumps(dict(item)) + "\n"
self.file.write(line)
return item
6. 类如何从Python中的另一个类继承?
回答
在Python中,类可通过继承获取另一个类的属性与方法。通过继承,子类能复用父类代码,并添加或重写功能。下面是简单示例展示类的继承:
# 定义父类(基类)
class Creature:
def __init__(self, name):
self.name = name
def make_sound(self):
return "I am a creature."
# 定义子类(派生类),继承自Creature
class Dog(Creature):
def make_sound(self):
return "Woof! My name is " + self.name
# 定义另一个子类(派生类),继承自Creature
class Cat(Creature):
def make_sound(self):
return "Meow! My name is " + self.name
# 实例化对象
doggy = Dog("Buddy")
kitty = Cat("Whiskers")
# 调用方法
print(doggy.make_sound()) # 输出: Woof! My name is Buddy
print(kitty.make_sound()) # 输出: Meow! My name is Whiskers
7. 请解释Python中的__repr__
和__str__
方法之间的区别。
回答
在Python中,__repr__
和__str__
是用于定义对象字符串表示的两个方法,它们存在一些重要区别。
__repr__
方法
- 目的 :
__repr__
主要是提供“官方”字符串表示,常用于开发和调试。 - 输出 :应返回能唯一标识对象的字符串,且若可能,返回的字符串应是有效Python表达式,可用
eval()
函数重建原对象。 -
用法 :使用
repr()
函数或直接在交互式解释器中输入对象名时,会调用__repr__
方法。class ExampleObj:
def init(self, val):
self.value = valdef __repr__(self): return f'ExampleObj(value={self.value!r})'
obj_inst = ExampleObj(42)
print(repr(obj_inst)) # 输出: ExampleObj(value=42)
__str__
方法
- 目的 :
__str__
主要是为用户提供可读性好的字符串表示,适合展示给用户看。 - 输出 :返回简单或更易理解的字符串表示,通常无需涉及对象所有细节。
-
用法 :使用
print()
函数或str()
函数时,会调用__str__
方法。class ExampleObj:
def init(self, val):
self.value = valdef __str__(self): return f'The value is {self.value}'
obj_inst = ExampleObj(42)
print(str(obj_inst)) # 输出: The value is 42
print(obj_inst) # 输出: The value is 42,因为print()内部调用__str__
8. 如何在Python中实现一个简单的装饰器?
回答
在Python中,装饰器是用于修改或增强函数(或方法)行为的工具。下面是简单装饰器示例,展示如何实现。
装饰器基本结构
装饰器本质是接受函数作为参数并返回新函数(通常是对原函数的增强或修改)的函数。
示例:时间记录装饰器
下面代码实现记录函数执行时间的装饰器:
import time
# 定义装饰器
def time_tracker(func):
def wrapper(*args, **kwargs):
start_time = time.time() # 记录开始时间
result = func(*args, **kwargs) # 调用原函数
end_time = time.time() # 记录结束时间
print(f"Function {func.__name__} took {end_time - start_time:.4f} seconds")
return result # 返回原函数返回值
return wrapper
# 使用装饰器
@time_tracker
def demo_func(n):
total = 0
for i in range(n):
total += i
return total
# 调用被装饰函数
res = demo_func(1000000)
print(f"Result: {res}")
9. 解释Python中的asyncio模块及其用途。
回答
asyncio
模块是Python内置库,用于编写单线程异步代码。它提供事件循环、协程和任务功能,让程序在等待I/O操作(如网络请求、文件操作等)时,不阻塞整个程序执行。
主要概念与特点
-
事件循环 :
asyncio
核心是事件循环,负责调度和执行异步任务。事件循环不断检查有无准备好的任务,执行任务并处理I/O事件。-
协程 :
-
协程用
async def
定义,允许执行时被中断,等待某操作完成后恢复执行。用await
关键词可暂停协程执行,等待另一协程或I/O操作完成。
import asyncio
async def greetings():
print("Hello!")
await asyncio.sleep(1) # 模拟非阻塞I/O
print("World!") -
任务 :
- 任务是对协程的封装,允许协程并发运行。可用
asyncio.create_task()
方法创建任务。
async def main_task():
task = asyncio.create_task(greetings())
await taskasyncio.run(main_task())
- 任务是对协程的封装,允许协程并发运行。可用
-
并发