英文:
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
替代 hexformat
。toupper
是一个布尔值,默认值为 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) -> 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("myfile.txt"), 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) -> bytes | hex | Any:
if hex and hexformat is not None:
raise TypeError("hex and hexformat are ___")
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) -> bytes | hex | Any:
or like this:
def read_bytes(path: pathlib.Path, tohex: bool = True, toupper: bool = None) -> 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) -> bytes | hex | Any:
as:
class ByteFormat(Enum):
BYTES = auto()
HEX_LOWER = auto()
HEX_UPPER = auto()
def read_bytes(path: pathlib.Path, format: ByteFormat) -> 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]) -> 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:
# actual implementation goes here
When you use a static type checker, calls to the function are checked against the @overload
s 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 "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
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论