什么是Python中的“方法”?
任何人都可以用简单的术语向我解释Python中的“方法”是什么?
在许多初学者的Python教程中,这个词的用法就像初学者已经知道Python中的一个方法是什么一样。 虽然我当然熟悉这个词的一般含义,但我不知道这个词在Python中意味着什么。 所以,请向我解释一下“python”的方法。
一些非常简单的示例代码将非常赞赏,因为一张图片胜过千言万语。
这是一个类的成员的函数:
class C: def my_method(self): print "I am a C" c = C() c.my_method() # Prints "I am a C"
就那么简单!
(还有一些其他的方法,可以让你控制类和函数之间的关系,但是我从你的问题猜测你并不是在问这个问题,而只是基本的问题。)
方法是一个将类实例作为第一个参数的函数。 方法是类的成员。
class C: def method(self, possibly, other, arguments): pass # do something here
正如你想知道它在Python中的具体含义,可以区分绑定方法和非绑定方法。 在Python中,所有的函数(也是这样的方法)都是可以传递和“玩”的对象。 因此,未绑定和绑定方法之间的区别是:
1)绑定方法
# Create an instance of C and call method() instance = C() print instance.method # prints '<bound method C.method of <__main__.C instance at 0x00FC50F8>>' instance.method(1, 2, 3) # normal method call f = instance.method f(1, 2, 3) # method call without using the variable 'instance' explicitly
绑定方法是属于类实例的方法。 在这个例子中, instance.method
被绑定到instance
。 每次绑定方法被调用时,实例都将作为第一个参数自动传递 – 这被称为self
。
2)没有约束的方法
print C.method # prints '<unbound method C.method>' instance = C() C.method(instance, 1, 2, 3) # this call is the same as... f = C.method f(instance, 1, 2, 3) # ..this one... instance.method(1, 2, 3) # and the same as calling the bound method as you would usually do
当你访问C.method
(类内的方法而不是内部的实例)时,你会得到一个未绑定的方法。 如果要调用它,则必须将该实例作为第一个parameter passing,因为该方法未绑定到任何实例。
知道这个区别,你可以使用函数/方法作为对象,比如传递方法。 作为一个示例用例,想象一个API,它可以让你定义一个callback函数,但是你想提供一个方法作为callback函数。 没问题,只要传递self.myCallbackMethod
作为callbackself.myCallbackMethod
,它将自动以实例作为第一个参数被调用。 这是不可能的,像C ++这样的静态语言(或者只有欺骗)。
希望你有这个观点;)我认为你应该知道的方法基础知识。 你也可以阅读更多关于classmethod
和staticmethod
装饰器,但这是另一个话题。
在Python中, 由于对象的types , 方法是一个可用于给定对象的函数 。
例如,如果创buildmy_list = [1, 2, 3]
,那么可以将append
方法应用于my_list
因为它是Python列表: my_list.append(4)
。 所有列表都有一个append
方法,因为它们是列表。
作为另一个例子,如果你创buildmy_string = 'some lowercase text'
, upper
方法可以被应用于my_string
因为它是一个Pythonstring: my_string.upper()
。
列表没有upper
方法,string没有append
方法。 为什么? 由于方法只存在于特定的对象,如果他们已经明确定义了这种types的对象 ,Python的开发人员(迄今)决定,这些特定的对象不需要这些特定的方法。
要调用一个方法,格式是object_name.method_name()
,并且该方法的所有参数都在括号内列出。 该方法隐式地作用于被命名的对象,因此一些方法没有任何陈述的论点,因为对象本身是唯一必要的论证。 例如, my_string.upper()
没有任何列出的参数,因为唯一需要的参数是对象本身my_string
。
一个常见的混淆视点如下:
import math math.sqrt(81)
sqrt
是math
对象的一种方法吗? 不,这是你从math
模块中调用sqrt
函数的方法。 正在使用的格式是module_name.function_name()
,而不是object_name.method_name()
。 通常,区分两种格式(可视化)的唯一方法是查看代码的其余部分,并查看句点 ( math
, my_list
, my_string
) 之前的部分是定义为对象还是模块。
对不起,但 – 在我看来 – RichieHindle完全正确地说这种方法…
这是一个类的成员的function。
这是一个函数的例子,成为类的成员。 从那以后,它就像class级的一个方法一样。 让我们从空类和普通函数开始,带一个参数:
>>> class C: ... pass ... >>> def func(self): ... print 'func called' ... >>> func('whatever') func called
现在,我们添加一个成员到C
类,这是该函数的参考。 之后,我们可以创build类的实例并调用它的方法,就好像它是在类中定义的一样:
>>> C.func = func >>> o = C() >>> o.func() func called
我们也可以使用另一种调用方法:
>>> C.func(o) func called
o.func
甚至performance出与类方法相同的方式:
>>> o.func <bound method C.func of <__main__.C instance at 0x000000000229ACC8>>
我们可以尝试颠倒的方法。 我们来定义一个类,并将其方法作为一个函数来窃取:
>>> class A: ... def func(self): ... print 'aaa' ... >>> a = A() >>> a.func <bound method A.func of <__main__.A instance at 0x000000000229AD08>> >>> a.func() aaa
到目前为止,它看起来是一样的。 现在盗取function:
>>> afunc = A.func >>> afunc(a) aaa
事实是这个方法不接受“无论”的论点:
>>> afunc('whatever') Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: unbound method func() must be called with A instance as first argument (got str instance instead)
恕我直言,这不是反对方法的论据是一个类的成员的函数 。
后来发现 Alex Martelli的回答基本上也是这样说的。 对不起,如果你认为它重复:)
http://docs.python.org/2/tutorial/classes.html#method-objects
通常,一个方法在被绑定之后被调用:
xf()
在MyClass示例中,这将返回string“hello world”。 但是,不需要立即调用一个方法:xf是一个方法对象,可以稍后存储和调用。 例如:
xf = xf while True: print xf()
将继续打印你好世界,直到时间的尽头。
当一个方法被调用时究竟发生了什么? 您可能已经注意到,即使f()的函数定义指定了参数,xf()也没有上面的参数被调用。 发生了什么事? 当一个需要参数的函数没有被调用时,Python会引发exception – 即使参数实际上没有被使用…
其实,你可能已经猜到了答案:关于方法的特殊之处在于对象是作为函数的第一个parameter passing的。 在我们的例子中,调用xf()完全等价于MyClass.f(x)。 一般情况下,调用带有n个参数列表的方法相当于使用通过在第一个参数之前插入方法对象创build的参数列表来调用相应的函数。
如果你仍然不明白方法是如何工作的,那么查看实现可能会澄清一些事情。 当引用不是数据属性的实例属性时,将search其类。 如果名称表示一个有效的类属性是一个函数对象,则方法对象是通过打包实例对象和在一个抽象对象中一起find的函数对象(指针)来创build的:这是方法对象。 当使用参数列表调用方法对象时,会从实例对象和参数列表构造一个新的参数列表,并使用此新参数列表调用函数对象。