Python使用特殊方法来处理对象的基本行为,而不是像Java和C#那样使用它们的基类Object
或object
。 Python使用__str__
,当对象传递给print
:
>>> class Demo:
>>> def __str__(self):
>>> return "representation"
>>> d = Demo()
>>> print(d)
representation
与len
相同:
>>> class Ruler:
>>> def __len__(self):
>>> return 42
>>> r = Ruler()
>>> len(r)
42
我期望的是这样的事情:
>>> class Ruler:
>>> def len(self):
>>> return 42
>>> r = Ruler()
>>> r.len()
42
间接使用特殊方法而不是直接调用常用方法的原因是什么?
答案 0 :(得分:13)
这里的原因在Python文档中有很好的解释:
主要原因是历史。功能 用于那些操作 对于一组类型而言是通用的 它们的目的是为了工作 没有方法的对象 所有(例如元组)。也是 方便有一个功能可以 容易应用于无定形 使用时的对象集合 Python的功能特性(map(), apply()et al)。
实际上,实现len(),max(), min()作为内置函数 实际上代码少于实现 它们作为每种类型的方法。一罐 关于个别案件的狡辩但是 它是Python的一部分,它也是 迟到做出这样根本性的改变 现在。功能必须保持 避免大规模的代码破坏。
(评论中对此进行了回答,但为了未来的读者,需要将其作为真正的答案。)
答案 1 :(得分:4)
这些不是钩子。
它们只是具有特殊名称的方法。
Python中特殊方法名称的约定是__name__
。
内置的len,iter,str,repr(和其他)函数使用普通方法,其名称遵循特殊约定,这样我们就可以确保我们已经正确地实现了特殊方法。
特殊方法具有奇怪的名称,因此我们可以自由使用我们想要的任何名称,而不必担心碰撞。
obj.len()实现和使用会更加直观。
或许对你而言。对其他人来说,这可能是完全莫名其妙。
对于许多常见函数,Python都有两种方法符号和函数表示法。
首选函数表示法。
它仍然是OO编程。只有符号已被更改。
答案 2 :(得分:0)
Hooks允许重新定义标准函数的行为。考虑覆盖__add__()
并使用标准中缀+
运算符与添加自定义add()
并使用嵌套调用。
此外,如果您定义__iter__()
,则可以在for ... in
循环中使用您的对象。将其与控制循环和手动推进迭代进行比较。考虑重写__call__()
并将实例转换为函数,与任何其他函数一样好。这提供了极大的灵活性。
如果需要,Java会对.toString()
执行相同操作,当您打印对象或将其连接到字符串时,它会隐式工作。
答案 3 :(得分:0)
不是Pythonista,所以这可能会有所不同,但如果我理解你的问题,我的印象是它是一种风格和习惯而不是行为。 Java(以及较小程度上的C#)是非常冗长,规范和正交的语言。一切都是一个对象(或者对于C#,表现就像一个 - IIRC int.toString()
是有效的),你应该明确表达你的程序所做的一切。
Python更简洁,重视便利,偶尔会牺牲清晰度。您也会在C ++中看到这一点,隐式转换和操作重载。只需考虑您的toString()
示例的C ++模拟:
std::ostream& operator<<(std::ostream& outstream, const Widget& rhs)
{
return outstream << rhs.name();
}
std::cout << myWidget;