提问人:jmg2027 提问时间:9/7/2023 更新时间:9/7/2023 访问量:27
避免在 Python 中循环导入的结构
Structure which avoids circular import in Python
问:
我正在python中构建浮点模型。浮点格式在类中定义,其运算(如乘法...等在其他模块中被定义为类。 以下是目录结构:
.
├── README.md
├── chess.py
├── float_class
│ ├── __init__.py
│ ├── bitstring.py
│ ├── floatbase.py
│ ├── floatclass.py
│ ├── hw_model
│ │ ├── __init__.py
│ │ ├── fp_add
│ │ │ ├── __init__.py
│ │ │ └── fpmul.py
...
└── test.py
float_class.floatclass 具有 Bfloat16/Float32 类,它描述了 fp 本身的定义和行为。float_class.hw_model.fp_add.fpadd 具有 FloatAddition 类,该类描述了用 float_class.bitstring 类描述的浮点加法的行为模型,该类具有位操作类 BitString。 而 Bfloat16/Float32 得到了这些hw_model。{operations} 作为实例,使其成为自己的操作方法。以下是我的一些代码片段:
floatclass.py
from abc import ABCMeta, abstractmethod, abstractclassmethod
from typing import Tuple, Optional, ClassVar, Union, TypeVar, Type, Generic, List
from typing_extensions import Self, TypeAlias
from float_class.hw_model.fp_mul.fpmul import FloatMultiplication as Mul
class FloatBase(metaclass=ABCMeta):
"""
Base class for floating-point numbers.
"""
_sign_bitpos: int = 64
_exponent_bits: int = 11
_mantissa_bits: int = 52
@property
def sign_bitpos(self) -> int:
return self._sign_bitpos
@property
def exponent_bits(self) -> int:
return self._exponent_bits
@property
def mantissa_bits(self) -> int:
return self._mantissa_bits
@property
def bias(self) -> int:
return (1 << (self._exponent_bits - 1)) - 1
@property
def exp_max(self) -> int:
return (1 << (self._exponent_bits - 1))
@property
def mant_max(self) -> int:
return (1 << self._mantissa_bits) - 1
@classmethod
def _bias(cls) -> int:
return (1 << (cls._exponent_bits - 1)) - 1
@classmethod
def _exp_max(cls) -> int:
return (1 << (cls._exponent_bits - 1))
@classmethod
def _mant_max(cls) -> int:
return (1 << cls._mantissa_bits) - 1
def __init__(self, sign: int, exponent: int, mantissa: int,
_sign_bitpos: int = 64,
_exponent_bits: int = 11,
_mantissa_bits: int = 52) -> None:
# call setter in __init__
self._sign_bitpos = _sign_bitpos
self._exponent_bits = _exponent_bits
self._mantissa_bits = _mantissa_bits
self.set(sign, exponent, mantissa)
def set(self, sign: int, exponent: int, mantissa: int) -> None:
self.sign: int = self.set_sign(sign)
self.exponent: int = self.set_exponent(exponent)
self.mantissa: int = self.set_mantissa(mantissa)
def set_sign(self, sign: int) -> int:
if not (sign == 0 or sign == 1):
raise FloatValueError(f"{self.__class__.__name__} sign value must be 0 or 1")
return sign
def set_exponent(self, exponent: int) -> int:
if not 0 - self.bias <= exponent <= self.exp_max:
raise FloatValueError(f"{self.__class__.__name__} exponent value must be in range of {-self._bias()} ~ {self.exp_max}")
return exponent
def set_mantissa(self, mantissa: int) -> int:
if not 0 <= mantissa <= self.mant_max:
raise FloatValueError(f"{self.__class__.__name__} mantissa value must be in range of 0 ~ {self.mant_max}")
return mantissa
# Operations in HW component
def __mul__(self, other: Self) -> Self:
if not isinstance(other, FloatBase):
raise FloatTypeError("Both operands should be FloatBase objects.")
if type(self) is not type(other):
raise FloatTypeError("Both operands should be of the same type.")
multiplication = Mul(self, other)
return multiplication.multiply()
...
class Bfloat16(FloatBase):
_sign_bitpos = 16
_exponent_bits = 8
_mantissa_bits = 7
def __init__(self, sign: int, exponent: int, mantissa: int) -> None:
super().__init__(sign, exponent, mantissa, self._sign_bitpos, self._exponent_bits, self._mantissa_bits)
...
class Float32(FloatBase):
_sign_bitpos = 32
_exponent_bits = 8
_mantissa_bits = 23
def __init__(self, sign: int, exponent: int, mantissa: int) -> None:
super().__init__(sign, exponent, mantissa, self._sign_bitpos, self._exponent_bits, self._mantissa_bits)
fp_mul.py
from float_class import *
from typing import Generic, TypeVar
FloatBaseT = TypeVar('FloatBaseT', bound='FloatBase')
class FloatMultiplication(Generic[FloatBaseT]):
def __init__(self, a: FloatBaseT, b: FloatBaseT) -> None:
self.a = a
self.b = b
def multiply(self):
# If input is Bfloat16, bf16_to_fp32
# Make flag of bf16 input
bf16_input = isinstance(self.a, bf16) & isinstance(self.b, bf16)
...
return
float_class._init_.py
from .floatclass import Bfloat16 as bf16
from .floatclass import Float32 as fp32
from .floatclass import FloatBase
__all__ = ['bf16', 'fp32', 'FloatBase']
test.py
a = bf16(0, 0, 0)
b = bf16(0, 1, 0)
c = a * b
其中返回: ''' 回溯(最近一次调用最后一次): 文件“/root/workspace/git/Bfloat16/test.py”,第 107 行,在 c = a * b 文件“/root/workspace/git/Bfloat16/float_class/floatclass.py”,第 184 行,在 mul return multiplication.multiply() 中 文件“/root/workspace/git/Bfloat16/float_class/hw_model/fp_mul/fpmul.py”,第 17 行,乘法 bf16_input = isinstance(self.a, bf16) & isinstance(self.b, bf16) NameError:未定义名称“bf16” '''
我不明白,因为 bf16 已经在 fpmul.py 中定义了!另外,我在编译循环导入问题时遇到了麻烦。 如何避免此问题?如果我需要重构或调制我的代码,该怎么做?在您的帮助下,我们将不胜感激。
答: 暂无答案
评论