Skip to content

项目开发

编程风格

变量命名

PEP 8要求:

  • 用小写字母拼写,多个单词用下划线连接。
  • 受保护的实例属性用单个下划线开头。
  • 私有的实例属性用两个下划线开头。

__name__ == __'main'__ :在该模块被当作独立模块运行时才执行的语句

具体用法如下:

  1. 性能测试或调试代码
    在开发过程中,可能需要临时添加一些性能测试或调试代码。使用 if __name__ == '__main__': 可以确保这些代码只在直接运行时执行。

示例

# performance_test.py
<div markdown="1" style="margin-top: -30px; font-size: 0.75em; opacity: 0.7;">
:material-circle-edit-outline:  1353 个字 :fontawesome-solid-code: 170 行代码 :material-clock-time-two-outline: 预计阅读时间 7 分钟
</div>
import time

def slow_function():
    time.sleep(2)
    return "Done"

if __name__ == '__main__':
    start_time = time.time()
    result = slow_function()
    end_time = time.time()
    print(f"Result: {result}, Time taken: {end_time - start_time:.2f} seconds")

直接运行

python performance_test.py
输出:
Result: Done, Time taken: 2.00 seconds

导入模块

import performance_test

print(performance_test.slow_function())  # 输出: Done


  1. 脚本与模块的复用
    一个文件既可以作为脚本独立运行,也可以作为模块被其他程序导入。if __name__ == '__main__': 是实现这种复用的关键。

示例

# data_processor.py
def process_data(data):
    return [x * 2 for x in data]

if __name__ == '__main__':
    # 直接运行时处理一些示例数据
    data = [1, 2, 3, 4]
    print("Processed data:", process_data(data))

直接运行

python data_processor.py
输出:
Processed data: [2, 4, 6, 8]

导入模块

import data_processor

data = [10, 20, 30]
print(data_processor.process_data(data))  # 输出: [20, 40, 60]


  1. 命令行工具
    在编写命令行工具时,通常会将工具的主要逻辑放在 if __name__ == '__main__': 块中,以便直接运行脚本时执行工具功能。

示例

# file_utils.py
import sys

def count_lines(filename):
    with open(filename, 'r') as file:
        return len(file.readlines())

if __name__ == '__main__':
    if len(sys.argv) != 2:
        print("Usage: python file_utils.py <filename>")
    else:
        filename = sys.argv[1]
        print(f"Number of lines in {filename}: {count_lines(filename)}")

直接运行

python file_utils.py example.txt
输出:
Number of lines in example.txt: 10

导入模块

import file_utils

print(file_utils.count_lines("example.txt"))  # 输出: 10


  1. 避免副作用
    当模块被导入时,可能会执行一些不必要的代码(如打印日志、初始化变量等)。使用 if __name__ == '__main__': 可以避免这些副作用。

示例

# logger.py
def log(message):
    print(f"LOG: {message}")

if __name__ == '__main__':
    # 直接运行时初始化一些日志
    log("Initializing logger...")

直接运行

python logger.py
输出:
LOG: Initializing logger...

导入模块

import logger

logger.log("This is a test message.")  # 输出: LOG: This is a test message.
- 初始化日志的代码不会执行。


  1. 多文件项目中的入口文件
    在大型项目中,通常有一个主入口文件(如 main.py),用于启动整个程序。其他模块文件可以通过 if __name__ == '__main__': 提供独立运行的功能。

示例

# main.py
from utils import helper

def main():
    print("Starting the program...")
    helper.do_something()

if __name__ == '__main__':
    main()

# utils/helper.py
def do_something():
    print("Doing something...")

if __name__ == '__main__':
    # 直接运行时测试功能
    do_something()

运行 main.py

python main.py
输出:
Starting the program...
Doing something...

直接运行 helper.py

python utils/helper.py
输出:
Doing something...


总结

场景 用途
模块的测试代码 确保测试代码只在直接运行时执行
脚本与模块的复用 让文件既能独立运行,又能被导入
命令行工具 提供命令行接口,方便直接运行
避免副作用 防止导入模块时执行不必要的代码
多文件项目中的入口文件 提供独立运行的功能,同时支持主程序调用
性能测试或调试代码 临时添加测试代码,不影响模块导入

通过 if __name__ == '__main__':,你可以更好地组织代码,使其更灵活、更易于维护。如果还有其他问题,欢迎继续提问!

通过 嵌套作用域,可以将数据隐藏在函数内部,避免使用全局变量,从而减少代码的耦合性和潜在的错误。这种方式利用了 Python 的作用域规则,使得外层函数的变量对嵌套函数可见,但对全局作用域不可见,从而实现了一种封装的效果。

