相反的是互斥的 – 两个论点必须共存。

huangapple go评论75阅读模式
英文:

Opposite of mutually exclusive - two arguments must exist together

问题

Here are the translations for the code parts you provided:

在Python中我有一个从文件中读取字节的函数

def read_bytes(path: pathlib.Path, tohex: bool = True, hexformat: Optional[Callable] = None) -> bytes | hex | Any:

在这个函数中,hex 是用来将字节转换为十六进制的选项。hexformat 是一个可调用对象,用于格式化十六进制。<br>
例如:

read_bytes(pathlib.Path("myfile.txt"), tohex=True, hexformat=str.upper)

是的,这个函数做了不止一件事情,这是不好的实践。但是,这个函数纯粹是理论性的。我只是想出一个具有两个必须一起存在的参数的简单示例而已。

从逻辑上讲,你不能只传递其中一个参数而不传递另一个。你必须同时传递都不传递。因此,如果是这种情况,我想引发一个错误:

def read_bytes(path: pathlib.Path, hex: bool = True, hexformat: Optional[Callable] = None) -> bytes | hex | Any:
    if hex and hexformat is not None:
        raise TypeError("hex and hexformat are ___")

然而,我不知道应该使用什么术语(我把 ___ 作为占位符)。这个术语是什么?<br><br><br>

编辑

我对这个概念还有另一个问题:如果参数中的一个布尔值具有默认值,我应该如何在签名中指定它?<br>

例如,假设我用 toupper 替代 hexformattoupper 是一个布尔值,默认值为 False。我应该像这样指定它吗:

def read_bytes(path: pathlib.Path, tohex: bool = True, toupper: bool = False) -> bytes | hex | Any:

还是像这样:

def read_bytes(path: pathlib.Path, tohex: bool = True, toupper: bool = None) -> bytes | hex | Any:
    if toupper is None:
         toupper = False

在前者中,我无法检查调用者是否明确传递了 toupper 但将 tohex 设置为 False,并在这种情况下引发错误(因为 toupper 有默认值)。另一方面,后者更加冗长。<br>

哪个更好?


Please note that code and technical terminology often remain in English, so some parts may not be translated.

<details>
<summary>英文:</summary>

