有没有一种简单、现代的方法在 Python 3.9+ 中输入提示物理单位?

问题描述 投票:0回答:2

我面临一个问题,我必须创建很多类,这些类具有很多与物理量相关的属性。我使用

dataclass
来简化此操作。但是,这些属性可以与不同的物理单位相关,我想将这些单位添加为类型提示。我尝试过使用
Annotated
NewType
TypeVar
,但这些解决方案都没有通过 mypy:

单位.py

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 单位的转换相似的。原因主要是为了尽量减少代码冗余,因为我将不得不编写很多泛型类,并且我希望可读性很高。

python mypy
2个回答
1
投票

我会声明一个新类型,它继承自您想要用来表示它的内置类型。例如

class Meter(float):
    ...

然后您可以在数据类中使用它,如下所示:

@dataclass
class Data:
    length_1: Meter = Meter(10e-3)

0
投票

到目前为止我知道,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)
© www.soinside.com 2019 - 2024. All rights reserved.