2011-02-25 64 views
8

Python不使用普通的OOP,如Java和C#使用其基类Objectobject,Python使用特殊的方法来处理对象的基本行为。 Python使用__str__当对象被传递给print它用于:Python中不常见OOP的原因是什么?

>>> 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 

什么间接使用特殊方法而不是直接调用常用方法的原因是什么?

+2

至于\ _ \ _海峡\ _ \ _,按我的理解,它严格等同于Java/C#的toString。 \ _ \ _ str \ _ \ _给出了对象的文本表示,这与打印的内容明显不同 - 将文本表示打印到标准输出。 – ChrisJ 2011-02-25 20:08:18

+4

这是你的意思吗? http://docs.python.org/faq/design.html#why-does-python-use-methods-for-some-functionality-eg-list-index-but-functions-for-other-eg-len-列表 – 2011-02-25 20:16:00

+0

@Thomas是的,这就是答案。也许你想写它作为答案... – deamon 2011-02-25 20:19:04

回答

13

这样做的原因在这里Python文档中很好地解释:

http://docs.python.org/faq/design.html#why-does-python-use-methods-for-some-functionality-e-g-list-index-but-functions-for-other-e-g-len-list

的主要原因是历史。函数 用于那些 对于一组类型通用的操作,而 即使对于没有方法 所有(例如,元组)的对象。它也是 方便有一个函数,当您使用Python(map(), apply()等)的功能特性时,可以很容易地将 应用于非对象集合。

事实上,实施LEN(),MAX(), 分钟(),为内置函数比实施 它们作为针对每种类型的方法 代码实际上更小。有人可能会对个别案例提出质疑,但 它是Python的一部分,它现在太迟了,因此 已经迟到了 。这些函数必须保持为 ,以避免大量代码损坏。

(这是回答的意见,但需要显示为未来的读者着想一个真正的答案。)

+2

你打败了我;-) – 2011-02-25 20:24:32

+1

另一个[良好的论点](http://lucumr.pocoo.org/2011/7/9/python-and-pola/)是像'len'这样的函数导致了更一致的API。 – deamon 2011-12-15 19:06:14

4

这些不是钩子。

它们只是具有特殊名称的方法。

Python中特殊方法名称的约定是__name__

内置的len,iter,str,repr(和其他)函数使用普通的方法,其名称遵循特殊的约定,以便我们都可以确保我们已经正确实施了特殊方法。

特殊的方法有奇怪的名字,所以我们可以自由使用任何我们想要的名称,而不用担心碰撞。


obj.len()会更直观的实现和使用。

给你,也许。对于其他人来说,这可能是完全令人困惑的。

Python有都有许多常用函数的方法符号和函数表示法。

并且函数表示法是优选的。

这仍然是面向对象编程。只有符号已被更改。

+0

好吧,我们称之为“特殊方法”。为什么'__len__'只能间接调用? obj.len()会更直观地实现和使用。 – deamon 2011-02-25 20:15:24

+0

这并不是他的问题的核心。 – FogleBird 2011-02-25 20:23:46

+0

@FogleBird:我很高兴你能理解这个问题的核心。显然,我无法理解它。 – 2011-02-25 20:31:27

0

挂钩允许重新定义标准函数的行为。考虑覆盖__add__()并使用标准中缀+运算符与添加自定义add()并使用嵌套调用。

此外,如果您定义了__iter__(),则可以在for ... in循环中使用您的对象。将它与手动控制循环和前进迭代进行比较。考虑覆盖__call__()并将您的实例转换为函数,与其他函数一样好。这给了巨大的灵活性。

如果你愿意,Java和.toString()一样,当你打印对象或将它连接到一个字符串时,它隐式地工作。

0

不是蟒蛇,所以这可能会离开,但如果我理解你的问题,我的印象是这是一个风格和成语而不是行为的问题。Java和C#在较小程度上都是非常冗长,规范和正交的语言。一切都是对象(或者对于C#,表现为就像一个 - IIRC int.toString()是有效的),并且您的程序所做的一切都应该明确表示。

Python更简洁,重视便捷性,偶尔也会增加清晰度。你也会在C++中看到这一点,其中隐式转换和操作重载。只是考虑到C++模拟到您的toString()例子:

std::ostream& operator<<(std::ostream& outstream, const Widget& rhs) 
{ 
    return outstream << rhs.name(); 
} 

std::cout << myWidget; 
+0

我认为你已经有了一个关于它更简洁的观点 - Python旨在实现显式和紧凑之间的平衡。但是在Python中,一切都是从'object'继承的,如果你想要的话,你可以执行'someint .__ str __()'(它不是推荐的,但它和'str(someint)'相同)。 – 2011-02-25 20:30:20

相关问题