Python Object Oriented Programming
Sources:
- 廖雪峰的教程
Class and Instance
1 | class Student(object): # 表示该类是从object类继承下来的 |
Create a instance: className()
1 | >>> bart = Student() |
可以看到,变量bart
指向的就是一个Student
的实例,后面的0x10a67a590
是内存地址,每个object的地址都不一样,而Student
本身则是一个类。
Members
可以自由地给一个实例变量绑定属性,比如,给实例bart
绑定一个name
属性:
1 | >>> bart.name = 'Bart Simpson' |
由于类可以起到模板的作用,因此,可以在创建实例的时候,把一些我们认为必须绑定的属性强制填写进去。通过定义一个特殊的__init__
方法,在创建实例的时候,就把name
,score
等属性绑上去:
1 | class Student(object): |
注意:特殊方法“init”前后分别有两个下划线!!!
注意到__init__
方法的第一个参数永远是self
,表示创建的实例本身,因此,在__init__
方法内部,就可以把各种属性绑定到self
,因为self
就指向创建的实例本身。
有了__init__
方法,在创建实例的时候,就不能传入空的参数了,必须传入与__init__
方法匹配的参数,但self
不需要传,Python解释器自己会把实例变量传进去:
1 | >>> bart = Student('Bart Simpson', 59) |
和普通的函数相比,在类中定义的函数只有一点不同,就是第一个参数永远是实例变量self
,并且,调用时,不用传递该参数。除此之外,类的方法和普通函数没有什么区别,所以,你仍然可以用默认参数、可变参数、关键字参数和命名关键字参数。访问限制
Access Contril
Most programming languages has three forms of access modifiers, which are Public, Protected and Private in a class.
- 在Python中,实例的变量名如果以
__
开头,就变成了一个私有变量(private),只有内部可以访问,外部不能访问. - 在Python中,变量名类似
__xxx__
的,也就是以双下划线开头,并且以双下划线结尾的,是特殊变量,特殊变量是可以直接访问的,不是private变量,所以,不能用__name__
、__score__
这样的变量名。
双下划线开头的实例变量是不是一定不能从外部访问呢?其实也不是。不能直接访问__name
是因为Python解释器对外把__name
变量改成了_Student__name
,所以,仍然可以通过_Student__name
来访问__name
变量:
1 | >>> bart._Student__name |
但是强烈建议你不要这么干,因为不同版本的Python解释器可能会把__name
改成不同的变量名。
Object
Equal
- The
==
operator compares only the value of the objects being compared. - The
is
operator compares if the objects are pointing to the same memory location or not.
type()
type()
: 判断对象的精确类型.
基本类型:
1
2
3
4
5
6>>> type(123)
<class 'int'>
>>> type('str')
<class 'str'>
>>> type(None)
<type(None) 'NoneType'>函数或者类:
1
2
3
4>>> type(abs)
<class 'builtin_function_or_method'>
>>> type(a)
<class '__main__.Animal'>
type()
函数返回的是对应的Class类型。如果我们要在if
语句中判断,就需要比较两个变量的type类型是否相同:
1 | >>> type(123)==type(456) |
判断基本数据类型可以直接写int
,str
等,但如果要判断一个对象是否是函数怎么办?可以使用types
模块中定义的常量:
1 | >>> import types |
isinstance()
isinstance()
: 判断对象是否是某一类型或者该类型的子类。先创建3种类型的对象:
能用type()
判断的基本类型也可以用isinstance()
判断:
1 | >>> isinstance('a', str) |
并且还可以判断一个变量是否是某些类型中的一种,比如下面的代码就可以判断是否是list或者tuple:
1 | >>> isinstance([1, 2, 3], (list, tuple)) |
总是优先使用isinstance()判断类型,可以将指定类型及其子类“一网打尽”。
dir()
如果要获得一个对象的所有属性和方法,可以使用dir()
函数,它返回一个包含字符串的list,比如,获得一个str对象的所有属性和方法:
1 | >>> dir('ABC') |
类似__xxx__
的属性和方法在Python中都是有特殊用途的,比如__len__
方法返回长度。在Python中,如果你调用len()
函数试图获取一个对象的长度,实际上,在len()
函数内部,它自动去调用该对象的__len__()
方法,所以,下面的代码是等价的:
1 | >>> len('ABC') |
我们自己写的类,如果也想用len(myObj)
的话,就自己写一个__len__()
方法:
1 | >>> class MyDog(object): |
剩下的都是普通属性或方法,比如lower()
返回小写的字符串:
1 | >>> 'ABC'.lower() |
仅仅把属性和方法列出来是不够的,配合getattr()
、setattr()
以及hasattr()
,我们可以直接操作一个对象的状态:
1 | >>> class MyObject(object): |
紧接着,可以测试该对象的属性:
1 | >>> hasattr(obj, 'x') # 有属性'x'吗? |
如果试图获取不存在的属性,会抛出AttributeError的错误:
1 | >>> getattr(obj, 'z') # 获取属性'z' |
可以传入一个default参数,如果属性不存在,就返回默认值:
1 | >>> getattr(obj, 'z', 404) # 获取属性'z',如果不存在,返回默认值404 |
也可以获得对象的方法:
1 | >>> hasattr(obj, 'power') # 有属性'power'吗? |
实例属性和类属性
由于Python是动态语言,根据类创建的实例可以任意绑定属性。
给实例绑定属性的方法是通过实例变量,或者通过self
变量:
1 | class Student(object): |
但是,如果Student
类本身需要绑定一个属性呢?可以直接在class中定义属性,这种属性是类属性,归Student
类所有:
1 | class Student(object): |
当我们定义了一个类属性后,这个属性虽然归类所有,但类的所有实例都可以访问到。来测试一下:
1 | >>> class Student(object): |
从上面的例子可以看出,在编写程序的时候,千万不要对实例属性和类属性使用相同的名字,因为相同名称的实例属性将屏蔽掉类属性,但是当你删除实例属性后,再使用相同的名称,访问到的将是类属性。