1. UV工具安装与实战指南 ---linux

参考Python依赖管理新标杆:UV工具安装与实战指南-阿里云开发者社区

2025年,由Rust编写的UV工具横空出世,凭借其10-100倍的安装速度提升和全流程集成能力

安装命令

curl -LsSf https://astral.sh/uv/install.sh | sh

以上不能直接使用还需要设置环境变量,需执行source $HOME/.local/bin/env  后可直接使用

echo 'export UV_INDEX_URL=https://pypi.tuna.tsinghua.edu.cn/simple' >> ~/.bashrc
source ~/.bashrc

可自行尝试以下命令,安装速度的确超快好评,请先执行uv init

uv init  # 重点,需要先执行
uv add requests   # 安装生产依赖
uv add pytest --dev  # (如测试工具)
uv add pandas # 安装插件及其依赖
uv add -r requirements.txt  ## 批量安装
uv python list # 列出可用Python版本
uv venv --python 3.12 my_env # 创建使用3.12的环境
uv run python main.py 无需手动激活,直接运行脚本

2.自定义lib库设置环境变量

1.   查看python环境变量

import sys
print(sys.path) 
#运行结果: ['','/usr/lib/python38.zip', '/usr/lib/python3.8', '/usr/lib/python3.8/lib-dynload', '/usr/local/lib/python3.8/dist-packages','/usr/lib/python3/dist-packages']

2. 上述内容可知python可用的变量路径 如 /usr/local/lib/python3.8/dist-packages,就很方便放置自定义的lib库,一种方式是直接把文件copy到这个路径下。第二种方法是着重介绍的

  到 /usr/local/lib/python3.8/dist-packages 路径下,创建一个 .pth文件

# vim /usr/local/lib/python3.8/dist-packages/suiyi_name.pth  将类似以下内容贴入其中
/root/work/lib
./aa/ss/ff  # 可以使用相对路径
/root/任意你想导入的路径地址/

3.魔术方法

        看过python库源代码朋友会有些困扰(特别是我),代码看起来有些似懂非懂,有些代码不知道哪里会生效,特别如__del__,__len__等,本文学习下核心的几类魔术方法。

 以下代码

import  os, json, sys
from loguru import logger       
class Study:
    def __init__(self, numb = 2 , nnn = 4): 
        self.numb = numb
        logger.info(f"__init__是最常用的魔术方法。一般在_new__之后运行, 这里打印下变量:numb = {self.numb}")
        logger.info(f"这里打印下__inti__的接收到的变量:self.numb = {self.numb}, nnn = {nnn}") 
        logger.info(f"———————————————————————————————————————————————————————————————————————————————————————————————————————————————\n")  
        
    def __new__(cls, nnn = 4, *args, **kwargs): # 它的职责是创建并返回一个类的实例   # 第一个参数应为 cls   
        logger.info("一般不需要重写 __new__方法。初始化工作应全部放在 __init__中, 建议不要用")
        logger.info(f"__new__实例时第一个被调用的方法。它负责创建并返回一个新的实例。通常不需要重写,除非你需要控制实例的创建过程(如实现单例模式或继承不可变类型)")
        instance = super().__new__(cls)  # 创建实例 
        instance.nnn = nnn  # 这是在设置实例属性      # 如果需要,可以在返回实例前对其进行一些操作 
        logger.info(f"__new__这里只显式声明nnn变量值:{nnn},这里只会关注这一个变量")
        logger.info(f"——————必须返回(return)这个实例  不然不会继续执行下面的代码——————")
        logger.info(f"———————————————————————————————————————————————————————————————————————————————————————————————————————————————\n")
        return instance   # 没有retrun 不会执行 __init__  
    
    def __del__(self): # 析构方法。当对象即将被垃圾回收时调用,常用于清理非内存资源(如关闭文件)。但它的调用时机不确定,不建议依赖它做重要清理工作 
        logger.info(f"__del__执行,实例销毁成功")
          
if __name__ == '__main__': 
    s = Study(nnn=3 ,numb=55)
    del s  # 销毁实例

4.self 和cls

下述是以上代码中用到的的介绍

下述是以上代码中*args和**kwargs介绍

        用于处理函数参数的强大工具,它们让你能够编写可以接受任意数量参数的函数,从而大大提升了代码的灵活性和可重用性

5.装饰器 

以下是 自定义了一个非常实用的装饰器 

作用是运行中的产物,放置在对应的py文件的对应的目录树的目录中  ,目录由引用装饰器的函数的 文件名,类名,函数名等组成,非常方便排查问题。

如:py路径未 /root/a/b/c/d/e/f.py  返回目录:/root/a/reports/b/c/d/e/f  

from pathlib import Path
import os,inspect
from functools import wraps 
def save_dir(func):  
    source_file = inspect.getsourcefile(func)
    line_number = inspect.getsourcelines(func)[1]  
    @wraps(func)
    def wrapper(*args, **kwargs):    # 如果args非空,第一个参数通常是实例或类(对于类方法) 
        # 如果引用的函数,无save_dir 则会报错
        if args:
            class_obj = args[0]
            class_name = class_obj.__class__.__name__  # 对于实例方法,是实例的类;对于类方法,是类本身。 
        else:
            class_name = None
        method_name = func.__name__
        # class_module = inspect.getmodule(class_obj)
        # 方法2:使用之前记录的装饰器源文件信息
        # print(f"装饰器应用位置: {source_file}:{line_number}") 
        # if class_module and hasattr(class_module, '__file__'):
        #     class_file = os.path.abspath(class_module.__file__)
        #     print(f"类定义文件: {class_file}") 
        file_name = os.path.splitext(os.path.basename(source_file))[0]  
        py_dir_path = os.path.dirname(os.path.abspath(source_file))
        d_path = py_dir_path.split("obf_test_framework/tests/")[-1]       # logger.info(py_dir_path)  
        product_path = "/root/zzz"
        if class_name:
            save_dir = Path(product_path) / d_path / file_name/ class_name / method_name 
        else:
            save_dir = Path(product_path)/ d_path / file_name/ method_name  
        kwargs['save_dir'] =  save_dir  
        os.makedirs(save_dir,exist_ok=True)
        return func(*args, **kwargs) 
    return wrapper

