我面临一个问题,我必须创建很多类,这些类具有很多与物理量相关的属性。我使用
dataclass
来简化此操作。但是,这些属性可以与不同的物理单位相关,我想将这些单位添加为类型提示。我尝试过使用 Annotated
、NewType
和 TypeVar
,但这些解决方案都没有通过 mypy:
from dataclasses import dataclass
from typing import Annotated, NewType, TypeVar
meter = TypeVar('meter', bound=float)
um = Annotated[float, 'um']
ohm = NewType('ohm', float)
@dataclass
class Data:
length_1: meter = 10e-3
length_2: um = 20
R: ohm = 50
> mypy units.py
:units.py:11: error: Type variable "units.meter" is unbound [valid-type]
units.py:11: note: (Hint: Use "Generic[meter]" or "Protocol[meter]" base class to bind "meter" inside a class)
units.py:11: note: (Hint: Use "meter" in function signature to bind "meter" inside a function)
units.py:12: error: Variable "units.um" is not valid as a type [valid-type]
units.py:12: note: See https://mypy.readthedocs.io/en/latest/common_issues.html#variables-vs-type-aliases
units.py:13: error: Incompatible types in assignment (expression has type "int", variable has type "ohm") [assignment]
我知道我在这里的所有情况下都稍微误用了打字模块,但是有什么方法可以实现类似这样的通过 mypy 的东西吗?我想将
float
传递给数据类 __init__
而不是其他特殊类型,然后使用类定义中指定的类型或其他类型在数据类的 __post_init__
中构建一些到 SI 单位的转换相似的。原因主要是为了尽量减少代码冗余,因为我将不得不编写很多泛型类,并且我希望可读性很高。
我会声明一个新类型,它继承自您想要用来表示它的内置类型。例如
class Meter(float):
...
然后您可以在数据类中使用它,如下所示:
@dataclass
class Data:
length_1: Meter = Meter(10e-3)
到目前为止我知道,Python 中没有对物理单位的标准、原生支持。然而,有大量的模块可以管理单位/值对。这是一个小概述。
我第一次使用Pint。尽管这个模块非常成熟并且提供了很多功能,但我个人不喜欢它对注册表的使用和非常冗长的单位表示法。我个人推荐我正在贡献的“scinumtools”包中的“物理单位”模块。下面是一个如何使用它的小例子:
>>> import numpy as np
>>> from scinumtools.units import Quantity, Unit
>>> Quantity(23.34, 'kg*m2/s2').to('erg') # unit conversions
Quantity(2.334e+08 erg)
>>> u = Unit() # calculations with units
>>> 34*u.cm + 53*u.dm
Quantity(5.640e+02 cm)
>>> Quantity(23.34, 'cm', abse=0.03) # uncertainities
Quantity(2.3340(30)e+01 cm)
>>> Quantity(3, 'A').value('dBA') # logarithmic units
9.542425094393248
>>> np.sqrt(Quantity([23,59,20,10], 'm2')) # arrays and NumPy
Quantity([4.796 7.681 4.472 3.162] m)