In python, I have a function to read bytes from a file:
```py
def read_bytes(path: pathlib.Path, tohex: bool = True, hexformat: Optional[Callable] = None) -&gt; bytes | hex | Any:

In this function, hex is whether to convert the bytes to hex. hexformat is a callable which formats the hex. <br>
For example:

read_bytes(pathlib.Path(&quot;myfile.txt&quot;), tohex=True, hexformat = str.upper)

Yes, this function does more than one thing, which is bad practice. However, this function is purely theoretical. I was just trying to come up with an easy example of a function with two arguments that must exist together.

Logically, you cannot pass one of these arguments but not the other. You must pass both or neither. So, if this is the case, I want to raise an error:

def read_bytes(path: pathlib.Path, hex: bool = True, hexformat: Optional[Callable] = None) -&gt; bytes | hex | Any:
    if hex and hexformat is not None:
        raise TypeError(&quot;hex and hexformat are ___&quot;)

However, I don't know what word to use (I put ___ as a placeholder). What is the terminology for this? <br><br><br>

Edit:

I have another problem with this concept: If one of the parameters is a boolean has a default, how should I specify it in the signature? <br>

For example, say I replace hexformat with toupper. toupper is a bool and it defaults to False. Should I specify that like this:

def read_bytes(path: pathlib.Path, tohex: bool = True, toupper: bool = False) -&gt; bytes | hex | Any:

or like this:

def read_bytes(path: pathlib.Path, tohex: bool = True, toupper: bool = None) -&gt; bytes | hex | Any:
    if toupper is None:
         toupper = False

In the former, I cannot check if the caller explicitly passed in toupper but set tohex to False, and raise an error if this is the case (since toupper has a default). On the other hand, the latter is more verbose.<br>

Which is better?

答案1

得分: 2

一般来说,当不同的参数相互依赖时,我的倾向是将它们合并在一起,这样在函数签名中就不可能出现互不兼容的组合。

例如,我可能会这样写:

def read_bytes(path: pathlib.Path, tohex: bool = True, toupper: bool = False) -> bytes | hex | Any:

改为:

class ByteFormat(Enum):
    BYTES = auto()
    HEX_LOWER = auto()
    HEX_UPPER = auto()

def read_bytes(path: pathlib.Path, format: ByteFormat) -> bytes | str:

因为逻辑上有三种格式化输出的方式,用一个具有三个值的枚举要比使用两个布尔值更直观(布尔值有四种可能的组合),或者更糟糕的是使用两个可选的布尔值(有种可能的组合,其中只有三种是有效的)。

另一种选择是使用 typing.overload 来列举可能的组合。这更加复杂,但好处是如果返回类型依赖于参数类型,也可以表达出来:

from typing import overload, Literal

@overload
def read_bytes(path: pathlib.Path, tohex: Literal[False]) -> bytes: ...

@overload
def read_bytes(path: pathlib.Path, tohex: Literal[True], toupper: bool) -> str: ...

def read_bytes(path: pathlib.Path, tohex: bool = True, toupper: bool = None) -> bytes | str:
    # 实际的实现在这里

当你使用静态类型检查器时,对函数的调用会根据 @overload 进行检查,如果调用与任何一个不匹配,就会报错:

read_bytes(pathlib.Path(), False)  # 正常
read_bytes(pathlib.Path(), True, False)  # 正常
read_bytes(pathlib.Path(), True)   # 错误!
# No overload variant of "read_bytes" matches argument types "Path", "bool"
# Possible overload variants:
#     def read_bytes(path: Path, tohex: Literal[False]) -> bytes
#     def read_bytes(path: Path, tohex: Literal[True], toupper: bool) -> str
英文:

In general, when different parameters are dependent on each other as you're describing, my tendency is to combine them so that mutually incompatible combinations are simply not possible within the signature of the function.

For example, I might write:

def read_bytes(path: pathlib.Path, tohex: bool = True, toupper: bool = False) -&gt; bytes | hex | Any:

as:

class ByteFormat(Enum):
    BYTES = auto()
    HEX_LOWER = auto()
    HEX_UPPER = auto()

def read_bytes(path: pathlib.Path, format: ByteFormat) -&gt; bytes | str:

Since there are logically three ways to format the output, it's much more straightforward to express that as an Enum with three values than two bools (which have four possible combinations) or worse, two optional bools (which have nine possible combinations, only three of which will be considered valid).

Another option is to use typing.overload to enumerate the possible combinations. This is more complicated, but it has the benefit that if the return type depends on the argument type, it's possible to express that:

from typing import overload, Literal

@overload
def read_bytes(path: pathlib.Path, tohex: Literal[False]) -&gt; bytes: ...

@overload
def read_bytes(path: pathlib.Path, tohex: Literal[True], toupper: bool) -&gt; str: ...

def read_bytes(path: pathlib.Path, tohex: bool=True, toupper: bool=None) -&gt; bytes | str:
    # actual implementation goes here

When you use a static type checker, calls to the function are checked against the @overloads and you get an error if the call doesn't match any of them:

read_bytes(pathlib.Path(), False)  # ok
read_bytes(pathlib.Path(), True, False)  # ok
read_bytes(pathlib.Path(), True)   # error!
# No overload variant of &quot;read_bytes&quot; matches argument types &quot;Path&quot;, &quot;bool&quot;
# Possible overload variants:
#     def read_bytes(path: Path, tohex: Literal[False]) -&gt; bytes
#     def read_bytes(path: Path, tohex: Literal[True], toupper: bool) -&gt; str

huangapple
  • 本文由 发表于 2023年5月15日 07:00:10
  • 转载请务必保留本文链接:https://go.coder-hub.com/76250019.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定