python知识和项目经验

一些功能的实现

从.py文件中获取函数对象和参数 的字典

在给定的Python脚本中,通过模块导入和反射机制,如何动态获取包含模型函数的模块中的函数及其默认参数,并构建一个字典以便后续使用?

解决方案

test.py

# test.py
import numpy as np
def return_inputs(*args):
    return args
# 前处理   要求输入为 X, y, **params  输出为 X_new, y_new
def mahalanobis(X, y,threshold=95):
    mahal_X = np.asarray(X)
    x_mu = mahal_X - np.mean(mahal_X, axis=0)
    cov = np.cov(mahal_X.T)
    inv_covmat = np.linalg.inv(cov)
    left_term = np.dot(x_mu, inv_covmat)
    mahal = np.dot(left_term, x_mu.T)
    d = mahal.diagonal()
    threshold = np.percentile(d, threshold)
    mahal_x = mahal_X[d < threshold]
    return mahal_x, y[d < threshold]

main.py


import test as AF  # 导入包含模型函数的模块
import inspect
def getModelParamsFromAF():

    # 获取模块中的所有成员
    module_members = AF.__dict__.items()

    # 构建models字典
    models = {}
    for name, member in module_members:
        if callable(member):  # 检查成员是否为函数
            # 使用inspect模块获取函数的参数信息
            params = inspect.signature(member).parameters
            default_params = {param: params[param].default for param in params if params[param].default != inspect.Parameter.empty}

            models[name] = (member, default_params)
    return models

print(getModelParamsFromAF())

总结
在这里插入图片描述
本问题涉及在Python脚本中通过模块导入和反射机制,动态获取包含模型函数的模块中的函数及其默认参数,并将其构建成一个字典。通过利用inspect模块获取函数参数信息,作者实现了一个函数getModelParamsFromAF(),该函数返回一个包含模型函数及其默认参数的字典。这种动态获取参数的方法可以方便后续使用,提高代码的灵活性和可维护性。最后,通过print语句输出获取到的模型函数及其默认参数,以便进行进一步的分析和使用。

Python 多进程

相关问题地址
python使用进程池多进程时,如何打印错误信息博客园

在python机器学习中,我想要进行自动调参,这需要比较大的运算能力,但是我发现cpu的性能总是不能跑满,原来是我用了多线程,python对于多线程的支持并不是很好可以看廖雪峰

python多线程为什么不能把多核CPU的性能吃满?
因为Python的线程虽然是真正的线程,但解释器执行代码时,有一个GIL锁:Global Interpreter Lock,任何Python线程执行前,必须先获得GIL锁,然后,每执行100条字节码,解释器就自动释放GIL锁,让别的线程有机会执行。这个GIL全局锁实际上把所有线程的执行代码都给上了锁,所以,多线程在Python中只能交替执行,即使100个线程跑在100核CPU上,也只能用到1个核。

GIL是Python解释器设计的历史遗留问题,通常我们用的解释器是官方实现的CPython,要真正利用多核,除非重写一个不带GIL的解释器。

所以,在Python中,可以使用多线程,但不要指望能有效利用多核。如果一定要通过多线程利用多核,那只能通过C扩展来实现,不过这样就失去了Python简单易用的特点。

不过,也不用过于担心,Python虽然不能利用多线程实现多核任务,但可以通过多进程实现多核任务。多个Python进程有各自独立的GIL锁,互不影响。

目前python团队已经计划在3.13版本以后删除GIL锁CSDN链接

把多线程改成多线程
一个例子,根据自己核心数创建进程,然后把数据写入json文件中最后合并

from multiprocessing import Pool
import multiprocessing
import os, time, random
import json

def long_time_task(name):
    print('Run task %s (%s)...' % (name, os.getpid()))
    start = time.time()
    # 需要保存的数据
    data = {
        "name": str(name)
    }

    # 将数据写入JSON文件
    with open('data'+str(name)+'.json', 'w') as f:
        json.dump(data, f, indent=4)
    end = time.time()
    print('Task %s runs %0.2f seconds.' % (name, (end - start)))

