python 参数列表中的self 显式不等于冗余


Posted in Python onDecember 01, 2008

self在区分全局变量/函数和对象中的成员变量/函数十分有用。例如,它提供了一种作用域机制,我个人认为比Ruby的@和@@清晰多了,这可能是习惯使然吧,但它确实和C++、Java中的this很相似。
然而,self总是有令我困扰的地方,我以前在这里说过—我曾幻想能在Python3中这些能得以改进,然后通常会引发一轮热议并最终以人们所说的“显胜于隐”告终。
我在巴西的时候曾和Luciano Ramalho(巴西Python组织的主席)有过一次交谈。他让我明白并非无处不在的self让我困扰不已,而是参数列表中的self,我想也称为非pythonic(un-pythonic)。
它是如何使用的
下面是一些简单的Python代码,说明了如何使用类。

def f(): pass 
a = 1 
class C1(object): 
a = 2 
def m1(self): 
print a # Prints '1' 
print self.a # Prints '2' 
f() # The global version 
self.m2() # Must scope other members 
def m2(self): pass 
obj = C1() 
obj.m1()

首先看f()和a,它们都可在全局作用域中调用。类C1被定义成继承自object,这是定义一个新类的标准过程(我想在Python3中这些会变得更加不明显)。
注意,m1()和m2()的第一个参数都是self。在Python中,self不是关键字。但按照惯例“self”代表当前对象的地址,也就是对象的地址通常是第一个参数。
在类范围上定义a是创建对象作用域的方式之一。你也可以在a的method里赋值给self.a,并且第一次运行该语句时就分配了这个域的内存空间。但有必要区分两种版本的a。若在method内部使用a,那么这个a就是全局版本的,而self.a体现的是对象域(你也可以在类内部对全局变量进行赋值,这里我暂不考虑这种情况)。
同样地,一个对f()的非限定调用(unqualified call)造就了全局函数,通过对其限定self.m2()调用的是成员函数(同时将当前对象地址作为传递给m2()的self变量)。
现在来看一个含有带参数的method的类:
class C2(object): 
def m2(self, a, b): pass

为了调用该method,我们创建了一个对象实例,然后使用点表达式调用对象obj上的m2():
obj = C2() 
obj.m2(1,2)

