python 使用进阶
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)
结果展示:

更多推荐

所有评论(0)