在Python中,有没有一种方法可以返回最小值和最大值的自定义值?

在Python中,有没有一种方法可以返回最小值和最大值的自定义值?,python,python-3.x,magic-methods,Python,Python 3.x,Magic Methods,我有一个自定义类 class A: def __init__(self, a, b): self.a = a self.b = b 该类不可iterable或indexable或类似的东西。如果可能的话,我想保持这种状态。有没有可能做如下工作 >>> x = A(1, 2) >>> min(x) 1 >>> max(x) 2 让我想到这一点的是,和在。由于被同样的文档认为是序列类型,我想一定有某种优

我有一个自定义类

class A:
    def __init__(self, a, b):
        self.a = a
        self.b = b
该类不可iterable或indexable或类似的东西。如果可能的话,我想保持这种状态。有没有可能做如下工作

>>> x = A(1, 2)
>>> min(x)
1
>>> max(x)
2

让我想到这一点的是,和在。由于被同样的文档认为是序列类型,我想一定有某种优化可以用于
范围
,也许我可以利用它


也许有一种我不知道的神奇方法可以实现这一点?

是的。当
min
接受一个参数时,它会假定它是一个iterable,对它进行迭代并获取最小值。所以

class A:
    def __init__(self, a, b):
        self.a = a
        self.b = b
    def __iter__(self):
        yield self.a
        yield self.b
应该有用

附加说明:如果您不想使用
\uuuuu iter\uuuuuu
,我不知道该怎么做。您可能希望创建自己的min函数,如果传递给某个
\u min\u
方法的参数中有一个方法,则该函数将调用该方法,并调用旧的
min
方法

oldmin = min
def min(*args):
    if len(args) == 1 and hasattr(args[0], '_min_'):
        return args[0]._min_()
    else:
        return oldmin(*args)

由于同样的文档认为
range
是一种序列类型,因此我认为必须对
range
进行某种优化,也许我可以利用它

没有针对范围的优化,也没有针对
min
/
max
的专门魔术方法

如果你看一看,你会发现在一些参数解析完成后,(即
obj.\uu iter\uuu()
)被用来获取迭代器:

it = PyObject_GetIter(v);
if (it == NULL) {
    return NULL;
}
然后(即
it.\uuuu next\uuu
)在循环中执行,以获取值进行比较:

while (( item = PyIter_Next(it) )) {
    /* Find min/max  */
有没有可能做如下工作

>>> x = A(1, 2)
>>> min(x)
1
>>> max(x)
2
否,如果要使用内置的
min
*唯一的选项是实现迭代器协议


*通过修补
min
,您当然可以让它做任何您想做的事情。显然是以在蟒蛇岛的运营为代价的。但是,如果您认为可以利用一些优化,我建议您创建一个
min
方法,而不是重新定义内置的
min

此外,如果您只有int作为实例变量,并且不介意另一个调用,则始终可以使用
vars
来获取
实例

>>> x = A(20, 4)
>>> min(vars(x).values())
4

没有
\uuuu min\uuuu
\uuuu max\uuuu
特殊方法*。这是一种耻辱,因为
range
已经看到了一些。您可以这样做:

>>> 1000000000000 in range(1000000000000)
False
但除非您想等待很长时间,否则不要尝试:

>>> max(range(1000000000000))
但是,正如所建议的,创建自己的
min
/
max
函数是一个非常好的主意

我会这样做的。更新:删除dunder名称
\uuu min\uuu
,改为
\u min
,建议如下:

永远不要捏造这样的名字;仅按文件规定使用

代码:

我认为这种方法可能更好一点,因为它可以处理一些其他答案没有考虑到的角落案例

请注意,具有
\u min
方法的iterable对象仍将按照常规由
oldmin
使用,但返回值将被特殊方法覆盖

但是,如果
\u min
方法要求迭代器仍然可以使用,则需要对其进行调整,因为迭代器首先被
oldmin
使用

还请注意,如果只通过调用
oldmin
来实现
\uu min
方法,事情仍然可以正常工作(即使使用了迭代器;这是因为在这种情况下
oldmin
会引发
ValueError


*这种方法通常被称为“魔术”,但这不是首选术语

你的意思是不定义
\uuuuuu iter\uuuuuuu
/
\uuuuuuuu next\uuuuuuuuuuuu
?我不确定我是否理解你的困惑。当你说“这个类不适合”,你的意思是“这个类不适合,但我愿意让它适合”,还是“这个类不适合,它绝对必须保持这种方式”?有趣的是,“我在想,一定有某种优化,它对范围是可能的。”,情况似乎并非如此;虽然O(1)min/max算法在理论上应该适用于范围对象,但无论输入类型如何,它似乎都是O(N)。如果你不介意告诉我,我有点好奇为什么你不希望你的对象如此适合。是为了防止用户做一些愚蠢的事情吗?“也许有更好的办法?”克里斯蒂安。我在为
float
数字做一个与
range
相当的东西。我提出了一个解决方案,当指定
步骤时,它是可执行的,否则不可执行。它仍然会提供一个有效的包容测试和一些其他东西,因此
min
max
将是有意义的,即使步骤不存在。我想如果没有明确的步骤,我只能允许它在边界上迭代。这是有道理的,尽管令人失望。我将问另一个问题,如何识别调用方,以便在除了
min
max
之外的任何人试图获取迭代器时,我可以引发异常。我希望你不介意我给另一个人打分。@MadPhysicator我想你不需要为此再发帖了。除非有人读到这里的评论不同意我的观点,否则我认为如果你这样做来检查它应该足够了:@MadPhysicast:不能那样做。(事实上,你甚至在尝试是一个巨大的“重新考虑你的设计决策”的危险信号。)@user2357112你是在拒绝尝试抓住
min
/
max
作为调用方吗?@idjaw:你无法检测到是否有人从
min
/
max
调用你。创造你自己的dunder met