背景:
最近在做大模型相关产品研发过程中,需要用到python,由于博主之前主要是Java方面的开发,以前也用过python开发过项目,但是一直没有确定的规范约束,在对python进行了一段时间的研究后,对python编程规范做一些小小的总结,文章内容为开发过程中的亲身经验,希望给有需要的同学一些帮助!
注:本文极有可能是python系列的开端,具体根据博主的时间来看,敬请期待~~
一、python编写类的规范:
在 Python 中编写类时,有一些约定俗成的规范和最佳实践,这些规范帮助代码更具可读性和一致性。以下是一些常见的规范和示例:
1. 类名命名规范
- 命名风格: 类名通常使用驼峰式命名法(CamelCase),即每个单词的首字母都大写,并且没有下划线。
- 示例
class MyClass:
pass
class CustomerAccount:
pass
2.类定义
- 类的定义: 使用
class
关键字定义类,类名后跟括号和冒号。 - 示例:
class Car:
def __init__(self, make, model, year):
self.make = make
self.model = model
self.year = year
def start_engine(self):
print(f"The {self.make} {self.model}'s engine is now running.")
3.方法和属性
- 方法命名: 方法名使用小写字母和下划线(snake_case),以提高可读性。
- 属性: 属性(变量)的命名也使用小写字母和下划线。
- 示例
class Employee:
def __init__(self, name, position):
self.name = name
self.position = position
def get_details(self):
return f"Name: {self.name}, Position: {self.position}"
4. 调用类和方法
- 实例化类: 使用类名加括号创建对象(实例)。
- 调用方法: 使用点(
.
)运算符调用对象的方法。 - 示例:
# 实例化类
my_car = Car("Toyota", "Corolla", 2022)
# 调用方法
my_car.start_engine() # 输出: The Toyota Corolla's engine is now running.
# 创建一个员工对象
emp = Employee("Alice", "Engineer")
# 获取员工详细信息
print(emp.get_details()) # 输出: Name: Alice, Position: Engineer
5. 文档字符串
- 文档字符串: 每个类和方法通常都应该包含一个文档字符串(docstring),描述其功能。
- 示例:
class Rectangle:
"""
A class to represent a rectangle.
"""
def __init__(self, width, height):
"""
Initialize the rectangle with width and height.
"""
self.width = width
self.height = height
def area(self):
"""
Calculate the area of the rectangle.
"""
return self.width * self.height
6. 特殊方法
- 特殊方法: 在类中,前后都有双下划线的方法被称为特殊方法(如
__init__
,__str__
),它们通常用于实现类的特殊行为或重载运算符。 - 示例:
class Circle:
def __init__(self, radius):
self.radius = radius
def __str__(self):
return f"Circle with radius {self.radius}"
def area(self):
import math
return math.pi * (self.radius ** 2)
总结
- 类名: 驼峰式命名(CamelCase)。
- 方法和属性: 小写字母和下划线(snake_case)。
- 实例化和方法调用: 使用类名创建实例,并通过点(
.
)调用方法。 - 文档字符串: 为类和方法提供简洁的说明。
遵循这些规范和最佳实践可以使你的 Python 代码更加规范和易于维护。
二、文件名命名规范
文件名的命名规范在 Python 编程中也很重要,因为它可以提高代码的组织性和可读性。以下是一些常见的文件名命名规范和最佳实践:
1. 文件名使用小写字母和下划线
- 命名风格: 文件名通常使用小写字母,并用下划线分隔单词,以提高可读性。
- 示例:
my_script.py
data_processing.py
utils_helpers.py
2. 避免使用特殊字符和空格
- 规范: 文件名中应避免使用特殊字符(如
@
,!
,#
,*
等)和空格。使用下划线代替空格是推荐的做法。 - 示例:
- 不推荐:
my script.py
,data-processing@2024.py
- 推荐:
my_script.py
,data_processing_2024.py
- 不推荐:
3. 文件名应简洁且描述性强
- 规范: 文件名应简洁明了,能够清楚地描述文件的内容或功能。
- 示例:
database_connection.py
适用于处理数据库连接的脚本。config_reader.py
适用于读取配置文件的脚本。
4. 避免使用与 Python 内置模块相同的名称
- 规范: 避免使用与 Python 标准库模块或常用第三方库模块相同的名称,以防止命名冲突。
- 示例:
- 避免:
json.py
(因为 Python 标准库有一个json
模块) - 推荐:
custom_json_parser.py
- 避免:
5. 使用一致的命名风格
- 规范: 在一个项目中,保持一致的命名风格对于文件名非常重要。这样可以使项目结构更加统一和易于理解。
- 示例:
- 如果项目中使用
snake_case
风格,那么所有文件名都应遵循这个风格。 - 如果项目中使用
kebab-case
(虽然不常见),那么所有文件名都应遵循这个风格(如data-processing-script.py
)。
- 如果项目中使用
6. 包和模块文件名
- 模块: 模块文件名通常是单个 Python 文件,用于实现特定的功能。
- 包: 包是包含
__init__.py
文件的目录,目录名也应使用小写字母和下划线。例如:my_package/
。
示例
-
脚本文件:
main.py
:主要执行脚本。helpers.py
:包含辅助函数的脚本。data_analysis.py
:进行数据分析的脚本。
-
包:
my_project/
__init__.py
:标识my_project
目录为一个包。module_one.py
:包中的第一个模块。module_two.py
:包中的第二个模块。
遵循这些文件命名规范可以提高代码的可维护性和可读性,帮助团队成员快速理解文件的内容和目的。
三、文件名和类型规约扩展:
文件名和类型(类名)之间并没有强制的规定必须保持一致,但有一些最佳实践可以帮助提高代码的组织性和可读性:
1.文件名和类型(类名)的关系
-
一致性:
- 实践: 虽然文件名和类名不需要严格一致,但在很多代码风格指南中,推荐让文件名和包含的主要类名保持一致,以便更容易识别文件的内容。
- 示例: 如果文件
my_class.py
中定义了一个主要的MyClass
类,这种一致性可以使代码更具可读性。
-
单一职责原则:
- 实践: 每个文件(模块)应尽量只定义一个主要的类或功能。这样有助于文件更专注于一个功能,便于维护和理解。
- 示例:
user.py
文件中定义了User
类,而utils.py
中包含了多个工具函数。
2.文件中可以定义多个类吗?
-
可以,但需要注意:
- 实践: 一个文件中可以定义多个类,尤其是当这些类紧密相关时。例如,一个文件中可能包含多个内部类或辅助类。
- 示例: 在
shapes.py
文件中,可以定义Circle
、Square
等多个类,因为它们都与“形状”相关。
-
最佳实践:
- 相关性: 如果多个类在功能上紧密相关,可以放在同一个文件中。例如,定义不同形状的几何图形类可以放在
shapes.py
中。 - 文件大小: 文件中类的数量不应过多,以免导致文件过大和难以管理。如果文件变得很大,可以考虑将类拆分到不同的文件中。
- 可读性: 为了保持代码的可读性,文件中的类定义应具有清晰的注释和组织。每个类的功能和职责应明确,以避免混淆。
- 相关性: 如果多个类在功能上紧密相关,可以放在同一个文件中。例如,定义不同形状的几何图形类可以放在
示例
-
单个类文件:
# user.py
class User:
def __init__(self, name):
self.name = name
def greet(self):
print(f"Hello, {self.name}!")
- 多个类文件:
# shapes.py
class Circle:
def __init__(self, radius):
self.radius = radius
def area(self):
return 3.14 * (self.radius ** 2)
class Square:
def __init__(self, side):
self.side = side
def area(self):
return self.side ** 2
- 文件内的多个类:
# shapes.py
class Circle:
def __init__(self, radius):
self.radius = radius
def area(self):
return 3.14 * (self.radius ** 2)
class Square:
def __init__(self, side):
self.side = side
def area(self):
return self.side ** 2
class Rectangle:
def __init__(self, width, height):
self.width = width
self.height = height
def area(self):
return self.width * self.height
总结来说,文件名和类名的一致性有助于代码的可读性,但并不是强制要求。文件中可以包含多个类,只要它们在功能上相关并且文件不变得过于庞大和难以管理
四、继承与基类
class Position_Model(BaseModel)
在 Python 中,类定义的括号中可以包含一个或多个基类。当你看到像 class Position_Model(BaseModel):
这样的定义时,这意味着 Position_Model
类继承自 BaseModel
类。括号中的 BaseModel
被称为“基类”或“父类”,它是 Position_Model
类的超类。
1.继承:
- 继承允许一个类(子类)获得另一个类(基类)的属性和方法。在这个例子中,
Position_Model
继承了BaseModel
的所有功能,并且可以添加自己的属性和方法,或者覆盖基类中的方法。 - 示例
class BaseModel:
def __init__(self):
self.id = None
def save(self):
print("Saving...")
class Position_Model(BaseModel):
def __init__(self, position_name):
super().__init__() # 调用 BaseModel 的构造函数
self.position_name = position_name
def display(self):
print(f"Position: {self.position_name}")
2.属性定义
在类中定义属性可以在 __init__
构造函数中进行。__init__
是一个特殊的方法,用于初始化类的实例。当你创建类的对象时,__init__
方法会被调用来设置对象的初始状态。
示例:如何在 Position_Model
类中定义属性
使用 __init__
方法定义属性:
class Position_Model(BaseModel):
def __init__(self, position_name, salary):
super().__init__() # 调用 BaseModel 的构造函数
self.position_name = position_name
self.salary = salary
在这个示例中,Position_Model
类的 __init__
方法定义了两个属性:position_name
和 salary
。这些属性可以通过对象的实例访问和修改。
属性定义示例:
# 创建 Position_Model 实例
position = Position_Model(position_name="Software Engineer", salary=90000)
# 访问属性
print(position.position_name) # 输出: Software Engineer
print(position.salary) # 输出: 90000
3.类中定义元组类型的属性:
要在类中定义一个元组类型的属性,可以在 __init__
方法中初始化这个属性,确保其值是一个元组。你可以使用类型注解来标明属性的类型
from typing import Tuple
class MyClass:
def __init__(self, coordinates: Tuple[float, float]):
self.coordinates = coordinates
# 示例
obj = MyClass((12.34, 56.78))
print(obj.coordinates) # 输出: (12.34, 56.78)
说明:
- 类型注解:
coordinates: Tuple[float, float]
表明coordinates
属性应当是一个包含两个浮点数的元组。 - 初始化:在
__init__
方法中,将传入的参数赋值给self.coordinates
,确保属性是一个元组。
总结
- 括号中的基类:括号中包含的是类的基类或父类。基类为子类提供了继承的属性和方法。
- 定义属性:属性通常在
__init__
方法中定义。通过self
关键字访问实例属性。 - 使用
super()
:在子类的__init__
方法中调用super().__init__()
是一种常见的做法,用于初始化基类的属性。
这种继承机制是面向对象编程的一个核心概念,有助于代码的复用和组织。
4.BaseModel
from pydantic import BaseModel的这个BaseModel的作用:
BaseModel
是 Pydantic 库中的一个核心组件。Pydantic 是一个用于数据验证和设置的数据模型库,特别适用于 Python 的数据解析和验证任务。BaseModel
提供了很多有用的功能,使得数据模型的创建和管理更加方便和安全。
BaseModel
的作用
数据验证:
BaseModel
可以自动验证模型中的数据类型和数据值。你可以定义模型属性的类型,Pydantic 会确保实例化时提供的数据符合这些类型。例如,如果你定义一个字段是int
类型,Pydantic 会确保传递的值是整数,否则会抛出验证错误。数据解析:
BaseModel
可以从不同的数据格式(如字典、JSON 等)创建模型实例。它会自动将输入数据解析成适当的类型。例如,你可以从一个 JSON 字符串创建一个模型实例,Pydantic 会解析 JSON 并验证数据。数据转换:
在验证数据的同时,Pydantic 还支持类型转换。例如,将字符串'123'
自动转换为整数123
。自动生成文档:
使用 Pydantic 可以轻松生成 API 文档,因为它可以与 FastAPI 等库集成,这些库能够自动生成 OpenAPI 文档。易于使用的错误处理:
当数据验证失败时,Pydantic 提供清晰且详细的错误信息,帮助开发者迅速定位和解决问题。
示例
以下是使用 BaseModel
的一个简单示例:
from pydantic import BaseModel, ValidationError
from typing import List
class Person(BaseModel):
name: str
age: int
friends: List[str] = []
# 正确的使用
try:
person = Person(name="Alice", age=30, friends=["Bob", "Charlie"])
print(person)
except ValidationError as e:
print(e)
# 错误的使用
try:
person = Person(name="Alice", age="thirty", friends=["Bob", "Charlie"])
except ValidationError as e:
print(e)
解释
-
定义模型:
Person
类继承自BaseModel
,定义了name
(字符串类型)、age
(整数类型)和friends
(字符串列表类型)三个属性。
-
创建实例:
- 如果提供的数据类型正确,
Person
实例将被成功创建,并可以访问属性。 - 如果数据类型错误(如将
age
设置为字符串),Pydantic 将抛出ValidationError
,提供详细的错误信息。
- 如果提供的数据类型正确,
结论
继承 BaseModel
使得类在数据验证、解析和转换方面具有强大的功能和便利性。这对于构建健壮和可靠的数据驱动应用程序尤其重要,特别是在处理外部输入数据时。
BaseModel VS __init__
从规范和开发角度来看,建议使用继承 BaseModel
。BaseModel
提供了自动数据验证、解析和类型转换的功能,显著减少了样板代码和潜在的错误。它还集成了友好的错误处理和数据转换机制,这可以帮助保持代码的简洁性和可靠性。自己编写 __init__
方法虽然可以提供更多的灵活性,但通常需要额外的代码来实现数据验证和解析,增加了出错的风险和维护的复杂性。
使用示例:
pip install pydantic==2.3.0
from pydantic import BaseModel
class PositionModel(BaseModel):
content: str = ""
position: list[tuple[float, float]]
page_num: int
# 调用示例
position_paragraph = PositionModel(
content=content,
position=position,
page_num=page_num
)