解析Python类中的方法定义


最近在学习类过程中,绑定方法这个概念没有理解透彻,所以在网上找了很多相关博客、文章研究到底是怎么一回事。因为有的文章所陈述与我在python3.5版本实际实验中有些出入,所以经过实践后总结出以下结论。

对于Python类中,方法的定义方式,我们可以归纳有4种类型:

1、不带self、cls参数且不加装饰器(staticmethod、classmethod)
2、正常的方法定义,带self参数
3、类方法:加装饰器(classmethod)
4、静态方法:加装饰器(staticmethod)

下面对每一种定义的方式进行分析:

1、不带self、cls参数且不加装饰器(staticmethod、classmethod)

定义代码如下:

class Student(object):
    def func(name):
        print('my name is {}'.format(name))

我们通过用类和实例分别调用该方法:

print(Student.func)
Student.func('Tom')
print(Student().func)
Student().func('Tom')

类调用output:

<function Student.func at 0x0000000000D7D268>
my name is Tom
[Finished in 0.1s]

实例调用output:

<bound method Student.func of <__main__.Student object at 0x0000000000D444A8>>
Traceback (most recent call last):
  File "I:\MyProject\awesome-python3-webapp\www\for_test.py", line 11, in <module>
    Student().func('Tom')
TypeError: func() takes 1 positional argument but 2 were given
[Finished in 0.2s with exit code 1]

从上面的输出我们可以看出,此种定义方法,如果用类来调用该方法,那么这个方法就只是一个函数,不会像绑定方法一样会自动传值。传参只需按照正常的函数传参即可;如果用实例来调用该方法,那么这个方法就是绑定(bound)的方法,既然是绑定方法,那么就会自动把Student()自身作为第一个参数传到方法中去,所以Student().func('Tom')会传实例Student()以及'Tom'两个参数到此方法,但是由于此方法定义时只定义了一个参数,所以就会有上述的报错。

2、正常的方法定义,带self参数

定义代码如下:

class Student(object):
    def func(self, name):
        print('my name is {}'.format(name))

类调用该方法:

print(Student.func)
Student.func('Tom')

output:

<function Student.func at 0x000000000070D268>
Traceback (most recent call last):
  File "I:\MyProject\awesome-python3-webapp\www\for_test.py", line 8, in <module>
    Student.func('Tom')
TypeError: func() missing 1 required positional argument: 'name'
[Finished in 0.2s with exit code 1]

用类调用该方法,跟第一种情况一样,依然是一个函数。因为此函数有两参数(selfname),由于实参'Tom'是传到了形参self,所以输出中提示调用func方法少了name参数。正确的调用方式为Student.func(Student(), 'Tom')

用实例调用该方法:

print(Student().func)
Student().func('Tom')

output:

<bound method Student.func of <__main__.Student object at 0x00000000006E44A8>>
my name is Tom
[Finished in 0.2s]

可以看出实例调用该方法,得到是绑定的方法,Student()Tom参数,分别传给形参selfname

其实第一种和第二种定义的方法是一样的,而他们的区别只是有没有self这个参数。只要是实例调用这个方法,都是绑定的方法。都会自动将实例自身作为第一个参数传递进去。self这个参数,是大家约定俗成的一种参数命名,命名成a或者b都是可以的,只不过这样命名会降低代码的可读性。下面要说的类方法中的cls参数也是这个道理。

3、类方法:加装饰器(classmethod)

定义代码如下:

class Student(object):
    @classmethod
    def func(cls, name):
        print('my name is {} from {}'.format(name, cls.__name__))

用类和实例分别调用该方法:

print(Student.func)
Student.func('Tom')
print(Student().func)
Student().func('Tom')

output:

<bound method Student.func of <class '__main__.Student'>>
my name is Tom from Student
<bound method Student.func of <class '__main__.Student'>>
my name is Tom from Student
[Finished in 0.2s]

可以看出,此种定义方式,用类或者实例调用,都是绑定的方法。用类调用,会将类自身作为第一个参数传递到方法中。用实例调用,会将实例所属的类作为第一个参数传递到方法中。

4、静态方法:加装饰器(staticmethod)

定义代码如下:

class Student(object):
    @staticmethod
    def func(name):
        print('my name is {}'.format(name))

用类和实例分别调用该方法:

print(Student.func)
Student.func('Tom')
print(Student().func)
Student().func('Tom')

output:

<function Student.func at 0x0000000000D6D268>
my name is Tom
<function Student.func at 0x0000000000D6D268>
my name is Tom
[Finished in 0.2s]

从上面的输出代码中,可以看出,使用装饰器staticmethod装饰的函数,只是一个普通函数,没有绑定方法的自动传值功能,传参只需按照正常的函数传参即可。

综合上面分析,我们可以总结如下:
1、凡是类中的方法、函数,如果没有加装饰器,当通过类来调用的时候,得到的是普通的函数,当通过实例来调用的时候,得到的是绑定方法;
2、加装饰器classmethod的方法,无论是通过类或者实例来调用,得到的都是绑定方法,python会自动将类本身或者实例所属的类作为第一个参数传递进去;
3、加装饰器staticmethod的方法,通过类或者实例调用,得到的都是普通函数。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 195,898评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,401评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,058评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,539评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,382评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,319评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,706评论 3 386
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,370评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,664评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,715评论 2 312
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,476评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,326评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,730评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,003评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,275评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,683评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,877评论 2 335

推荐阅读更多精彩内容

  • @(python)[笔记] 目录 前言 在python中,一切皆对象面向对象的程序设计的核心就是对象;面向对象的程...
    CaiGuangyin阅读 583评论 0 5
  • 要点: 函数式编程:注意不是“函数编程”,多了一个“式” 模块:如何使用模块 面向对象编程:面向对象的概念、属性、...
    victorsungo阅读 1,447评论 0 6
  • 我们学校才刚放暑假,而且才放35天,今年夏天好像尤其热,好多同学叫苦连天的离校了!偌大的校园安静了下来了,可是我们...
    冬阳一缕阅读 376评论 0 8
  • 环境: CentOS 7.2 背景 帮客户托管在机房的服务器系统做安全加固,加固好后会有第三方机构进行安全扫描。 ...
    飞翼_U阅读 3,536评论 0 0