【Python神技巧】一行代码转蛇形命名,代码规范瞬间提升10倍!
·
前言
大家好,这里是 Charming讲Python编码小技巧 系列专栏。每天分享一个 30-seconds-of-python 仓库中的神级写法,助你告别"屎山"代码,写出让人眼前一亮的 Pythonic 风格!
小技巧内容描述
在Python开发中,你是否遇到过这样的场景:需要将驼峰命名转换为蛇形命名?比如将camelCase转换为camel_case,将SomeMixedString转换为some_mixed_string。
还在手动替换大小写?今天教你一个超实用的技巧,几行代码就能搞定!
from re import sub
def snake(s):
return '_'.join(
sub('([A-Z][a-z]+)', r' \1',
sub('([A-Z]+)', r' \1',
s.replace('-', ' '))).split()).lower()
就这么简单!让我来详细解释一下为什么这么写。
为什么这么用?
核心原理:正则表达式的威力
这个技巧的核心在于使用正则表达式对字符串进行"智能分割":
s.replace('-', ' ')- 先将连字符替换为空格,统一分隔符sub('([A-Z]+)', r' \1', ...)- 在大写字母前插入空格(处理连续大写)sub('([A-Z][a-z]+)', r' \1', ...)- 在大写字母开头的单词前插入空格.split()- 按空格分割成单词列表'_'.join(...).lower()- 用下划线连接并转为小写
举个栗子
# 基础示例
print(snake('camelCase')) # 'camel_case'
print(snake('some text')) # 'some_text'
print(snake('AllThe-small Things')) # 'all_the_small_things'
# 处理复杂混合字符串
print(snake('some-mixed_string With spaces_underscores-and-hyphens'))
# 'some_mixed_string_with_spaces_underscores_and_hyphens'
# 处理连续大写
print(snake('XMLHttpRequest')) # 'xml_http_request'
print(snake('getURLById')) # 'get_url_by_id'
# 处理数字
print(snake('user2Name')) # 'user2_name'
print(snake('API2Version3')) # 'api2_version3'
更多实用场景
场景一:API接口参数转换
# 假设从前端接收到的参数是驼峰命名
def process_user_data(data):
"""处理用户数据,将驼峰命名转换为蛇形命名"""
converted = {}
for key, value in data.items():
converted[snake(key)] = value
return converted
# 测试
user_input = {
'userName': '张三',
'userAge': 25,
'userEmail': 'zhangsan@example.com',
'phoneNumber': '13800138000'
}
processed = process_user_data(user_input)
print(processed)
# 输出: {'user_name': '张三', 'user_age': 25, 'user_email': 'zhangsan@example.com', 'phone_number': '13800138000'}
场景二:数据库字段映射
# 将Python类属性名映射到数据库字段名
class User:
def __init__(self):
self.userId = None
self.userName = None
self.userEmail = None
self.createdAt = None
self.updatedAt = None
def get_db_field_names(model_class):
"""获取模型类对应的数据库字段名"""
return [snake(attr) for attr in dir(model_class) if not attr.startswith('_')]
# 测试
print(get_db_field_names(User))
# 输出: ['user_id', 'user_name', 'user_email', 'created_at', 'updated_at']
场景三:JSON数据规范化
import json
def normalize_json_keys(data):
"""规范化JSON数据的键名"""
if isinstance(data, dict):
return {snake(k): normalize_json_keys(v) for k, v in data.items()}
elif isinstance(data, list):
return [normalize_json_keys(item) for item in data]
else:
return data
# 测试
api_response = {
'userId': 123,
'userName': '张三',
'userProfile': {
'firstName': '三',
'lastName': '张',
'contactInfo': {
'phoneNumber': '13800138000',
'emailAddress': 'zhangsan@example.com'
}
},
'orderHistory': [
{'orderId': 1, 'orderDate': '2024-01-01'},
{'orderId': 2, 'orderDate': '2024-01-15'}
]
}
normalized = normalize_json_keys(api_response)
print(json.dumps(normalized, ensure_ascii=False, indent=2))
# 输出:
# {
# "user_id": 123,
# "user_name": "张三",
# "user_profile": {
# "first_name": "三",
# "last_name": "张",
# "contact_info": {
# "phone_number": "13800138000",
# "email_address": "zhangsan@example.com"
# }
# },
# "order_history": [
# {"order_id": 1, "order_date": "2024-01-01"},
# {"order_id": 2, "order_date": "2024-01-15"}
# ]
# }
场景四:类属性自动转换
class Base:
"""基类,自动处理属性命名转换"""
def __init__(self, **kwargs):
for key, value in kwargs.items():
setattr(self, snake(key), value)
def to_dict(self):
"""将对象转换为字典"""
return {snake(k): v for k, v in self.__dict__.items()}
class User(Base):
pass
# 测试
user = User(userName='张三', userEmail='zhangsan@example.com', userAge=25)
print(user.user_name) # '张三'
print(user.user_email) # 'zhangsan@example.com'
print(user.user_age) # 25
print(user.to_dict()) # {'user_name': '张三', 'user_email': 'zhangsan@example.com', 'user_age': 25}
场景五:代码生成器
def generate_python_class(json_schema, class_name):
"""根据JSON Schema生成Python类"""
fields = []
for field_name, field_type in json_schema.items():
snake_name = snake(field_name)
fields.append(f" self.{snake_name}: {field_type} = None")
class_code = f'''class {class_name}:
"""自动生成的{class_name}类"""
def __init__(self):
{chr(10).join(fields)}
def to_dict(self):
return {{k: v for k, v in self.__dict__.items() if v is not None}}
'''
return class_code
# 测试
schema = {
'userId': 'int',
'userName': 'str',
'userEmail': 'str',
'createdAt': 'str',
'updatedAt': 'str'
}
print(generate_python_class(schema, 'User'))
# 输出:
# class User:
# """自动生成的User类"""
#
# def __init__(self):
# self.user_id: int = None
# self.user_name: str = None
# self.user_email: str = None
# self.created_at: str = None
# self.updated_at: str = None
#
# def to_dict(self):
# return {k: v for k, v in self.__dict__.items() if v is not None}
对比其他方法
方法1:手动替换(繁琐)
def snake_manual(s):
"""手动替换,容易出错"""
result = []
for i, char in enumerate(s):
if char.isupper():
if i > 0 and (s[i-1].islower() or (i+1 < len(s) and s[i+1].islower())):
result.append('_')
result.append(char.lower())
elif char == '-':
result.append('_')
else:
result.append(char)
return ''.join(result)
print(snake_manual('camelCase')) # 'camel_case'
print(snake_manual('XMLHttpRequest')) # 'xml_http_request'
方法2:使用第三方库(依赖外部)
# 需要安装: pip install inflection
import inflection
print(inflection.underscore('camelCase')) # 'camel_case'
print(inflection.underscore('XMLHttpRequest')) # 'xml_http_request'
我们的版本(推荐)
from re import sub
def snake(s):
return '_'.join(
sub('([A-Z][a-z]+)', r' \1',
sub('([A-Z]+)', r' \1',
s.replace('-', ' '))).split()).lower()
对比总结:
- 手动替换:代码冗长,逻辑复杂,容易出错
- 第三方库:功能强大,但需要额外依赖
- 我们的版本:简洁高效,零依赖,功能完整
进阶版本:处理更多边缘情况
from re import sub
def snake_advanced(s, *, uppercase=False):
"""高级版本的snake,支持更多选项"""
# 基础处理
result = '_'.join(
sub('([A-Z][a-z]+)', r' \1',
sub('([A-Z]+)', r' \1',
s.replace('-', ' '))).split())
# 转换大小写
return result.upper() if uppercase else result.lower()
# 测试
print(snake_advanced('camelCase')) # 'camel_case'
print(snake_advanced('camelCase', uppercase=True)) # 'CAMEL_CASE'
print(snake_advanced('XMLHttpRequest')) # 'xml_http_request'
print(snake_advanced('API2Version3')) # 'api2_version3'
性能对比
import time
import inflection
# 测试字符串
test_strings = [
'camelCase',
'some text',
'AllThe-small Things',
'XMLHttpRequest',
'getURLById',
'API2Version3',
'some-mixed_string With spaces_underscores-and-hyphens'
]
# 测试我们的方法
start = time.time()
for _ in range(10000):
for s in test_strings:
snake(s)
print(f"我们的方法: {time.time() - start:.4f}秒")
# 测试第三方库方法
start = time.time()
for _ in range(10000):
for s in test_strings:
inflection.underscore(s)
print(f"第三方库方法: {time.time() - start:.4f}秒")
总结
这个"驼峰命名转蛇形命名"的技巧之所以如此实用,是因为:
- 代码简洁:核心逻辑只有几行正则表达式
- 功能完整:处理了驼峰、连字符、空格等各种情况
- 零依赖:不需要安装任何第三方库
- 通用性强:适用于各种命名转换场景
- 符合规范:Python官方推荐的命名风格
命名规范小贴士
-
Python命名规范(PEP 8):
- 变量/函数:使用蛇形命名
my_variable - 类名:使用驼峰命名
MyClass - 常量:使用全大写
MY_CONSTANT
- 变量/函数:使用蛇形命名
-
何时使用蛇形命名:
- Python变量和函数
- 数据库字段名
- JSON键名(Python风格)
- 配置文件键名
-
何时使用驼峰命名:
- 类名
- JavaScript/Java变量
- API接口参数(某些风格)
今日小技巧: snake() - 一行代码转蛇形命名
适用场景: API参数转换、数据库字段映射、JSON规范化、代码生成等
点赞收藏,每天学一个Python神技巧!
更多推荐


所有评论(0)