在Python中,什么是“类方法”和“实例方法”?


37

聊天中已经讨论了一个问题(该问题本身与该问题无关),这表明我可能不知道Python。

在我看来,尽管术语在不同语言之间是不同的,但我们通常可以将功能归类为:

  • [免费]功能
  • 静态方法/静态成员函数
  • 非静态方法/非静态成员函数

显然,在Python中,还有另一种不适用于上述类别的函数,一种是方法,但“不知道其类”。

在Python中,什么是“类方法”和“实例方法”?


1
如果有人对聊天讨论感兴趣,请从这里开始:chat.stackexchange.com/transcript/message/26479002#26479002
yannis 2015年

1
:IMO一个更好的答案是不同的stackexchange网站提供stackoverflow.com/questions/136097/...
特雷弗·博伊德·史密斯

仅供参考,该链接位于接受的底部...但是我认为许多人会错过该链接或永远不会访问它,因此我在这里复制了它。
Trevor Boyd Smith

Answers:


49

简短的答案

  • 实例方法知道其实例(并由此知道其类)
  • 类方法知道其类
  • 静态方法不知道其类或实例

长答案

类方法

类方法是一个属于类作为一个整体。它不需要实例。相反,该类将自动作为第一个参数发送。@classmethod装饰器声明了一个类方法。

例如:

class Foo(object):
    @classmethod
    def hello(cls):
        print("hello from %s" % cls.__name__)
Foo.hello()
-> "Hello from Foo"
Foo().hello()
-> "Hello from Foo"

实例方法

另一方面,实例方法 需要一个实例才能调用它,并且不需要装饰器。到目前为止,这是最常见的方法类型。

class Foo(object):
    def hello(self):
        print("hello from %s" % self.__class__.__name__)
Foo.hello()
-> TypeError: hello() missing 1 required positional argument: 'self'

(注意:以上是针对python3的;对于python2,您会得到略有不同的错误)

静态方法

静态方法是类似于类的方法,但不会得到类对象作为自动参数。它是通过使用@staticmethod装饰器创建的。

class Foo(object):
    @staticmethod
    def hello(cls):
        print("hello from %s" % cls.__name__)

Foo.hello()
-> TypeError: hello() missing 1 required positional argument: 'cls'

文档链接

以下是相关python3文档的链接:

数据模型文件有这样说的类方法和静态方法的区别:

静态方法对象静态方法对象提供了一种克服功能对象向上述方法对象的转换的方法。静态方法对象是任何其他对象(通常是用户定义的方法对象)的包装。从类或类实例中检索静态方法对象时,实际返回的对象是包装的对象,无需进行任何进一步的转换。静态方法对象本身不是可调用的,尽管它们通常包装的对象是可调用的。静态方法对象由内置的staticmethod()构造函数创建。

类方法对象 类方法对象与静态方法对象一样,是另一个对象的包装,它更改了从类和类实例检索该对象的方式。上面在“用户定义的方法”下描述了此类检索时类方法对象的行为。类方法对象是由内置的classmethod()构造函数创建的。

相关问题


4
@LightnessRacesinOrbit:我认为在python中不经常使用静态方法。使用我的系统作为随机样本,当我搜索所有已安装的软件包时,所有方法中只有大约1%是静态方法(坦​​率地说,这超出了我的预期)。
布赖恩·奥克利

1
“静态方法”通常是代码的味道,例如Gogole Python样式指南不建议这样做。
9000

3
我认为如果提请注意子类,答案会更好,这是类方法获得某些有用性的地方。
温斯顿·埃韦特2015年

1
@ user2357112:我只计算了的所有实例"^ def(",然后计算了的所有实例@staticmethod。非常不科学,但可能在球场附近。
布莱恩·奥克利

2
@Kashyap:TL; DR适用于第一段。我认为它在顶部比底部更有效。
布莱恩·奥克利

8

在Python中,什么是“类方法”和“实例方法”?

  • “实例方法”使用实例中包含的信息来计算要返回的值(或要执行的副作用)。这些很常见。

  • “类方法”使用有关类的信息(而不是该类的实例)来影响其功能(它们通常用于创建新实例作为替代构造函数,因此并不常见)。

  • “静态方法”不使用有关类或实例的任何信息来计算其功能。为了方便起见,通常只在课堂上讲。(因此,它们也不是很常见。)

X的函数

记住数学课,“ y是x的函数f(x)吗?” 让我们在代码中应用它:

y = function(x)

以上所隐含的是,由于x可能会更改,所以y更改时可能会x更改。这就是说“ y是”的功能时的x意思。

将什么y是时候z12'FooBarBaz'

y不是的函数z,因此z可以是任何东西,并且假设我们function是纯函数,则不影响该函数的结果。(如果它z作为全局变量访问,则它不是纯函数-这就是函数纯净的含义。)

阅读以下说明时,请牢记以上几点:

实例方法

一个实例方法是函数是一个函数一个实例。该函数隐式地接受该实例作为其参数,并且该实例由该函数使用以确定该函数的输出。

实例方法的内置示例为str.lower:

>>> 'ABC'.lower()
'abc'

str.lower 在字符串的实例上调用,并使用实例中包含的信息确定要返回的新字符串。

类方法:

记住,在Python中,一切都是对象。这意味着该类是一个对象,并且可以作为参数传递给函数。