在调用过程中,obj的地址作为self变量在m2()中隐含传递,这里遇到了一个严重的矛盾:为何当定义method时隐式好于显式,而调用method时隐式也毫无问题?
当然我想这可能是method调用语法所要求的,但这就意味着method的定义和调用有很大不同,这里既没有“显式”也不pythonic。在调用参数个数错误的method时就能看出来:
obj.m2(1)
结果错误提示为:
Traceback (most recent call last):
File "classes.py", line 9, in <module>
obj.m2(1)
TypeError: m2() takes exactly 3 arguments (2 given)
由于method调用期间self的隐式参数传递,上述错误信息实际是说应该这样调用method:
C2.m2(obj,1,2)
即使上面这行语句运行成功,它当然也不是实际的调用方式。你应该使用常规的method调用语法,即传递两个参数:
obj.m2(1,2)
错误信息“m2() takes exactly 3 arguments (2 given)”不仅让初学者十分糊涂,我每次看到它后也常常懵住。我想这既表明了它是非Pythonic、也直指method定义和调用的矛盾。
绝望的建议
尽管漫长历史中尽是绝望,我又有哪些建议呢?
在Python3.1中增加self为关键字(有一点更加向后不兼容)(或直接使用this来使C++和Java程序员时更容易过渡)。而所有与self有关的已有规则都不变。
唯一的改变是:你不必将self放入method参数列表中。这是唯一隐式的地方,其它都是显式的—除了依旧不变的method调用。
它实现了method定义和调用的一致性。你可以定义一个与调用时具有相同参数个数的method。当调用method所传递参数个数出错时,错误信息会通知method应含有的实际参数个数,而不是多出一个。
显式 vs.冗余
在我再一次听到“显胜于隐”之前,让某件事变得清晰和变得冗余还是有区别的。我们已有这样一种语言:它让你历经了无数考验,原因就是起初看起来似乎很好但之后问题却越来越多。它叫做Java。
如果想让每一件东西都变为显式,我们可以使用C或汇编以及其它能够精确说明和展现机器内部运行细节的语言。
强制程序员将self放入method参数列表与显式根本不沾边,它只是强制造成冗余的做法,也不会增加编程的表达方式(已经知道是一个method了,何必还要在参数列表中加入self来提醒我们呢)。我认为,它是死板的,也是非pythonic。
Python 相关文章推荐
python抓取网页时字符集转换问题处理方案分享
Jun 19 Python
Python实现控制台输入密码的方法
May 29 Python
python和shell获取文本内容的方法
Jun 05 Python
10分钟教你用Python实现微信自动回复功能
Nov 28 Python
Scrapy框架爬取西刺代理网免费高匿代理的实现代码
Feb 22 Python
Python实现的文轩网爬虫完整示例
May 16 Python
python 多进程并行编程 ProcessPoolExecutor的实现
Oct 11 Python
python进程的状态、创建及使用方法详解
Dec 06 Python
python实现吃苹果小游戏
Mar 21 Python
Python动态强类型解释型语言原理解析
Mar 25 Python
使用python无账号无限制获取企查查信息的实例代码
Apr 17 Python
python 如何区分return和yield
Sep 22 Python
Python GAE、Django导出Excel的方法
Nov 24 #Python
Python类的基础入门知识
Nov 24 #Python
Python 连连看连接算法
Nov 22 #Python
python sqlobject(mysql)中文乱码解决方法
Nov 14 #Python
Python转码问题的解决方法
Oct 07 #Python
Python函数学习笔记
Oct 07 #Python
Python日期操作学习笔记
Oct 07 #Python
You might like
PHP Zip解压 文件在线解压缩的函数代码
2010/05/26 PHP
Zend Framework教程之响应对象的封装Zend_Controller_Response实例详解
2016/03/07 PHP
PHP封装的多文件上传类实例与用法详解
2017/02/07 PHP
PHP+jQuery+Ajax实现多图片上传效果
2015/03/14 Javascript
jquery实现select下拉框美化特效代码分享
2015/08/18 Javascript
JavaScript基本数据类型及值类型和引用类型
2015/08/25 Javascript
jquery实现一个简单的表单验证实例
2016/03/30 Javascript
Vue.js基础知识汇总
2016/04/27 Javascript
jQuery选择器总结之常用元素查找方法
2016/08/04 Javascript
AngularJS基于ngInfiniteScroll实现下拉滚动加载的方法
2016/12/14 Javascript
详解vue-validator(vue验证器)
2017/01/16 Javascript
微信小程序 生命周期和页面的生命周期详细介绍
2017/01/19 Javascript
详解Vue学习笔记入门篇之组件的内容分发(slot)
2017/07/17 Javascript
把vue-router和express项目部署到服务器的方法
2018/02/21 Javascript
Angular HMR(热模块替换)功能实现方法
2018/04/04 Javascript
Vue页面跳转动画效果的实现方法
2018/09/23 Javascript
对angularJs中ng-style动态改变样式的实例讲解
2018/09/30 Javascript
seajs和requirejs模块化简单案例分析
2019/08/26 Javascript
[04:11]2014DOTA2国际邀请赛 CIS遗憾出局梦想不灭
2014/07/09 DOTA
[42:20]Winstrike vs VGJ.S 2018国际邀请赛淘汰赛BO3 第二场 8.23
2018/08/24 DOTA
python 多进程通信模块的简单实现
2014/02/20 Python
零基础写python爬虫之爬虫框架Scrapy安装配置
2014/11/06 Python
python中子类继承父类的__init__方法实例
2016/12/15 Python
Python动态声明变量赋值代码实例
2019/12/30 Python
python 非线性规划方式(scipy.optimize.minimize)
2020/02/11 Python
HTML5 语义化结构化规范化
2008/10/17 HTML / CSS
台湾团购、宅配和优惠券:17Life
2017/08/14 全球购物
捷克建筑材料网上商店:DEK.cz
2021/03/06 全球购物
常见的软件开发流程有哪些
2015/11/14 面试题
群众路线对照检查剖析材料
2014/10/09 职场文书
2014年乡镇妇联工作总结
2014/12/02 职场文书
2016小学新学期寄语
2015/12/04 职场文书
如何撰写促销方案?
2019/07/05 职场文书
python 通过使用Yolact训练数据集
2021/04/06 Python
Python+Appium实现自动抢微信红包
2021/05/21 Python
python使用opencv对图像添加噪声(高斯/椒盐/泊松/斑点)
2022/04/06 Python