【问题标题】:Why do some methods use dot notation and others don't?为什么有些方法使用点符号而其他方法不使用?
【发布时间】:2015-04-26 13:12:41
【问题描述】:

所以,我才刚刚开始学习 Python(使用 Codecademy),我有点困惑。

为什么有些方法带参数,而有些方法使用点符号?

len() 接受一个参数,但不能使用点符号:

>>> len("Help")
4
>>>"help".len()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'str' object has no attribute 'len'

同样:

>>>"help".upper()
'HELP'
>>>upper("help")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'upper' is not defined

【问题讨论】:

标签: python methods syntax


【解决方案1】:

这里的关键词是方法。函数和方法之间存在细微差别。

方法

是在给定对象的类中定义的函数。例如:

class Dog:
    def bark(self):
        print 'Woof woof!'

rufus = Dog()
rufus.bark() # called from the object

功能

函数是一个全局定义的过程:

def bark():
    print 'Woof woof!'

关于len函数的问题,全局定义的函数调用对象的__len__特殊方法。所以在这种情况下,这是一个可读性问题。

否则,仅适用于某些对象的方法会更好。函数在应用于多个对象时会更好。例如,如何将数字大写?您不会将其定义为函数,您只会将其定义为仅在字符串类中的方法。

【讨论】:

  • 所以,只是为了确认一下——在我上面的例子中,len() 是一个全局函数,而 upper() 是字符串类的一个方法?
  • 您并没有真正了解类特定函数与接受参数的函数。
  • 鱼,这是正确的。仅适用于某些对象的方法会更好。函数在应用于多个对象时会更好。例如,如何将数字大写。你可以将它定义为一个函数,你可以将它定义为一个字符串方法。
  • @MalikBrahimi 您可以lower() 起重机,也可以lower() 字符串,但这是一种方法。事实上,Python 开发者在定义 len() 和其他类似函数时犯了一个错误;如果我们最终定义了__len__(),为什么不首先使用len 方法?
  • @MalikBrahimi 并非所有对象都实现__len__,例如,您不能 len() 一个整数。 lenlower 的用例和实现之间没有区别,除了 len 直接调用 __len__
【解决方案2】:

您所说的“点表示法”是类方法,它们仅适用于具有由类实现者定义的方法的类。 len 是一个内置函数,它接受一个参数并返回该对象的大小。一个类可以实现一个名为len 的方法,如果它愿意的话,但大多数都不会。内置的len 函数有一个规则,如果一个类有一个名为__len__ 的方法,它将使用它,所以这是可行的:

>>> class C(object):
...     def __len__(self):
...             return 100
... 
>>> len(C())
100

"help".upper 正好相反。 string 类定义了一个名为upper 的方法,但这并不意味着还必须有一个名为upper 的函数。原来string模块里面有一个upper函数,但是一般不需要因为实现了类方法就额外实现函数。

【讨论】:

  • 4 个下划线和“self”部分是什么? (我真的很陌生)@tdelany
  • @danielcg,在 Python 的类中,self 表示该类的当前实例(在本例中为 C 的实例)。下划线包围的方法(如__len__)通常在某些时候被Python内部调用,但它们只是一个名称——没有什么特别的(在这种情况下,C.__len__len调用,作为另一个例子, __init__ 是一个类初始化器)。
【解决方案3】:

这就是函数方法之间的区别。如果你只是学习基础知识,也许可以简单地接受这种区别的存在,并且你最终会明白了。

还在这里吗?实际上,这甚至都不难。在面向对象的编程中,在很多事情上,方法比函数更受欢迎,因为这意味着一种类型的对象可以覆盖 版本的方法,而不会影响系统的其余部分。

例如,假设您有一种新的字符串,当您调用.upper() 时,重音字符应该会失去重音。这种类型的实例可以继承str 并且在其他方​​面表现完全相同,基本上是免费的;他们只需要重新定义upper 方法(即使那样,也可能调用基类的方法,并且仅在处理重音小写字符时才更改逻辑)。如果您传入这种新类型的对象(其中需要标准 str),那么期望在字符串上工作的软件将继续工作,甚至不知道区别。

Python 的一个设计原则是一切都是对象。这意味着您可以创建自己的替代品,即使是objectclasstype 等基本的基本对象,即扩展或覆盖您的应用程序或平台的基本语言。

事实上,这发生在 Python 2 中,当时unicode 字符串被引入该语言。许多应用软件继续像以前一样工作,但现在有了unicode 实例,以前编写代码来处理str 实例。 (这种差异在 Python 3 中不再存在;或者更确切地说,被称为 str 并且几乎在任何地方都使用的类型现在称为 bytes 并且仅在您特别想要处理非文本数据时使用。)

回到我们新的upper 方法,想想相反的情况;如果upper 只是标准库中的一个函数,你怎么会考虑修改需要upper 行为不同的软件?如果明天你的老板想让你为lower做同样的事情怎么办?这将是一项艰巨的任务,您必须对整个代码库进行的更改很容易趋向于意大利面条结构,并且可能会引入微妙的新错误。

这是面向对象编程的基石之一,但只有当您在更结构化的介绍中了解其他两三个原则时,它可能真正才有意义。就目前而言,也许快速而肮脏的总结是“方法使实现模块化和可扩展”。

【讨论】:

  • 您可能会问为什么len 不是 一种方法,这将是一个非常好的问题。我认为简短的解释是“遗留”。
猜你喜欢
  • 2010-11-23
  • 1970-01-01
  • 2021-09-28
  • 2019-02-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-11
相关资源
最近更新 更多