python学习:从新手到专家阅读笔记(4)
类
在python中,可以使用class关键字定义类
?
这里,可以看出:
??? 1. 定义类时,类的成员属性可以不用声明,直接拿过来用,比如self.name
??? 2. 定义类成员方法时,必须作为第一个参数显式声明self参数,在方法内部引用时也是显式引用这个self参数,而在调用这个类的方法时,无需显式添加这个参数了,比如greet方法,定义时是greet(self),使用时直接person.greet()就ok了。
??? 3. 方法和属性的引用与module中函数的引用是一样的,都是用"."引用。这一点看着舒服,输入方便,比lua的":"方便。
?
比较起来,lua中变量默认都是global的,以及使用":"分隔这些,用起来就觉得不爽,用lua写大型程序自然也就不容易了。
?
函数和方法
在所有面向对象语言中,函数和方法的区别,就是方法的第一个参数是对象本身(this或self)。
在lua中,obj.method只是obj["method"]的一个syntax sugar,所以对于一个方法m1,只要obj1.method = m1, obj2.method=m1,则obj1.method()和obj2.method()返回值都是一样的。就是说,方法的执行和方法从哪个对象中的引用调用过来是没有关系的:
?
而在javascript中,情况有所不同,使用哪个对象去调用方法,结果会不一样,这与面向对象的理念更加接近,但与函数作为“第一阶级”元素的函数式编程理念却有些背离:
?
python中的方法,是更加面向对象一些呢,还是更加函数式一些呢?测试一下:
?
?
可以看出,python的方法,独立性更强一些,更加函数式一些,只要定义时确定了是什么,不管从哪里调用,就是什么,不会随着调用位置的改变而改变,与调用对象的关系不大。
?
也可以看出,对象的方法,在对象被定义时就已经确定了,可以知道其self是谁了,这个方法是一个独一无二的实例,不会存在着多个对象共用一个方法的问题。这样会造成方法代码存储的浪费,但灵活性更强。当然,在实际实现中,可以通过一个中间层“function”对象,来解耦真正的代码和它的绑定数据,从而增加灵活性的同时,不会造成方法代码存储的浪费。lua中的function就是这么做的。
?
在python中,方法也叫“绑定方法”,就是说,方法在定义时已经绑定了某个对象,后续对它的调用,无论是使用方法调用方式obj.method(),还是使用函数调用方式func(),效果都是一样的。
?
方法访问权限
在python中,没有private、protected、public等成员修饰属性,要让一个方法外部不可见,只能内部可见,方法名字前面可以加上两个下划线,比如:__myprivatemethod。实际上,凡是带有双下划线的方法,python会添加前缀_Classname,所以类Person的私有方法__privatemethod,实际上仍然可以这样访问_Person__privatemethod,尽管这种访问方式不标准。
?
带单下划线的话,from module import *时,不会把这些方法导入。实际上,在使用*导入一个module中的名字时,所有以下划线开头的(单下划线或多下划线)名字都不会导入,不论方法名还是变量名还是类名
?
类作用域
在类定义内部,实际上是开始了一个新的作用域(scope),在这个作用域中可以执行任何语句,包括print,赋值语句等等,def实际上是定义函数变量。
另外,dict虽然可以用dict['key']来访问其内部以字符串为key的项,但不能使用dict.key的方式来访问。这一点不如lua方便。
在类作用域中定义的成员都是类级别的成员,在类的所有成员对象中共享,而在self范围内定义的就是self的成员,只有具体对象使用。
?
异常
异常与其他语言的异常类似,语法如下:
try:
except xxx:
else:
finally:
?
构造函数
python中,所有以__开头并以__结尾的名字都有特殊含义,比如类中__init__是构造函数,而__del__是析构函数。其中__init__用得最多。
?
lua中,访问一个不存在的变量返回none,而python中,访问一个不存在的变量会产生异常。相对而言,python的这种做法更好,更容易发现错误。
?
在创建了一个新的对象后,对象中的方法都是绑定了的。如果使用类名直接引用类中的方法,如Person.greet,此时这个方法是没有绑定的,需要显式指定self对象,比如person = Person(),person.greet(), Person.greet(person)
?