# ----------如在其他文件中使用此装饰器如---------------

#from xxxx import save_dir  # 导入装饰器
class aa:  
    @save_dir
    def a(self, save_dir = None):
        print(save_dir)  
aa().a() 
@save_dir
def ass(  save_dir = None):
    print(save_dir)  
ass()
#打印结果
#root@RobocarL4-8650-012:~/obf_test_framework# sudo .venv/bin/python xxxx /pp.py
#/root/xxxxtest/pp/aa/a
#/root/xxxxtest/pp/ass

6.参数的继承与修改

场景1,在一个类的实例化中有很多参数,需要再类的方法中对这些参数进行赋值,由于参数数量多,且不同的用处赋值的参数也会有变化,那么怎么简洁高效的解决,原代码如下

class A:
    def __init__(self):
        self.a ,self.b,self.d ,self.e = 2 ,34, 34,22 
    def sss(self,aa=None,bb=None):
        if aa:
            self.a = aa 
        if bb:
            self.bb = bb
            '''等等'''
        print(self.a,self.b) 
if __name__ == "__main__":
    A().sss(aa=9)

方案1,利用上述的**kwargs可轻易实现

setattr()是 Python 的内置函数,用于动态设置对象的属性值。赋值用的

class A:
    def __init__(self):
        self.a ,self.b,self.d ,self.e = 2 ,34, 34,22  
    def sss(self, **kwargs):
        for key, value in kwargs.items():
            if hasattr(self, key):  # 只更新已存在的属性
                setattr(self, key, value)
            else: 
                setattr(self, key, value)       # 可以选择动态创建新属性
        for key, value in self.__dict__.items():    # 打印所有实例属性
            if not key.startswith('__'):
                print(f"{key}: {value}") 
if __name__ == "__main__":
    A().sss(a=9, b=30, c=150)

方案2. 装饰器

def update_and_print(func): #  """装饰器:更新属性后自动打印""" 
    def wrapper(self, **kwargs): 
        for key, value in kwargs.items():        # 更新属性
            setattr(self, key, value) 
        result = func(self, **kwargs)   # 调用原函数 
        print("更新后的属性:")   # 打印更新后的属性
        for key, value in self.__dict__.items():
            if not key.startswith('__'):
                print(f"  {key}: {value}")
        return result
    return wrapper 
class A:
    def __init__(self, **kwargs):
        self.defaults = {'a': 2, 'b': 23, 'c': 100}
        for key, value in {**self.defaults, **kwargs}.items():
            setattr(self, key, value) 
    @update_and_print
    def update(self, **kwargs): #      """更新任意属性"""
        return kwargs  # 可以返回更新了哪些属性 
if __name__ == "__main__":
    A().update(a=9, d=500)  # 更新a,新增d

hasattr && getattr 变量的操作

hasattr()是 Python ˅一个非常实用的内置函数,用于检查对象是否具有指定的属性或方法

class Read_someip_dbc_excel:
    """SOMEIP Excel 读取器,带缓存功能""" 
    def __init__(self, excel_path=None):
        """初始化Excel读取器"""
        if hasattr(self, '_initialized'):
            return  # 避免重复初始化 

以上是个excel表格读取类,由于该类会被多次调用,故使用此方法 。
hasattr(object, name) # objact是对象,上面代码self,代表类本身。_initialized是变量的名字 
此行的作用是返回object是否有变量name,有的话是true,反只false 
一般用来安全访问变量和动态调用方法等  

getattr(object, name)# 获取变量name的值 
if hasattr(settings, name):
  return getattr(settings, name)

json文件,将其中列表写成一行

写json文件,换行格式化会有利于阅读,但是如果值为列表,换行过多反而不利于查看了,以下代码就是将列表写成一行

def custom_json_dump(data_json, file, indent=2, list_threshold=5, **kwargs):
        """ 自定义JSON导出, 控制列表是否换行   Args: data_json: 要导出的对象    file: 文件对象  indent: 缩进大小  list_threshold: 列表元素超过此数量时换行   """
        def _format(data_json, level=0):
            indent_str = ' ' * (indent * level) 
            if isinstance(data_json, dict):
                items = []
                for k, v in data_json.items():
                    items.append(f'{" " * (indent * (level + 1))}"{k}": {_format(v, level + 1)}')
                return '{\n' + ',\n'.join(items) + f'\n{indent_str}}}' 
            elif isinstance(data_json, list):  # 根据阈值决定是否换行
                if len(data_json) <= list_threshold:   # 短列表不换行
                    items = ', '.join(_format(item, 0) for item in data_json)
                    return f'[{items}]'
                else:    # 长列表换行
                    items = []
                    for item in data_json:
                        items.append(f'{" " * (indent * (level + 1))}{_format(item, level + 1)}')
                    return '[\n' + ',\n'.join(items) + f'\n{indent_str}]' 
            else:
                return json.dumps(data_json, ensure_ascii=False) 
        file.write(_format(data_json))  

#with open(soa_srvid_yml, "w", encoding='utf-8') as f:
#                self.custom_json_dump(data_dict,  f, indent=2, list_threshold=200) 

结果展示:

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