Python面试282题深度剖析及延伸提问合辑

1. 请解释Python中的模块和包。

回答

在Python中,模块与包是组织代码的关键手段,它们助力代码实现复用与结构化。

模块(Module)

模块是携有Python代码的文件,一般以.py作为文件扩展名。模块能够定义函数、类以及变量,还能包含可执行代码。借助模块,可将相关功能归类到一个文件内,让代码更为结构化且易维护。

创建与使用模块
  1. 创建模块 :你能创建一个Python文件(例如mymodule.py),并在其中定义函数或变量:

     # mymodule.py
     def say_hello(name):
         return f"Hi, {name}!"
    
     pi_value = 3.14159
    
  2. 使用模块 :在其他Python文件或解释器中,可运用import语句导入模块:

     import mymodule
    
     print(mymodule.say_hello("Bob"))
     print(mymodule.pi_value)
    
包(Package)

包是组织多个模块的方式。它本质是包含多个模块的文件夹,且该文件夹下需有一个子文件__init__.py(可空),此文件告知Python将该文件夹视作包。包有助于分层组织模块,方便管理较大型项目。

创建与使用包
  1. 创建包 :你可创建一个文件夹,比如mypackage,并在其中放入多个模块(如module_a.pymodule_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"
  1. 使用包 :在其他文件中,可通过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. [列举面向对象中带双下划线的特殊方法,如:newinit

?](https://www.bagujing.com/problem-exercise/22?pid=4008)

回答

在Python中,带双下划线的特殊方法(常称“魔法方法”或“dunder方法”)用于定义类的特定行为。以下是一些常见的带双下划线特殊方法:

  1. __new__(cls, ...):用于创建实例。实例化对象时调用,常与__init__协同使用。

  2. __init__(self, ...):用于初始化新创建的对象,是构造函数。

  3. __str__(self):返回对象的可读字符串表示,常用于print

  4. __repr__(self):返回对象的官方字符串表示,应尽可能可用于重新创建该对象。

  5. __len__(self):定义对象长度,使用len()函数时调用。

  6. __getitem__(self, key):定义对象的索引访问,使用obj[key]语法时调用。

  7. __setitem__(self, key, value):定义对象的索引赋值,使用obj[key] = value语法时调用。

  8. __delitem__(self, key):定义对象的索引删除,使用del obj[key]语法时调用。

  9. __iter__(self):返回迭代器,允许用for循环遍历对象。

  10. __next__(self):返回下一个可迭代值,通常与__iter__配合使用。

  11. __contains__(self, item):定义成员检查,使用item in obj语法时调用。

  12. __call__(self, ...):让类实例可像函数一样被调用。

  13. __eq__(self, other):定义相等性比较,使用==运算符时调用。

  14. __ne__(self, other):定义不相等性比较,使用!=运算符时调用。

  15. __lt__(self, other):定义小于比较,使用<运算符时调用。

  16. __le__(self, other):定义小于或等于比较,使用<=运算符时调用。

  17. __gt__(self, other):定义大于比较,使用>运算符时调用。

  18. __ge__(self, other):定义大于或等于比较,使用>=运算符时调用。

  19. __hash__(self):定义对象哈希值,常用于集合和字典的键。

  20. __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 = val

    def __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 = val

    def __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操作(如网络请求、文件操作等)时,不阻塞整个程序执行。

主要概念与特点
  1. 事件循环

    • asyncio核心是事件循环,负责调度和执行异步任务。事件循环不断检查有无准备好的任务,执行任务并处理I/O事件。
    • 协程

    • 协程用async def定义,允许执行时被中断,等待某操作完成后恢复执行。用await关键词可暂停协程执行,等待另一协程或I/O操作完成。

    import asyncio

    async def greetings():
    print("Hello!")
    await asyncio.sleep(1) # 模拟非阻塞I/O
    print("World!")

  2. 任务

    • 任务是对协程的封装,允许协程并发运行。可用asyncio.create_task()方法创建任务。

    async def main_task():
    task = asyncio.create_task(greetings())
    await task

    asyncio.run(main_task())

  3. 并发

版权声明:程序员胖胖胖虎阿 发表于 2025年9月18日 上午11:58。
转载请注明:Python面试282题深度剖析及延伸提问合辑 | 胖虎的工具箱-编程导航

相关文章

暂无评论

暂无评论...