一类方法是一个函数,它是一个函数。它接受类作为其参数。

一个内置的示例是dict.fromkeys

>>> dict.fromkeys('ABC')
{'C': None, 'B': None, 'A': None}

该函数隐式地知道其自己的类,该函数使用该类来影响该函数的输出,并从可迭代对象中创建该类的新类。使用相同的方法时,OrderedDict会对此进行演示:

>>> from collections import OrderedDict
>>> OrderedDict.fromkeys('ABC')
OrderedDict([('A', None), ('B', None), ('C', None)])

class方法使用有关类的信息(而不是该类的实例)来影响要返回的类的类型。

静态方法

您提到了“不知道其类”的方法-这是Python中的静态方法。它只是为了方便而附加到类对象上。它可以选择是另一个模块中的单独函数,但其​​调用签名将相同。

静态方法既不是类也不是对象的函数。

静态方法的内置示例是Python 3中的str.maketrans。

>>> str.maketrans('abc', 'bca')
{97: 98, 98: 99, 99: 97}

给定几个参数,它将创建一个字典,而不是其类的函数。

这很方便,因为str它始终在全局名称空间中可用,因此您可以轻松地将其与translation函数一起使用:

>>> 'abracadabra'.translate(str.maketrans('abc', 'bca'))
'bcrbabdbcrb'

在Python 2中,您必须从string模块访问它:

>>> 'abracadabra'.translate(str.maketrans('abc', 'bca'))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: type object 'str' has no attribute 'maketrans'
>>> import string
>>> 'abracadabra'.translate(string.maketrans('abc', 'bca'))
'bcrbabdbcrb'

class AClass(object):
    """In Python, a class may have several types of methods: 
    instance methods, class methods, and static methods
    """

    def an_instance_method(self, x, y, z=None):
        """this is a function of the instance of the object
        self is the object's instance
        """
        return self.a_class_method(x, y)

    @classmethod
    def a_class_method(cls, x, y, z=None):
        """this is a function of the class of the object
        cls is the object's class
        """
        return cls.a_static_method(x, y, z=z)

    @staticmethod
    def a_static_method(x, y, z=None):
        """this is neither a function of the instance or class to 
        which it is attached
        """
        return x, y, z

让我们实例化:

>>> instance = AClass()

现在,实例可以调用所有方法:

>>> instance.an_instance_method('x', 'y')
('x', 'y', None)
>>> instance.a_static_method('x', 'y')
('x', 'y', None)
>>> instance.a_class_method('x', 'y')
('x', 'y', None)

但是该类通常不打算调用该实例方法,尽管希望它可以调用其他方法:

>>> AClass.a_class_method('x', 'y')
('x', 'y', None)
>>> AClass.a_static_method('x', 'y')
('x', 'y', None)
>>> AClass.an_instance_method('x', 'y')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: an_instance_method() missing 1 required positional argument: 'y'

您必须显式传递实例才能调用实例方法:

>>> AClass.an_instance_method(instance, 'x', 'y')
('x', 'y', None)

“这是Python中的静态方法。为方便起见,它只是附加到类对象上。可以选择在另一个模块中作为单独的函数,但其​​调用签名相同。” 似乎比方便更令人困惑。如果函数的主体没有该类的概念,为什么还要将其附加到该类。
与莫妮卡(Monica)进行的轻度比赛

我已经详细说明了@LightnessRacesinOrbit
亚伦·霍尔

就我个人而言,我一直看待它的方式是,实例方法是对特定实例的操作,类方法是一种构造函数(为方便起见,没有什么类似MyClass(1,2,3),而是类似MyClass.get_special(1,2,3)),而静态方法只是一种是正常的功能,无论如何都可以单独使用。
Zizouz212 2015年

是的,类方法通常用于替代构造函数(请参见上面的dict.fromkeys示例,另请参见pandas.DataFrame源代码),但这不是定义特征。有时,我只需要从一种方法访问存储在类级别的数据,而无需访问实例。如果您要调用type(self)(或更糟的是self .__ class__),而不是在实例方法中不直接使用self,则表明您应该将其视为类方法是一个好兆头。由于类方法不需要实例,因此使它们更易于单元测试。
亚伦·霍尔

4
  • “实例方法”是将实例对象作为其第一个参数传递的方法,按照惯例,该参数称为self。这是默认值。

  • “静态方法”是没有初始self参数的方法。这是通过@staticmethod装饰器实现

  • “类方法”是一种方法,其中初始参数不是实例对象,而是类对象(有关 “类对象”的含义,请参见Python文档的此部分),按惯例称为cls。这是通过@classmethod装饰器实现

C / C ++ / etc中术语“静态方法”的典型用法适用于Python“静态”和Python“类”方法,因为这两种类型的方法都缺少对实例的引用。在C / C ++ / etc中,方法通常可以隐式访问该类的所有非实例成员/方法,这可能就是为什么这种区别仅存在于Python / Ruby / etc等语言中的原因。


C / C ++中的静态方法是否具有对类对象的引用?还是仅仅是班上的“成员”?他们可以创建班级的新成员吗?:)
亚伦·霍尔

3
@AaronHall在C / C ++中,没有类对象之类的东西,您不需要引用它即可调用静态方法。您只要编写Class::staticMethod()就可以了(只要不staticMethod()因私有或其他原因而被禁止调用它)。
Ixrec 2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.