if __name__=='__main__':
    print('Parent process %s.' % os.getpid())
    p = Pool()
    # 获取CPU的核心数
    cpu_cores = multiprocessing.cpu_count()
    print(cpu_cores)
    for i in range(cpu_cores):
        p.apply_async(long_time_task, args=(i,))
    print('Waiting for all subprocesses done...')
    p.close()
    p.join()


    files = []
    file_path = os.path.dirname(__file__)
    for file in os.listdir(file_path):
        if file.find('data') != -1:
            files.append(file)
    merged_data = []

    # 遍历每个文件,读取并解析 JSON 数据,然后添加到合并后的数据列表中
    for file_name in files:
        with open(file_name, 'r') as file:
            print(file_name)
            data = json.load(file)
            merged_data.append(data)

    # 将合并后的数据写入新的 JSON 文件
    with open('merged.json', 'w') as merged_file:
        json.dump(merged_data, merged_file, indent=4)

    print('JSON 文件已合并完成。')

    print('All subprocesses done.')

加进程锁

from multiprocessing import Process, Queue, Pool
import multiprocessing
import os, time, random

def write1(q, lock):
    lock.acquire()  # 加上锁
    for value in ['A', 'B', 'C']:
        print('Put %s to queue...' % value)
        q.put(value)
        time.sleep(random.random())
    lock.release()

def write2(q, lock):
    lock.acquire()  # 加上锁
    for value in ['D', 'E', 'F']:
        print('Put %s to queue...' % value)
        q.put(value)
        time.sleep(random.random())
    lock.release()

if __name__ == '__main__':
    q = Queue()
    manager = multiprocessing.Manager()
    lock = manager.Lock()
    pw1 = Process(target=write1, args=(q, lock))
    pw2 = Process(target=write2, args=(q, lock))
    # 启动子进程pw,写入:
    pw1.start()
    pw2.start()
    # pr.start()
    pw1.join()
    pw2.join()
    # pr.join()
    print('所有数据都写入并且读完')


总结

