Python 面试高频问题 (含 Flask) - 面向新手
基础知识
Python 的特点是什么?
- 易于学习、可读性好、解释型语言。
- 动态类型、面向对象,拥有丰富的库。
Python 的基本数据类型有哪些?
- 整型 (int): 例如 1, 2, -3
- 浮点型 (float): 例如 3.14, -2.5
- 字符串 (str): 例如 "hello", 'world'
- 布尔型 (bool):
True或False
什么是可变类型和不可变类型?举例说明。
- 可变类型: 值可以修改。例如:列表 (list), 字典 (dict), 集合 (set)。python
my_list = [1, 2, 3] my_list[0] = 10 # 可以修改 print(my_list) # 输出: [10, 2, 3] - 不可变类型: 值不能修改。例如:整型 (int), 浮点型 (float), 字符串 (str), 元组 (tuple)。python
my_string = "hello" # my_string[0] = 'H' # 错误! 字符串不能修改
- 可变类型: 值可以修改。例如:列表 (list), 字典 (dict), 集合 (set)。
什么是深拷贝和浅拷贝?有什么区别?
- 浅拷贝: 创建一个新对象,但新对象中的子对象仍然是原对象的引用。 使用
copy.copy()。 - 深拷贝: 创建一个新对象,并且递归地拷贝所有子对象,创建一个完全独立的副本。 使用
copy.deepcopy()。
pythonimport copy list1 = [1, [2, 3]] list2 = copy.copy(list1) # 浅拷贝 list3 = copy.deepcopy(list1) # 深拷贝 list1[1][0] = 99 # 修改 list1 的子列表 print(list1) # 输出: [1, [99, 3]] print(list2) # 输出: [1, [99, 3]] (浅拷贝,子列表也改变) print(list3) # 输出: [1, [2, 3]] (深拷贝,子列表不变)- 浅拷贝: 创建一个新对象,但新对象中的子对象仍然是原对象的引用。 使用
Python 中如何进行类型转换?举例说明。
- 使用内置函数:
int(): 转换为整数float(): 转换为浮点数str(): 转换为字符串bool(): 转换为布尔值list(),tuple(),dict(),set(): 转换为对应的容器类型
pythonx = "10" y = int(x) # 将字符串 "10" 转换为整数 10 print(y) # 输出: 10
- 使用内置函数:
什么是列表推导式?如何使用?举例说明。
- 一种用一行代码创建新列表的简洁方式。
- 基本语法:
[expression for item in iterable if condition]
python# 创建一个包含 1 到 10 的偶数的列表 even_numbers = [x for x in range(1, 11) if x % 2 == 0] print(even_numbers) # 输出: [2, 4, 6, 8, 10]什么是字典推导式?如何使用?举例说明。
- 一种用一行代码创建新字典的简洁方式。
- 基本语法:
{key_expression: value_expression for item in iterable if condition}
python# 创建一个字典,键是数字,值是数字的平方 squares = {x: x*x for x in range(1, 6)} print(squares) # 输出: {1: 1, 2: 4, 3: 9, 4: 16, 5: 25}什么是生成器 (generator)?有什么作用?
- 使用
yield语句的函数。 - 可以创建迭代器,逐个生成值,而不是一次性生成所有值,节省内存,提高效率。
pythondef my_generator(n): for i in range(n): yield i # 每次生成一个值 for value in my_generator(5): print(value) # 输出: 0, 1, 2, 3, 4- 使用
什么是迭代器 (iterator)?有什么作用?
- 可以被
for循环遍历的对象。 - 需要实现
__iter__()和__next__()方法。 - 迭代器用于逐个访问集合中的元素。
- 可以被
__init__和__new__的区别是什么?__new__: 创建实例,先于__init__执行。__init__: 初始化实例,在实例创建后执行。
Python 中的多线程是什么?它有什么限制?
- 使用
threading模块创建多个线程并发执行。 - 限制: 由于 GIL (全局解释器锁) 的存在,Python 的多线程在 CPU 密集型任务中无法实现真正的并行(同一时刻只有一个线程能执行 Python 字节码)。 适合 I/O 密集型任务(例如,网络请求)。
- 使用
Python 中的多进程是什么?有什么优势?
- 使用
multiprocessing模块创建多个进程并发执行。 - 优势: 可以实现真正的并行,克服 GIL 的限制,适用于 CPU 密集型任务。
- 使用
什么是 GIL (全局解释器锁)?它有什么影响?为什么会有 GIL?
- 全局解释器锁 (Global Interpreter Lock): 在同一时刻只允许一个线程拥有 Python 解释器的控制权。
- 影响: 限制了 Python 多线程在 CPU 密集型任务中的并行性。
- 为什么会有 GIL? GIL 是为了简化 CPython 解释器的内存管理,避免多线程同时操作同一内存区域导致的数据竞争问题。 历史原因,以及 CPython 的设计选择。
- 绕过 GIL 的方法: 使用多进程、使用 C 扩展 (例如,使用 C 编写 CPU 密集型代码,然后通过 Python 调用)。
什么是装饰器 (decorator)?如何使用?
- 一种用来修改函数或类的强大工具,不修改函数或类本身的代码。
- 使用
@符号。
pythondef my_decorator(func): # 装饰器是一个函数 def wrapper(): print("Before the function is called.") func() print("After the function is called.") return wrapper @my_decorator # 使用装饰器 def say_hello(): print("Hello!") say_hello()装饰器的作用是什么?有哪些常见的应用场景?
- 作用:在不修改原有函数代码的情况下,增加额外的功能。
- 应用场景:
- 日志记录
- 性能测试
- 权限控制
- 缓存
常见的装饰器有哪些?举例说明。
@staticmethod和@classmethod: 改变方法的作用域。pythonclass MyClass: @staticmethod def my_static_method(): print("This is a static method.") @classmethod def my_class_method(cls): print(f"This is a class method, cls is {cls}")@property: 将方法伪装成属性,可以进行属性的读、写、删除操作。pythonclass Circle: def __init__(self, radius): self._radius = radius # 使用 _ 约定 (并非强制) @property def radius(self): return self._radius @radius.setter def radius(self, value): if value >= 0: self._radius = value else: raise ValueError("Radius cannot be negative") @property def diameter(self): return self.radius * 2@functools.wraps: 用于保留原始函数的元信息 (例如,__name__,__doc__)。 重要! 当装饰器修改了函数时,原函数的元信息会丢失,导致问题。 使用functools.wraps可以解决。pythonimport functools def my_decorator(func): @functools.wraps(func) # 保留原始函数的元信息 def wrapper(*args, **kwargs): """This is the wrapper function's docstring.""" print("Before the function is called.") result = func(*args, **kwargs) print("After the function is called.") return result return wrapper @my_decorator def say_hello(): """This is the original function's docstring.""" print("Hello!") print(say_hello.__name__) # 输出: say_hello print(say_hello.__doc__) # 输出: This is the original function's docstring.- Flask 路由装饰器: 例如,
@app.route('/')
Python 中的魔法方法 (magic methods) / 特殊方法是什么?举例说明。
- 以双下划线
__开头和结尾的方法。 - 用于实现类的特殊行为,例如:
__init__: 初始化对象。__str__: 返回对象的字符串表示。__len__: 返回对象的长度 (用于len()函数)。__getitem__: 实现索引访问 (例如obj[index])。__setitem__: 实现索引赋值 (例如obj[index] = value)。__delitem__: 实现索引删除 (例如del obj[index])。
- 以双下划线
什么是面向对象编程 (OOP)?Python 如何实现 OOP?
- OOP: 一种编程范式,将程序组织成对象,对象包含数据 (属性) 和操作数据的方法。
- Python 实现 OOP: 类、对象、继承、多态、封装。
self的作用是什么?- 指向类的实例本身。
- 在实例方法中,必须作为第一个参数传递。
Python 中的继承是什么?
- 一个类 (子类) 可以继承另一个类 (父类) 的属性和方法。
class 子类(父类):
Python 中的多态是什么?举例说明。
- 不同的对象可以对同一方法做出不同的响应。 Python 是动态语言,依赖鸭子类型。
pythonclass Dog: def speak(self): return "Woof!" class Cat: def speak(self): return "Meow!" def animal_sound(animal): print(animal.speak()) # 无论是什么动物,调用speak()方法 dog = Dog() cat = Cat() animal_sound(dog) # 输出: Woof! animal_sound(cat) # 输出: Meow!Python 中的封装是什么?
- 将数据 (属性) 和方法封装在一个类中,隐藏实现细节,只暴露必要的接口。
- 使用访问修饰符 (public, protected, private)。 (Python 没有严格的 private 修饰符,使用
_或__来约定)。
常用模块
os模块的作用是什么?常用的方法有哪些?- 提供与操作系统交互的功能。
- 常用方法:
os.getcwd(): 获取当前工作目录。os.chdir(path): 改变当前工作目录。os.listdir(path): 列出指定目录下的文件和目录。os.mkdir(path): 创建目录。os.remove(path): 删除文件。os.rename(src, dst): 重命名文件或目录。os.path.join(path1, path2, ...): 拼接路径。os.path.exists(path): 判断路径是否存在。
sys模块的作用是什么?常用的方法有哪些?- 提供与Python 解释器交互的功能。
- 常用方法:
sys.argv: 命令行参数列表。sys.path: 模块搜索路径。sys.exit(): 退出程序。sys.stdin,sys.stdout,sys.stderr: 标准输入、标准输出、标准错误。
re模块的作用是什么?常用的正则表达式有哪些?- 用于正则表达式操作。
- 常用正则表达式:
.: 匹配任意字符 (除了换行符)。^: 匹配字符串的开头。$: 匹配字符串的结尾。*: 匹配 0 次或多次。+: 匹配 1 次或多次。?: 匹配 0 次或 1 次。[]: 字符集,匹配其中任意一个字符。(): 分组。
- 常用方法:
re.search(pattern, string): 在字符串中搜索匹配项。re.match(pattern, string): 从字符串的开头开始匹配。re.findall(pattern, string): 查找所有匹配项,返回列表。re.sub(pattern, repl, string): 替换匹配项。
datetime模块的作用是什么?常用的类有哪些?- 用于处理日期和时间。
- 常用类:
datetime.datetime: 表示日期和时间。datetime.date: 表示日期。datetime.time: 表示时间。datetime.timedelta: 表示时间差。
json模块的作用是什么?常用的方法有哪些?- 用于处理 JSON 数据 (序列化和反序列化)。
- 常用方法:
json.dumps(obj): 将 Python 对象序列化为 JSON 字符串。json.loads(json_str): 将 JSON 字符串反序列化为 Python 对象。
requests模块的作用是什么?常用的方法有哪些?- 用于发送 HTTP 请求。
- 常用方法:
requests.get(url): 发送 GET 请求。requests.post(url, data=data): 发送 POST 请求。requests.put(url, data=data): 发送 PUT 请求。requests.delete(url): 发送 DELETE 请求。
math模块的作用是什么?常用的方法有哪些?- 提供数学运算相关函数。
- 常用方法:
math.sqrt(x): 求平方根。math.sin(x),math.cos(x),math.tan(x): 三角函数。math.pi: π 值。math.e: e 值。
random模块的作用是什么?常用的方法有哪些?- 生成随机数。
- 常用方法:
random.randint(a, b): 生成 [a, b] 范围内的随机整数。random.random(): 生成 [0.0, 1.0) 范围内的随机浮点数。random.choice(seq): 从序列中随机选择一个元素。random.shuffle(seq): 将序列中的元素随机打乱。
异常处理
Python 中如何进行异常处理?
- 使用
try...except...finally语句。
pythontry: # 可能会发生异常的代码 result = 10 / 0 # 抛出 ZeroDivisionError 异常 except ZeroDivisionError: # 处理 ZeroDivisionError 异常 print("除数不能为零!") except ValueError: # 处理 ValueError 异常 print("数值错误!") finally: # 无论是否发生异常,都会执行的代码 (例如,释放资源) print("执行 finally 块")- 使用
常见的异常类型有哪些?
TypeError: 类型错误。ValueError: 值错误。IndexError: 索引超出范围。KeyError: 字典键不存在。IOError: 输入/输出错误。ZeroDivisionError: 除数为零。NameError: 变量名未定义。FileNotFoundError: 文件未找到 (是 IOError 的子类)。AttributeError: 尝试访问对象不存在的属性。ImportError: 模块导入错误。
如何自定义异常?
- 创建一个新的类,继承自
Exception类。
pythonclass MyCustomError(Exception): def __init__(self, message): self.message = message def __str__(self): # 定义异常的字符串表示 return f"MyCustomError: {self.message}" try: raise MyCustomError("这是一个自定义异常") except MyCustomError as e: print(f"捕获到自定义异常: {e}")- 创建一个新的类,继承自
编码规范 & 工具
PEP 8 是什么?
- Python 的代码风格规范,规定了代码的排版、命名、注释等。
常用的 Python 代码风格检查工具?
pylint: 更全面的代码质量检查工具。flake8: 结合了pycodestyle,pyflakes, 和mccabe的检查工具。black: 一个自动化的代码格式化工具,会帮你把代码格式化成符合 PEP 8 的风格。
如何使用虚拟环境?有什么作用?
- 使用
venv模块 (Python 3.3 及以上) 或virtualenv包。 - 作用: 隔离不同项目的依赖包,避免版本冲突。
- 创建虚拟环境:bash
python -m venv <venv_name> # 使用 venv # 或者 virtualenv <venv_name> # 使用 virtualenv - 激活虚拟环境:
- Linux/macOS:
source <venv_name>/bin/activate - Windows:
<venv_name>\Scripts\activate
- Linux/macOS:
- 安装依赖:
pip install <package_name> - 退出虚拟环境:
deactivate
- 使用
pip的作用是什么?- Python 的包管理工具,用于安装、卸载、管理 Python 包。
requirements.txt的作用是什么?- 记录项目依赖的包及其版本。
- 用于方便地在不同环境中安装项目依赖,实现环境的可复现性。
- 生成
requirements.txt:pip freeze > requirements.txt - 安装依赖:
pip install -r requirements.txt
进阶问题
如何在 Python 中实现单例模式?
- 使用元类 (metaclass)。
pythonclass Singleton(type): _instances = {} def __call__(cls, *args, **kwargs): if cls not in cls._instances: cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs) return cls._instances[cls] class MyClass(metaclass=Singleton): def __init__(self, name): self.name = name- 使用模块 (简单易用)。
python# singleton_module.py class MyClass: def __init__(self, name): self.name = name instance = MyClass("example") # another_file.py import singleton_module print(singleton_module.instance.name) # 访问单例- 使用装饰器。
什么是上下文管理器 (context manager)?如何使用?
- 用于管理资源的工具,确保资源在使用后被正确释放(例如,关闭文件,释放锁)。
- 使用
with语句。
pythonwith open("file.txt", "r") as f: # 自动处理文件的打开和关闭 content = f.read() print(content)如何创建自定义的上下文管理器?
- 实现
__enter__()和__exit__()方法。
pythonclass MyContextManager: def __enter__(self): print("Entering the context...") return self # 可以返回一个对象,供 with 语句使用 def __exit__(self, exc_type, exc_value, traceback): print("Exiting the context...") if exc_type: print(f"An exception occurred: {exc_type}, {exc_value}") return False # 如果返回 True,则抑制异常 with MyContextManager() as cm: print("Inside the context...") # 模拟异常 # raise ValueError("Something went wrong")- 可以使用
@contextlib.contextmanager装饰器。
- 实现
Python 中的协程 (coroutine) 是什么?
- 一种并发编程方式,使用
async和await关键字。 - 基于
asyncio库,用于编写异步代码。 协程是单线程的,但可以实现并发的效果(在等待 I/O 时,切换到其他任务)。
- 一种并发编程方式,使用
什么是装饰器模式?
- 在不修改原有对象的情况下,动态地给对象添加一些额外的职责。
- Python 中使用装饰器来实现。
解释一下 Python 的鸭子类型?
- 关注对象的行为,而不是其类型。 如果一个对象实现了特定的方法,就可以像该类型一样使用。 “如果它走起来像鸭子,叫起来像鸭子,那么它就是鸭子。”
Python 中的 GIL 对多线程和多进程的影响是什么?
- GIL (全局解释器锁): 限制了 Python 多线程在 CPU 密集型任务中的并行性。
- 多线程: 在 CPU 密集型任务中,由于 GIL 的存在,多个线程无法真正并行,无法提高性能。
- 多进程: 可以克服 GIL 的限制,实现真正的并行,适用于 CPU 密集型任务。
Flask 相关
Flask 的特点是什么?
- 轻量级、易于使用、灵活、可扩展。
- 基于 Werkzeug WSGI 工具包和 Jinja2 模板引擎。
Flask 的基本结构是什么?
pythonfrom flask import Flask, render_template, request, jsonify app = Flask(__name__) # 创建 Flask 实例 @app.route("/") # 定义路由,对应一个 URL def hello_world(): return "<p>Hello, World!</p>" # 视图函数,返回响应 if __name__ == '__main__': app.run(debug=True) # 启动开发服务器Flask 的路由 (Routing) 机制是什么?
- 使用
@app.route()装饰器定义 URL 规则和关联的视图函数。 - 支持动态路由 (例如
<int:id>),用于处理 URL 参数。 - 支持 HTTP 方法 (GET, POST, PUT, DELETE, etc.)。
- 使用
Flask 中的请求 (Request) 对象有什么作用?如何获取请求数据?
request对象用于访问客户端发送的请求数据。- 常用属性:
request.method: HTTP 方法 (GET, POST, etc.)request.args: GET 请求的查询参数 (例如/search?q=python)。request.form: POST 请求的表单数据。request.files: 上传的文件。request.headers: HTTP 请求头。request.cookies: Cookie 信息。
pythonfrom flask import Flask, request, jsonify app = Flask(__name__) @app.route('/login', methods=['POST']) def login(): username = request.form.get('username') # 从表单获取数据 password = request.form.get('password') # ... 验证用户 ... return jsonify({'message': 'Login successful'})Flask 中的响应 (Response) 对象有什么作用?如何构建响应?
Response对象用于构建服务器的响应。- 可以返回字符串、HTML 内容,或者使用
make_response()创建自定义响应。 jsonify()可以将 Python 对象转换为 JSON 响应。
pythonfrom flask import Flask, jsonify, make_response app = Flask(__name__) @app.route('/api/data') def get_data(): data = {'message': 'Hello, Flask!'} return jsonify(data) # 返回 JSON 响应 @app.route('/error') def error_example(): response = make_response("Error!", 500) # 设置状态码 return response- 设置状态码:
response.status_code = 200(或其他状态码)。
Flask 中的模板 (Template) 是什么?如何使用模板?
- 使用 Jinja2 模板引擎。
render_template()函数用于渲染模板。- 模板中可以使用变量、控制结构 (if/else, for 循环) 和模板继承。
pythonfrom flask import Flask, render_template app = Flask(__name__) @app.route('/hello/<name>') def hello(name): return render_template('hello.html', name=name) # 渲染模板 # hello.html 模板 (示例) # <h1>Hello, {{ name }}!</h1>Flask 中的静态文件处理是怎么样的?
- 静态文件 (CSS, JavaScript, 图片等) 存储在
static目录下。 - 使用
url_for('static', filename='...')生成静态文件 URL。
python# 假设 static 目录下有一个 style.css 文件 from flask import Flask, url_for app = Flask(__name__) @app.route('/') def index(): css_url = url_for('static', filename='style.css') return f'<link rel="stylesheet" href="{css_url}">'- 静态文件 (CSS, JavaScript, 图片等) 存储在
Flask 的上下文 (Context) 是什么?有哪些类型的上下文?
- 请求上下文 (Request Context): 包含与特定请求相关的信息 (例如
request对象,session对象)。 由app.app_context()和app.test_request_context()创建。 - 应用上下文 (Application Context): 包含与应用程序相关的信息 (例如
current_app, 配置)。 由app.app_context()创建. - 上下文用于在处理请求期间访问全局对象。
- 请求上下文 (Request Context): 包含与特定请求相关的信息 (例如
Flask 中的会话 (Session) 是什么?
- 用于在用户会话期间存储数据。
- 默认情况下,Flask 使用 Cookie 存储会话数据 (有安全风险)。
- 可以配置使用其他存储方式 (例如,服务器端存储)。
- 使用
session对象访问会话数据。
pythonfrom flask import Flask, session, redirect, url_for app = Flask(__name__) app.secret_key = "your_secret_key" # 设置 secret_key 用于加密session @app.route('/login') def login(): session['username'] = 'example_user' return redirect(url_for('profile')) # 重定向到 profile 页面 @app.route('/profile') def profile(): if 'username' in session: return f"Hello, {session['username']}!" return "You are not logged in"Flask 中的配置 (Configuration) 是什么?如何设置?
- 用于配置 Flask 应用程序的行为。
app.config字典用于存储配置信息。- 可以从文件加载配置、设置环境变量。
pythonfrom flask import Flask app = Flask(__name__) app.config['DEBUG'] = True # 启用调试模式 app.config['SECRET_KEY'] = "your_secret_key" # 设置密钥 # app.config.from_pyfile('config.py') # 从文件加载配置- 常用配置项:
DEBUG,SECRET_KEY,DATABASE_URL。
Flask 中的蓝图 (Blueprint) 是什么?
- 用于组织大型 Flask 应用程序。
- 可以将相关的视图、模板、静态文件组织到蓝图中。
- 蓝图可以重复使用,方便代码复用和模块化。
Flask 中如何处理表单?
- 使用
request.form访问表单数据 (POST 请求)。 - 可以使用 Flask-WTF 扩展,简化表单处理和验证。
- 使用
Flask 中如何进行数据库操作?
- 可以使用 Flask-SQLAlchemy 扩展,简化与数据库的交互。
- 定义数据库模型。
- 使用 ORM (Object-Relational Mapping) 操作数据库。
Flask 中如何进行单元测试?
- 使用
app.test_client()创建测试客户端。 - 模拟 HTTP 请求。
- 断言响应状态码、内容等。
- 可以使用
pytest等测试框架。
- 使用
Flask-SQLAlchemy 是什么?作用是什么?
- Flask 的一个扩展,用于简化与 SQLAlchemy 数据库的交互。
- 提供 ORM (Object-Relational Mapping) 功能。
ORM (Object-Relational Mapping) 的作用是什么?
- 将数据库表映射为 Python 对象。
- 使用 Python 代码操作数据库,简化数据库操作。
SQLAlchemy 是什么?如何在 Flask 中使用 SQLAlchemy (通过 Flask-SQLAlchemy)?
- SQLAlchemy: 是一个强大的 Python SQL 工具包和 ORM 库。
- Flask-SQLAlchemy: 是 Flask 的一个扩展,简化了在 Flask 应用中使用 SQLAlchemy 的过程。
- 使用步骤:
- 安装:
pip install flask-sqlalchemy - 配置数据库连接: 在 Flask 应用中配置数据库 URL。 例如:python
from flask import Flask from flask_sqlalchemy import SQLAlchemy app = Flask(__name__) app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///example.db' # 使用 SQLite 数据库,文件名为 example.db app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False # 禁用追踪修改,可以提高性能 db = SQLAlchemy(app) # 创建 SQLAlchemy 实例 - 定义模型 (models): 定义数据库表对应的 Python 类。python
class User(db.Model): id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(80), unique=True, nullable=False) email = db.Column(db.String(120), unique=True, nullable=False) def __repr__(self): # 定义对象的字符串表示,便于调试 return '<User %r>' % self.username - 创建数据库表:python
with app.app_context(): # 必须在应用上下文里创建 db.create_all() # 创建所有模型对应的表 - 数据库操作 (CRUD): 使用 Python 代码进行数据库的增删改查。python
from flask import Flask, render_template, request, redirect, url_for from flask_sqlalchemy import SQLAlchemy app = Flask(__name__) app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///example.db' app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False db = SQLAlchemy(app) class User(db.Model): id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(80), unique=True, nullable=False) email = db.Column(db.String(120), unique=True, nullable=False) def __repr__(self): return '<User %r>' % self.username with app.app_context(): db.create_all() @app.route('/') def index(): users = User.query.all() # 查询所有用户 return render_template('index.html', users=users) @app.route('/add', methods=['POST']) def add_user(): if request.method == 'POST': username = request.form['username'] email = request.form['email'] new_user = User(username=username, email=email) db.session.add(new_user) # 添加到 session db.session.commit() # 提交到数据库 return redirect(url_for('index')) # 重定向到首页 return render
- 安装:
SQLAlchemy 数据库操作 (CRUD - 增删改查) 怎么做? (接上一个问题)
创建 (Create):
- 创建模型实例,添加到 session,提交。
pythonfrom flask import Flask, request, redirect, url_for from flask_sqlalchemy import SQLAlchemy app = Flask(__name__) app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///example.db' app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False db = SQLAlchemy(app) class User(db.Model): id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(80), unique=True, nullable=False) email = db.Column(db.String(120), unique=True, nullable=False) def __repr__(self): return '<User %r>' % self.username with app.app_context(): db.create_all() @app.route('/add', methods=['POST']) def add_user(): if request.method == 'POST': username = request.form['username'] email = request.form['email'] new_user = User(username=username, email=email) db.session.add(new_user) # 添加到 session db.session.commit() # 提交到数据库 return redirect(url_for('index')) # 重定向到首页 return "Add User Form"读取 (Read):
- 使用
query对象进行查询。 User.query.all(): 获取所有用户。User.query.get(id): 根据 ID 获取用户。User.query.filter_by(username='xxx').first(): 根据用户名获取第一个用户。User.query.filter(User.email.like('%@example.com%')).all(): 使用filter进行更复杂的查询 (like, 比较运算符等)。
python@app.route('/') def index(): users = User.query.all() # 查询所有用户 return render_template('index.html', users=users)- 使用
更新 (Update):
- 获取要更新的实例。
- 修改实例的属性。
- 添加到 session,提交。
python@app.route('/update/<int:user_id>', methods=['POST']) def update_user(user_id): user = User.query.get_or_404(user_id) if request.method == 'POST': user.username = request.form['username'] user.email = request.form['email'] db.session.commit() return redirect(url_for('index')) return render_template('update.html', user=user)删除 (Delete):
- 获取要删除的实例。
- 从 session 中删除。
- 提交。
python@app.route('/delete/<int:user_id>') def delete_user(user_id): user = User.query.get_or_404(user_id) db.session.delete(user) db.session.commit() return redirect(url_for('index'))
Flask 中的中间件 (Middleware)?
- 在请求到达视图函数之前或响应返回给客户端之后执行的代码。
- 可以用于日志记录、身份验证、请求处理等。
- 使用
app.before_request,app.after_request,app.teardown_request装饰器。
pythonfrom flask import Flask, request, jsonify app = Flask(__name__) @app.before_request def before_request_callback(): print("Before request...") # 可以进行身份验证,日志记录等操作 @app.after_request def after_request_callback(response): print("After request...") # 可以修改响应,设置响应头等 return response @app.route('/') def hello(): return jsonify({'message': 'Hello, World!'})如何部署 Flask 应用?
- 使用 WSGI 服务器 (例如 Gunicorn, uWSGI)。 WSGI 服务器将请求转发给你的 Flask 应用。
- 使用反向代理服务器 (例如 Nginx, Apache)。 反向代理可以处理静态文件、负载均衡、SSL 证书等。
- 云服务平台 (例如 AWS, Google Cloud, Heroku)。 这些平台提供了方便的部署和管理工具。
- 部署步骤 (典型):
- 准备代码: 确保你的 Flask 应用代码已准备好 (包括
requirements.txt)。 - 选择 WSGI 服务器: 例如 Gunicorn:
gunicorn --workers 3 --bind 0.0.0.0:5000 app:app(假设你的 Flask 应用在app.py中,app是 Flask 实例) - 配置反向代理 (可选): 如果需要负载均衡、SSL 等,配置 Nginx 或 Apache。
- 设置环境变量: 设置必要的环境变量 (例如,数据库连接字符串、密钥)。
- 启动服务: 启动 WSGI 服务器,或者配置云服务平台。
- 准备代码: 确保你的 Flask 应用代码已准备好 (包括
RESTful API 相关
RESTful API 的概念是什么?
- Representational State Transfer,一种设计风格。
- 使用 HTTP 方法 (GET, POST, PUT, DELETE) 对资源进行操作。
- 使用 JSON 或 XML 作为数据交换格式。
- 核心原则:
- 客户端-服务器: 客户端和服务器分离。
- 无状态性: 服务器不保存客户端的状态。 每个请求都包含所有必要的信息。
- 缓存: 可以缓存服务器的响应,提高性能。
- 统一接口: 使用统一的接口 (HTTP 方法) 来操作资源。
- 分层系统: 客户端可以访问中间层,隐藏服务器的复杂性。
Flask 中如何创建 RESTful API?
- 使用 Flask 的路由和视图函数,处理 HTTP 请求。
- 使用
request对象获取请求数据。 - 使用
jsonify()返回 JSON 响应。 - 可以结合 Flask-RESTful 或 Flask-RESTX 等扩展,简化 API 的创建。
HTTP 方法 (GET, POST, PUT, DELETE) 的作用是什么?
- GET: 获取资源。 幂等 (多次执行结果一致)。
- POST: 创建资源。
- PUT: 更新资源 (完整替换)。 幂等。
- PATCH: 更新资源 (部分更新)。
- DELETE: 删除资源。 幂等。
- 幂等性: 多次执行相同操作,结果一致。例如,PUT 和 DELETE 是幂等的,而 POST 通常不是。
HTTP 状态码的作用是什么?有哪些常见的状态码?
- 表示服务器对客户端请求的处理结果。
- 2xx (成功):
- 200 OK (成功)
- 201 Created (已创建)
- 204 No Content (成功,但没有内容返回)
- 3xx (重定向):
- 301 Moved Permanently (永久移动)
- 302 Found (临时移动)
- 304 Not Modified (未修改,使用缓存)
- 4xx (客户端错误):
- 400 Bad Request (错误请求)
- 401 Unauthorized (未授权)
- 403 Forbidden (禁止访问)
- 404 Not Found (未找到)
- 405 Method Not Allowed (方法不允许)
- 422 Unprocessable Entity (请求格式正确,但语义错误,例如,数据验证失败)
- 5xx (服务器错误):
- 500 Internal Server Error (服务器内部错误)
- 503 Service Unavailable (服务不可用)
其他
解释一下你对单元测试、集成测试和端到端测试的理解?
- 单元测试: 测试单个函数或类的方法。 目的是验证代码的最小单元是否按预期工作。 编写单元测试时,通常需要 mock 依赖项。
- 集成测试: 测试多个模块协同工作的情况。 验证模块之间的交互是否正确。
- 端到端测试: 测试整个系统的功能,模拟用户操作。 从用户角度出发,测试系统是否满足业务需求。
你在 Python 项目中遇到的最大的挑战是什么?你是如何解决的? (准备好项目经验,包括具体技术,解决问题的步骤,和学到的东西) 例如:
- 性能问题 (如何分析,如何优化)
- 数据库问题 (SQL 优化,ORM 问题)
- 依赖管理问题 (虚拟环境,包版本冲突)
- 代码可读性和可维护性问题 (代码风格,重构)
- 团队协作问题 (代码审查,沟通)
你最喜欢的 Python 特性是什么? (例如,列表推导式、装饰器、生成器等) 为什么喜欢? 解释其优点和应用场景。
你最熟悉的 Python 库是什么? (准备好相关的项目经验,说明你为什么熟悉它,它解决了什么问题,你的使用经验)
面试准备建议:
- 回顾基础知识: 确保你对 Python 的基本概念 (数据类型、控制流、函数等) 有清晰的理解。
- 动手实践: 编写代码,解决一些小问题,加深对 Python 的理解。
- 准备项目经验: 准备好分享你参与过的项目,着重描述你做了什么,遇到了什么问题,以及如何解决的。 准备一个简短的 Flask 项目示例。
- 清晰表达: 用清晰的语言解释你的理解,展示你的沟通能力。
- 积极思考: 如果不知道答案,可以尝试分析问题、给出你的思路,或者说明你如何查找答案。
- 提问: 面试结束时,可以向面试官提问,了解更多关于公司和团队的信息。 例如:
- 团队使用的技术栈
- 团队的开发流程
- 你的角色和职责
- 公司的发展方向
- 你未来可能面临的挑战