如何通过嵌套作用域隐藏数据?

示例 1:计数器

假设我们需要实现一个计数器,但不想使用全局变量。可以通过嵌套作用域将计数器隐藏在函数内部:

def create_counter():
    count = 0  # 计数器变量,隐藏在 create_counter 的作用域中

    def counter():
        nonlocal count  # 声明 count 是外层作用域的变量
        count += 1
        return count

    return counter  # 返回嵌套函数

# 创建两个独立的计数器
counter1 = create_counter()
counter2 = create_counter()

print(counter1())  # 输出: 1
print(counter1())  # 输出: 2
print(counter2())  # 输出: 1
print(counter2())  # 输出: 2

说明: - count 变量被隐藏在 create_counter 的作用域中,外部无法直接访问或修改。 - 每次调用 create_counter 都会创建一个新的独立计数器,避免了全局变量的污染。


示例 2:缓存函数

通过嵌套作用域,可以实现一个缓存函数,避免重复计算:

def create_cached_function():
    cache = {}  # 缓存数据,隐藏在 create_cached_function 的作用域中

    def cached_function(x):
        if x in cache:
            print("Returning cached result")
            return cache[x]
        else:
            print("Calculating result")
            result = x * x  # 假设这是一个耗时的计算
            cache[x] = result
            return result

    return cached_function  # 返回嵌套函数

# 创建缓存函数
square = create_cached_function()

print(square(2))  # 输出: Calculating result \n 4
print(square(2))  # 输出: Returning cached result \n 4
print(square(3))  # 输出: Calculating result \n 9

说明: - cache 变量被隐藏在 create_cached_function 的作用域中,外部无法直接访问或修改。 - 缓存数据只在 cached_function 内部使用,避免了全局变量的污染。


示例 3:私有数据

通过嵌套作用域,可以模拟私有数据:

def create_person(name, age):
    data = {"name": name, "age": age}  # 私有数据,隐藏在 create_person 的作用域中

    def get_name():
        return data["name"]

    def get_age():
        return data["age"]

    def set_age(new_age):
        nonlocal data
        data["age"] = new_age

    return get_name, get_age, set_age  # 返回嵌套函数

# 创建一个人对象
get_name, get_age, set_age = create_person("Alice", 30)

print(get_name())  # 输出: Alice
print(get_age())   # 输出: 30
set_age(31)
print(get_age())   # 输出: 31

说明: - data 变量被隐藏在 create_person 的作用域中,外部无法直接访问或修改。 - 只能通过返回的嵌套函数(get_nameget_ageset_age)来访问或修改数据,实现了数据的封装。


这就是一种闭包:

闭包(Closure) 是指一个函数能够记住并访问其词法作用域(Lexical Scope)中的变量,即使该函数在其词法作用域之外执行。闭包是函数式编程中的一个重要概念,广泛应用于 Python 等支持嵌套函数的语言中。


闭包的核心特点

  1. 嵌套函数:闭包通常涉及嵌套函数,即在一个函数内部定义另一个函数。
  2. 访问外层变量:内层函数可以访问外层函数的变量(即使外层函数已经执行完毕)。
  3. 延长变量生命周期:闭包使得外层函数的变量不会被销毁,即使外层函数已经返回。

闭包的形成条件

  1. 必须有一个嵌套函数(内层函数)。
  2. 内层函数必须引用外层函数的变量。
  3. 外层函数必须返回内层函数。

闭包的示例

示例 1:闭包的实际应用(计数器)

def create_counter():
    count = 0  # 外层函数的局部变量

    def counter():
        nonlocal count  # 声明 count 是外层作用域的变量
        count += 1
        return count

    return counter  # 返回内层函数

counter1 = create_counter()
print(counter1())  # 输出: 1
print(counter1())  # 输出: 2

counter2 = create_counter()
print(counter2())  # 输出: 1

说明: - counter 是一个闭包,它记住了 create_counter 中的变量 count。 - 每次调用 create_counter 都会创建一个新的独立计数器。


示例 2:闭包的实际应用(缓存函数)

def create_cached_function():
    cache = {}  # 外层函数的局部变量

    def cached_function(x):
        if x in cache:
            print("Returning cached result")
            return cache[x]
        else:
            print("Calculating result")
            result = x * x  # 假设这是一个耗时的计算
            cache[x] = result
            return result

    return cached_function  # 返回内层函数

square = create_cached_function()
print(square(2))  # 输出: Calculating result \n 4
print(square(2))  # 输出: Returning cached result \n 4

说明: - cached_function 是一个闭包,它记住了 create_cached_function 中的变量 cache。 - 缓存数据只在 cached_function 内部使用,避免了全局变量的污染。


颜色主题调整