`在这里插入图片描述

写过另外一个程序

collection_lock = Lock()
def collect_with_retry():
      if collection_lock.acquire(blocking=False):
          try:
              main()
              # break
          except Exception as e:
              self.logger.error(f"Collection failed: {str(e)}")
          finally:
              collection_lock.release()
      else:
          self.logger.warning("Failed to acquire lock for collection after multiple attempts")
if not hasattr(self, 'collection_thread') or not self.collection_thread.is_alive():
    self.collection_thread = Thread(target=collect_with_retry)
    self.collection_thread.daemon = True
    self.collection_thread.start()
else:
    self.logger.warning("Collection is already in progress")



文件所在文件夹外的另一文件导入函数或类

要在一个Python文件中从位于该文件所在文件夹外的另一个文件导入函数或类,你需要确保两个文件都在Python的搜索路径中。假设你有如下的目录结构:

project/
│
├── utils.py
│
└── subfolder/
    └── myfile.py

在这种情况下,utils.py 文件位于 subfolder 文件夹的外面。要从 myfile.py 中导入 utils.py 中的内容,你可以使用几种方法:

方法1: 修改系统路径
myfile.py 中,你可以添加代码来修改系统路径,这样 Python 就可以找到 utils.py 文件。示例如下:

import sys
sys.path.insert(0, '../')

from utils import *

这里 sys.path.insert(0, '../')utils.py 文件所在的上级目录添加到 Python 搜索路径的开始处,确保 Python 可以找到并导入 utils.py

方法2: 使用相对导入
如果你的项目结构适合使用包的结构(即目录中有 __init__.py 文件),你可以使用相对导入。首先,确保每个需要作为包处理的目录中都有一个空的 __init__.py 文件:

project/
│
├── utils.py
│
└── subfolder/
    ├── __init__.py
    └── myfile.py

然后,在 myfile.py 中使用相对导入:

from ..utils import *

注意,使用相对导入时,你的脚本必须作为包的一部分运行,不能直接作为主脚本运行,否则会出错。
即,你需要这样的方式执行代码:

python -m myproject.submodule1.myscript

方法3:使用环境变量
你可以设置 PYTHONPATH 环境变量,使其包括 utils.py 所在的目录。这样,当你运行 Python 时,它会自动将该目录添加到搜索路径中。

在 Unix-like 系统中,你可以在终端中这样设置:

export PYTHONPATH="/path/to/project:$PYTHONPATH"

在 Windows 系统中,你可以在命令提示符中这样设置:

set PYTHONPATH=C:\path\to\project;%PYTHONPATH%

这样设置之后,你可以在 myfile.py 中正常导入:

from utils import *

选择最适合你项目结构和需求的方法来导入模块。如果你正在开发一个较大的项目,考虑使用环境变量或确保你的项目可以作为包运行,这通常更为稳定和灵活。

OS库常用函数

  1. 获取当前工作目录

    import os
    current_directory = os.getcwd()
    print(current_directory)
    
  2. 改变工作目录

    os.chdir('/path/to/directory')
    
  3. 列出目录中的文件

    files = os.listdir('/path/to/directory')
    print(files)
    
  4. 创建新目录

    os.mkdir('new_directory')
    
  5. 删除目录

    os.rmdir('new_directory')
    
  6. 检查文件或目录是否存在

    exists = os.path.exists('/path/to/file_or_directory')
    print(exists)
    
  7. 获取文件大小

    file_size = os.path.getsize('/path/to/file')
    print(file_size)
    

装饰器函数 @…

在这里插入图片描述

在sklearn中看到红框中的函数,于是好奇是什么东西,查到python-函数前一行加@xxxx的含义

在这里插入图片描述

于是找到函数定义:def validate_params(parameter_constraints, *, prefer_skip_nested_validation):
在这里插入图片描述

但是,里面没有定义func参数
于是再看到下面,原来这个函数下面又定义了一个def decorator(func):
这样是可以的嘛?
于是去尝试

def test_func():
    print(1111)
    def inner_func(func):
        func()
        return 

@test_func()
def some_func():
    print("pp")
    return
some_func()

这也不行啊
在这里插入图片描述

进一步了解到,原来:它是通过 functools 重写了装饰器函数,
你要这样写才行

import functools
def test_func():
    print(1111)
    ### 装饰器函数
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            return func(*args, **kwargs)
        return wrapper
    return decorator

@test_func()
def some_func():
    print("pp")
    return

some_func()

下面是具体介绍

@validate_params 装饰器的运作原理

  1. 装饰器定义

    • validate_params 是一个装饰器函数。它的作用是用于验证被装饰函数的参数类型是否符合预设的约束条件。
  2. 参数约束

    • parameter_constraints 是一个字典,用于定义每个参数的允许类型。例如,可以指定某个参数可以是列表或 NumPy 数组。
  3. 内部装饰器

    • decoratorvalidate_params 内部定义的装饰器函数。它接受被装饰的函数 func 作为参数。
  4. 参数绑定

    • wrapper 函数中,使用 signature(func).bind(*args, **kwargs).arguments 将传入的参数与函数的签名进行绑定,生成一个包含所有参数及其值的字典 params
  5. 参数验证

    • 对字典中的每个参数进行检查。使用 any() 函数来判断该参数的值是否符合定义的约束条件。如果不符合,则抛出一个自定义的异常 InvalidParameterError,并提供错误信息。
  6. 调用原函数

    • 如果所有参数都通过了验证,wrapper 函数就会调用原始的被装饰函数 func,并返回其结果。

@validate_params
装饰器的核心功能是自动检查函数参数的类型。这可以帮助开发者在调用函数之前发现潜在的错误,增强代码的健壮性和可维护性。通过这种方式,确保了函数在执行时获得正确类型的输入,从而减少了运行时错误的风险。
我写了一个示例代码:

import functools
import numpy as np
from inspect import signature

class InvalidParameterError(ValueError):
    pass

def validate_params(parameter_constraints, *, prefer_skip_nested_validation):
    """装饰器用于验证函数和方法的参数类型和值。"""
    
    def decorator(func):
        setattr(func, "_parameter_constraints", parameter_constraints)

        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            params = signature(func).bind(*args, **kwargs).arguments
            to_ignore = ["self", "cls"]
            params = {k: v for k, v in params.items() if k not in to_ignore}

            validate_parameter_constraints(parameter_constraints, params, caller_name=func.__qualname__)

            return func(*args, **kwargs)

        return wrapper

    return decorator

def validate_parameter_constraints(parameter_constraints, params, caller_name):
    for param, constraints in parameter_constraints.items():
        if param not in params:
            continue
        value = params[param]
        valid = False
        for constraint in constraints:
            # 检查是否为类型
            if isinstance(constraint, type):
                if isinstance(value, constraint):
                    valid = True
                    break
            # 检查是否为 None
            elif constraint is None and value is None:
                valid = True
                break

        if not valid:
            expected_types = ', '.join(c.__name__ if isinstance(c, type) else str(c) for c in constraints)
            raise InvalidParameterError(f"{caller_name}: '{param}' must be one of types: {expected_types}.")

@validate_params(
    {
        "y_true": [list, np.ndarray],
        "y_pred": [list, np.ndarray],
        "sample_weight": [list, np.ndarray, None],
    },
    prefer_skip_nested_validation=True,
)
def mean_squared_error(y_true, y_pred, *, sample_weight=None):
    """计算均方误差 (MSE)。"""

    if sample_weight is not None:
        sample_weight = np.array(sample_weight)
    
    y_true = np.array(y_true)
    y_pred = np.array(y_pred)

    if sample_weight is not None:
        return np.average((y_pred - y_true) ** 2, weights=sample_weight)
    else:
        return np.mean((y_pred - y_true) ** 2)

# 示例用法
y_true = [3, -0.5, 2, 7]  # 真实值
y_pred = [2.5, 0.0, 2, 8]  # 预测值
print(mean_squared_error(y_true, y_pred))  # 输出均方误差

结果
在这里插入图片描述

sklearn中源码


def validate_params(parameter_constraints, *, prefer_skip_nested_validation):
    """Decorator to validate types and values of functions and methods.

    Parameters
    ----------
    parameter_constraints : dict
        A dictionary `param_name: list of constraints`. See the docstring of
        `validate_parameter_constraints` for a description of the accepted constraints.

        Note that the *args and **kwargs parameters are not validated and must not be
        present in the parameter_constraints dictionary.

    prefer_skip_nested_validation : bool
        If True, the validation of parameters of inner estimators or functions
        called by the decorated function will be skipped.

        This is useful to avoid validating many times the parameters passed by the
        user from the public facing API. It's also useful to avoid validating
        parameters that we pass internally to inner functions that are guaranteed to
        be valid by the test suite.

        It should be set to True for most functions, except for those that receive
        non-validated objects as parameters or that are just wrappers around classes
        because they only perform a partial validation.

    Returns
    -------
    decorated_function : function or method
        The decorated function.
    """

    def decorator(func):
        # The dict of parameter constraints is set as an attribute of the function
        # to make it possible to dynamically introspect the constraints for
        # automatic testing.
        setattr(func, "_skl_parameter_constraints", parameter_constraints)

        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            global_skip_validation = get_config()["skip_parameter_validation"]
            if global_skip_validation:
                return func(*args, **kwargs)

            func_sig = signature(func)

            # Map *args/**kwargs to the function signature
            params = func_sig.bind(*args, **kwargs)
            params.apply_defaults()

            # ignore self/cls and positional/keyword markers
            to_ignore = [
                p.name
                for p in func_sig.parameters.values()
                if p.kind in (p.VAR_POSITIONAL, p.VAR_KEYWORD)
            ]
            to_ignore += ["self", "cls"]
            params = {k: v for k, v in params.arguments.items() if k not in to_ignore}

            validate_parameter_constraints(
                parameter_constraints, params, caller_name=func.__qualname__
            )

            try:
                with config_context(
                    skip_parameter_validation=(
                        prefer_skip_nested_validation or global_skip_validation
                    )
                ):
                    return func(*args, **kwargs)
            except InvalidParameterError as e:
                # When the function is just a wrapper around an estimator, we allow
                # the function to delegate validation to the estimator, but we replace
                # the name of the estimator by the name of the function in the error
                # message to avoid confusion.
                msg = re.sub(
                    r"parameter of \w+ must be",
                    f"parameter of {func.__qualname__} must be",
                    str(e),
                )
                raise InvalidParameterError(msg) from e

        return wrapper

    return decorator




@validate_params(
    {
        "y_true": ["array-like"],
        "y_pred": ["array-like"],
        "sample_weight": ["array-like", None],
        "multioutput": [StrOptions({"raw_values", "uniform_average"}), "array-like"],
    },
    prefer_skip_nested_validation=True,
)
def mean_absolute_error(
    y_true, y_pred, *, sample_weight=None, multioutput="uniform_average"
):
    """Mean absolute error regression loss.

    Read more in the :ref:`User Guide <mean_absolute_error>`.

    Parameters
    ----------
    y_true : array-like of shape (n_samples,) or (n_samples, n_outputs)
        Ground truth (correct) target values.

    y_pred : array-like of shape (n_samples,) or (n_samples, n_outputs)
        Estimated target values.

    sample_weight : array-like of shape (n_samples,), default=None
        Sample weights.

    multioutput : {'raw_values', 'uniform_average'}  or array-like of shape \
            (n_outputs,), default='uniform_average'
        Defines aggregating of multiple output values.
        Array-like value defines weights used to average errors.

        'raw_values' :
            Returns a full set of errors in case of multioutput input.

        'uniform_average' :
            Errors of all outputs are averaged with uniform weight.

    Returns
    -------
    loss : float or ndarray of floats
        If multioutput is 'raw_values', then mean absolute error is returned
        for each output separately.
        If multioutput is 'uniform_average' or an ndarray of weights, then the
        weighted average of all output errors is returned.

        MAE output is non-negative floating point. The best value is 0.0.

    Examples
    --------
    >>> from sklearn.metrics import mean_absolute_error
    >>> y_true = [3, -0.5, 2, 7]
    >>> y_pred = [2.5, 0.0, 2, 8]
    >>> mean_absolute_error(y_true, y_pred)
    0.5
    >>> y_true = [[0.5, 1], [-1, 1], [7, -6]]
    >>> y_pred = [[0, 2], [-1, 2], [8, -5]]
    >>> mean_absolute_error(y_true, y_pred)
    0.75
    >>> mean_absolute_error(y_true, y_pred, multioutput='raw_values')
    array([0.5, 1. ])
    >>> mean_absolute_error(y_true, y_pred, multioutput=[0.3, 0.7])
    0.85...
    """
    y_type, y_true, y_pred, multioutput = _check_reg_targets(
        y_true, y_pred, multioutput
    )
    check_consistent_length(y_true, y_pred, sample_weight)
    output_errors = np.average(np.abs(y_pred - y_true), weights=sample_weight, axis=0)
    if isinstance(multioutput, str):
        if multioutput == "raw_values":
            return output_errors
        elif multioutput == "uniform_average":
            # pass None as weights to np.average: uniform mean
            multioutput = None

    return np.average(output_errors, weights=multioutput)


函数中的*号和**号

在 Python 中,*** 是用于处理函数参数的特殊符号。它们分别表示不同的含义,主要用于处理可变数量的参数和解包操作。以下是详细的介绍:


1. **单星号* 的作用**
* 主要用在以下两种场景:

(1) *定义可变位置参数(args)
在函数定义中,*args 用于接收任意数量的位置参数。这些参数会被打包成一个元组(tuple),供函数内部使用。

def my_function(*args):
    print(args)  # args 是一个元组

my_function(1, 2, 3)
# 输出: (1, 2, 3)
  • *args 中的 args 只是一个约定俗成的名字,你可以使用其他名字,比如 *values
  • 这些参数是按位置传递的,调用时不需要指定参数名。

(2) 解包可迭代对象
在函数调用时,* 可以用来解包一个可迭代对象(如列表、元组等),将其元素作为独立的位置参数传递给函数。

def add(a, b, c):
    return a + b + c

numbers = [1, 2, 3]
result = add(*numbers)  # 等价于 add(1, 2, 3)
print(result)
# 输出: 6

2. **双星号** 的作用**
** 主要用在以下两种场景:

(1) **定义可变关键字参数(kwargs)
在函数定义中,**kwargs 用于接收任意数量的关键字参数。这些参数会被打包成一个字典(dictionary),供函数内部使用。

def my_function(**kwargs):
    print(kwargs)  # kwargs 是一个字典

my_function(a=1, b=2, c=3)
# 输出: {'a': 1, 'b': 2, 'c': 3}
  • **kwargs 中的 kwargs 同样只是一个约定俗成的名字,你可以使用其他名字,比如 **options
  • 这些参数是通过键值对传递的,调用时需要指定参数名。

(2) 解包字典
在函数调用时,** 可以用来解包一个字典,将其键值对作为独立的关键字参数传递给函数。

def greet(name, age):
    print(f"Hello {name}, you are {age} years old.")

info = {"name": "Alice", "age": 25}
greet(**info)  # 等价于 greet(name="Alice", age=25)
# 输出: Hello Alice, you are 25 years old.

3. ***** 的结合使用**
在一个函数定义中,可以同时使用 *args**kwargs,分别处理位置参数和关键字参数。

def my_function(*args, **kwargs):
    print("Positional arguments:", args)
    print("Keyword arguments:", kwargs)

my_function(1, 2, 3, a=4, b=5)
# 输出:
# Positional arguments: (1, 2, 3)
# Keyword arguments: {'a': 4, 'b': 5}

4. **注意事项**

  • 顺序规则:在函数定义中,参数的顺序必须是:

    1. 普通参数
    2. *args
    3. 带默认值的参数
    4. **kwargs

    示例:

    def example(a, b, *args, c=10, **kwargs):
        pass
    
  • 强制关键字参数:从 Python 3 开始,可以通过在 * 后面添加参数来强制要求某些参数必须通过关键字传递。例如:

    def example(a, *, b):
        print(a, b)
    
    example(1, b=2)  # 正确
    example(1, 2)    # 错误,TypeError
    

总结

  • * 用于处理可变数量的位置参数或解包可迭代对象。
  • ** 用于处理可变数量的关键字参数或解包字典。
  • 它们可以单独使用,也可以结合使用,提供了灵活的函数参数处理方式。

如果你有更多具体问题,欢迎继续提问!







遇到的问题

导入路径问题(原本main函数调用它,现在直接运行该文件,导包路径变化)

问题描述
在运行 Python 文件时,可能会遇到以下错误:

ModuleNotFoundError: No module named 'utils'

原因:

  • Python 的模块导入机制依赖于当前工作目录和 sys.path 中的路径。
  • 当直接运行某个文件时,Python 会将该文件所在目录添加到 sys.path,而不是项目的根目录,导致无法正确导入其他模块。

解决方法 (一般再临时调试时候会出现,我推荐使用方法三)

方法 1:修改 sys.path
在代码中手动将项目的根目录添加到 sys.path

import sys
import os

current_dir = os.path.dirname(os.path.abspath(__file__))
project_root = os.path.abspath(os.path.join(current_dir, '..'))

if project_root not in sys.path:
    sys.path.append(project_root)

from utils.subgraph_extraction import *

优点:简单直接,适合快速调试。
缺点:不够优雅,可能不适合复杂项目。


方法 2:使用相对导入
如果项目是一个包(包含 __init__.py),可以使用相对导入:

from ..utils.subgraph_extraction import *

然后从项目的根目录运行脚本:

python -m utils.Core_functions

优点:符合 Python 包管理规范,适合大型项目。
缺点:不能直接运行单个文件,需要调整运行方式。


方法 3:设置环境变量 PYTHONPATH
在运行脚本前,设置环境变量 PYTHONPATH 指向项目的根目录。
比如这样,我原本再根目录调用这个文件,没有问题,但是现在我想要进入这个文件里面运行它
在这里插入图片描述
就会报错:
在这里插入图片描述
这样再运行就没问题了
在这里插入图片描述

  • Linux/MacOS
    export PYTHONPATH=/path/to/your/project
    python utils/Core_functions.py
    
  • Windows(命令提示符)
    set PYTHONPATH=C:\path\to\your\project
    python utils\Core_functions.py
    
  • Windows(PowerShell)
    $env:PYTHONPATH = "C:\path\to\your\project"
    python utils\Core_functions.py
    

优点:无需修改代码,适合团队协作。
缺点:需要每次运行前设置环境变量。

方法 4:使用 IDE 配置工作目录
通过 IDE 配置运行时的工作目录为项目的根目录。

  • PyCharm

    1. 打开运行配置(Run/Debug Configurations)。
    2. 设置 Working Directory 为项目的根目录。
  • VSCode
    .vscode/launch.json 中添加以下配置:

    {
        "version": "0.2.0",
        "configurations": [
            {
                "name": "Run Core_functions",
                "type": "python",
                "request": "launch",
                "program": "utils/Core_functions.py",
                "cwd": "${workspaceFolder}"
            }
        ]
    }
    

优点:适合开发环境,无需修改代码。
缺点:仅适用于特定 IDE。


方法 5:重构项目结构
将所有模块组织为一个包,并通过入口脚本(如 main.py)统一调用。例如:

project/
├── main.py
├── utils/
│   ├── __init__.py
│   ├── Core_functions.py
│   └── subgraph_extraction.py

main.py 中:

from utils.Core_functions import some_function

if __name__ == "__main__":
    some_function()

然后始终通过 main.py 运行项目:

python main.py

优点:规范项目结构,避免路径问题。
缺点:需要对项目进行一定的重构。


总结

  • 临时调试:推荐 方法 1方法 3
  • 长期维护:推荐 方法 2方法 5
  • IDE 开发:推荐 方法 4

根据具体需求选择合适的方法即可!




本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/968692.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Unity下ML-Agents第一个示例

本文写于2025年2月12日&#xff0c;需要提前安装好Anaconda。按文中步骤测试了两次都可正常运行。 一、准备Python端 1.下载并解压 ML-Agents Release 22&#xff08;使用git clone大概率会失败&#xff09; 解压路径为 C:\Users\Administrator&#xff08;Administrator为电…

FastExcel + Java:打造高效灵活的Excel数据导入导出解决方案

作者&#xff1a;后端小肥肠 &#x1f347; 我写过的文章中的相关代码放到了gitee&#xff0c;地址&#xff1a;xfc-fdw-cloud: 公共解决方案 &#x1f34a; 有疑问可私信或评论区联系我。 &#x1f951; 创作不易未经允许严禁转载。 姊妹篇&#xff1a; 基于AOP的数据字典实现…

解决IDEA中gitlab登录只有token选项,没有账号密码选项

如图&#xff0c;当点击gitlab账户登录的时候&#xff0c;只显示server和token&#xff0c;而没有账号选项。期望通过账号密码登录。 解决方式&#xff1a; 插件 - GitLab - 禁用即可。

AI语言模型的技术之争:DeepSeek与ChatGPT的架构与训练揭秘

云边有个稻草人-CSDN博客 目录 第一章&#xff1a;DeepSeek与ChatGPT的基础概述 1.1 DeepSeek简介 1.2 ChatGPT简介 第二章&#xff1a;模型架构对比 2.1 Transformer架构&#xff1a;核心相似性 2.2 模型规模与参数 第三章&#xff1a;训练方法与技术 3.1 预训练与微调…

PHP 中的除以零错误

除以零错误&#xff08;Division by zero&#xff09;是指数字除以零的情况&#xff0c; 这在数学上是未定义的。在 PHP 中&#xff0c;处理这种错误的方式取决于 PHP 版本&#xff1a; PHP 7&#xff1a; 使用 / 运算符会产生一个警告 (E_WARNING) 并返回 false。 使用 intd…

【设计模式】01- 一文理解常用设计模式-“创建型模式”篇

一、前言 最近在复习设计模式&#xff0c;撰写、整理了内容和代码片段&#xff0c;和大家一起交流学习。 设计模式是软件设计中常见问题的典型解决方案。 二、模式分类 模式可以根据其意图或目的来分类。常见的设计模式包括&#xff1a; 创建型模式提供创建对象的机制&#x…

数据结构-链式二叉树

文章目录 一、链式二叉树1.1 链式二叉树的创建1.2 根、左子树、右子树1.3 二叉树的前中后序遍历1.3.1前(先)序遍历1.3.2中序遍历1.3.3后序遍历 1.4 二叉树的节点个数1.5 二叉树的叶子结点个数1.6 第K层节点个数1.7 二叉树的高度1.8 查找指定的值(val)1.9 二叉树的销毁 二、层序…

游戏引擎学习第99天

仓库:https://gitee.com/mrxiao_com/2d_game_2 黑板&#xff1a;制作一些光场(Light Field) 当前的目标是为游戏添加光照系统&#xff0c;并已完成了法线映射&#xff08;normal maps&#xff09;的管道&#xff0c;但还没有创建可以供这些正常映射采样的光场。为了继续推进&…

LSTM变种模型

GRU GRU简介 门控循环神经网络 (Gated Recurrent Neural Network&#xff0c;GRNN) 的提出&#xff0c;旨在更好地捕捉时间序列中时间步距离较大的依赖关系。它通过可学习的门来控制信息的流动。其中&#xff0c;门控循环单元 (Gated Recurrent Unit &#xff0c; GRU) 是…

业务开发 | 基础知识 | Maven 快速入门

Maven 快速入门 1.Maven 全面概述 Apache Maven 是一种软件项目管理和理解工具。基于项目对象模型的概念&#xff08;POM&#xff09;&#xff0c;Maven 可以从中央信息中管理项目的构建&#xff0c;报告和文档。 2.Maven 基本功能 因此实际上 Maven 的基本功能就是作为 Ja…

新一代SCADA: 宏集Panorama Suite 2025 正式发布,提供更灵活、符合人体工学且安全的应用体验

宏集科技宣布正式推出全新Panorama Suite 2025 SCADA软件&#xff01;全新版本标志着 Panorama Suite的一个重要里程碑&#xff0c;代表了从 Panorama Suite 2022 开始并跨越三个版本&#xff08;2022、2023、2025&#xff09;的开发过程的顶峰。 此次重大发布集中在六个核心主…

PAT乙级真题 — 1080 MOOC期终成绩(java)【测试点3超时】

对于在中国大学MOOC&#xff08;http://www.icourse163.org/ &#xff09;学习“数据结构”课程的学生&#xff0c;想要获得一张合格证书&#xff0c;必须首先获得不少于200分的在线编程作业分&#xff0c;然后总评获得不少于60分&#xff08;满分100&#xff09;。总评成绩的计…

【Oracle篇】浅谈执行计划中的多表连接(含内连接、外连接、半连接、反连接、笛卡尔连接五种连接方式和嵌套、哈希、排序合并三种连接算法)

&#x1f4ab;《博主介绍》&#xff1a;✨又是一天没白过&#xff0c;我是奈斯&#xff0c;从事IT领域✨ &#x1f4ab;《擅长领域》&#xff1a;✌️擅长阿里云AnalyticDB for MySQL(分布式数据仓库)、Oracle、MySQL、Linux、prometheus监控&#xff1b;并对SQLserver、NoSQL(…

TCP 端口号为何位于首部前四个字节?协议设计的智慧与启示

知乎的一个问题很有意思&#xff1a;“为什么在TCP首部中要把TCP的端口号放入最开始的四个字节&#xff1f;” 这种问题很适合我这种搞历史的人&#xff0c;大年初一我给出了一个简短的解释&#xff0c;但仔细探究这个问题&#xff0c;我们将会获得 TCP/IP 被定义的过程。 文…

oracle表分区--范围分区

文章目录 oracle表分区分区的原因分区的优势oracle表分区的作用oracle表分区类型一、范围分区二、 创建分区表和使用&#xff1a;1、按照数值范围划分2、按照时间范围3、MAXVALUE2. 向现有表添加新的分区3、 分区维护和重新组织&#xff08;合并/删除&#xff09; oracle表分区…

蓝桥杯(B组)-每日一题(求最大公约数最小公倍数)

题目&#xff1a; 代码展现&#xff1a; #include<iostream> using namespace std; int main() {int m,n,x,y;cin>>m>>n;//输入两个整数int b;bm%n;//取余数xm;//赋值yn;while(b)//当余数不为0的时候{xy;//辗转相除求最小公约数yb;bx%y;}cout<<y<&…

基于STM32的学习环境控制系统设计

&#x1f91e;&#x1f91e;大家好&#xff0c;这里是5132单片机毕设设计项目分享&#xff0c;今天给大家分享的是学习环境控制。 设备的详细功能见网盘中的文章《21、基于STM32的学习环境控制系统设计》&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1uWSZX2zbZwy9sY…

WPS接入DeepSeek模型

1.wps 下载安装 WPS-支持多人在线协作编辑Word、Excel和PPT文档_WPS官方网站 &#xff08;最好是安装最新的wps&#xff09; 2.offieceAi工具下载安装 软件下载 | OfficeAI助手 下载后安装下载下来的两个工具。安装路径可以自行修改 3.打开WPS,点击文件-》 选项-》信任中心 勾…

4. React 中的 CSS

用例中的干净的脚手架的创建可以参考另一篇文章&#xff1a;3.React 组件化开发React官方并没有给出在React中统一的样式风格&#xff1a; 由此&#xff0c;从普通的css&#xff0c;到css modules&#xff0c;再到css in js&#xff0c;有几十种不同的解决方案&#xff0c;上百…

Unity进阶教程AOI算法原理详解

最新课程《全栈双客户端(Unity/Cocos) TurnKey方案》更新了AOI专题&#xff0c;今天分享一下AOI算法的实现原理。 AOI的功能和作用 在MMORPG网路游戏当中&#xff0c;单服同时在线一般都会有几千人。当有个玩家执行一个操作&#xff0c;理想情况下要把玩家的操作广播同步给单…