避免在 Python 中循环导入的结构

Structure which avoids circular import in Python

提问人:jmg2027 提问时间:9/7/2023 更新时间:9/7/2023 访问量:27

问:

我正在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 中定义了!另外,我在编译循环导入问题时遇到了麻烦。 如何避免此问题?如果我需要重构或调制我的代码,该怎么做?在您的帮助下,我们将不胜感激。

命名空间 python-import 循环依赖 项名称错误

评论


答: 暂无答案