|
1 | 1 | # 类和实例 |
2 | 2 |
|
| 3 | +类是一个抽象的概念,我们可以把它理解为具有相同**属性**和**方法**的一组对象的集合,而实例则是一个具体的对象。我们还是先来看看在 Python 中怎么定义一个类。 |
| 4 | + |
| 5 | +这里以动物(Animal)类为例,Python 提供关键字 `class` 来声明一个类: |
| 6 | + |
| 7 | +```python |
| 8 | +class Animal(object): |
| 9 | + pass |
| 10 | +``` |
| 11 | + |
| 12 | +其中,`Animal` 是类名,通常类名的首字母采用大写(如果有多个单词,则每个单词的首字母大写),后面紧跟着 `(object)`,表示该类是从哪个类继承而来的,所有类最终都会继承自 `object` 类。 |
| 13 | + |
| 14 | +类定义好了,接下来我们就可以**创建实例**了: |
| 15 | + |
| 16 | +```python |
| 17 | +>>> animal = Animal() # 创建一个实例对象 |
| 18 | +>>> animal |
| 19 | +<__main__.Animal at 0x1030a44d0> |
| 20 | +``` |
| 21 | + |
| 22 | +我们在创建实例的时候,还可以传入一些参数,以初始化对象的属性,为此,我们需要添加一个 `__init__` 方法: |
| 23 | + |
| 24 | +```python |
| 25 | +class Animal(object): |
| 26 | + def __init__(self, name): |
| 27 | + self.name = name |
| 28 | +``` |
| 29 | + |
| 30 | +然后,在创建实例的时候,传入参数: |
| 31 | + |
| 32 | +```python |
| 33 | +>>> animal = Aniaml('dog1') # 传入参数 'dog1' |
| 34 | +>>> animal.name # 访问对象的 name 属性 |
| 35 | +'dog1' |
| 36 | +``` |
| 37 | + |
| 38 | +我们可以把 `__init__` 理解为对象的初始化方法,它的第一个参数永远是 `self`,指向创建的实例本身。定义了 `__init__` 方法,我们在创建实例的时候,就需要传入与 `__init__` 方法匹配的参数。 |
| 39 | + |
| 40 | +接下来,我们再来添加一个方法: |
| 41 | + |
| 42 | +```python |
| 43 | +class Animal(object): |
| 44 | + def __init__(self, name): |
| 45 | + self.name = name |
| 46 | + def greet(self): |
| 47 | + print 'Hello, I am %s.' % self.name |
| 48 | +``` |
| 49 | + |
| 50 | +我们添加了方法 `greet`,看看下面的使用: |
| 51 | + |
| 52 | +```python |
| 53 | +>>> dog1 = Animal('dog1') |
| 54 | +>>> dog1.name |
| 55 | +'dog1' |
| 56 | +>>> dog1.greet() |
| 57 | +Hello, I am dog1. |
| 58 | +``` |
| 59 | + |
| 60 | +现在,让我们做一下总结。我们在 Animal 类定义了两个方法:`__init__` 和 `greet`。`__init__` 是 Python 中的**特殊方法(special method)**,它用于对对象进行初始化,类似于 C++ 中的构造函数;`greet` 是我们自定义的方法。 |
| 61 | + |
| 62 | +注意到,我们在上面定义的两个**方法**有一个共同点,就是它们的第一个参数都是 `self`,指向实例本身,也就是说它们是和实例绑定的函数,这也是我们称它们为方法而不是函数的原因。 |
| 63 | + |
| 64 | +# 访问限制 |
| 65 | + |
| 66 | +在某些情况下,我们希望限制用户访问对象的属性或方法,也就是希望它是私有的,对外隐蔽。比如,对于上面的例子,我们希望 `name` 属性在外部不能被访问,我们可以**在属性或方法的名称前面加上两个下划线**,即 `__`,对上面的例子做一点改动: |
| 67 | + |
| 68 | +```python |
| 69 | +class Animal(object): |
| 70 | + def __init__(self, name): |
| 71 | + self.__name = name |
| 72 | + def greet(self): |
| 73 | + print 'Hello, I am %s.' % self.__name |
| 74 | +``` |
| 75 | + |
| 76 | +```python |
| 77 | +>>> dog1 = Animal('dog1') |
| 78 | +>>> dog1.__name # 访问不了 |
| 79 | +--------------------------------------------------------------------------- |
| 80 | +AttributeError Traceback (most recent call last) |
| 81 | +<ipython-input-206-7f6730db631e> in <module>() |
| 82 | +----> 1 dog1.__name |
| 83 | + |
| 84 | +AttributeError: 'Animal' object has no attribute '__name' |
| 85 | +>>> dog1.greet() # 可以访问 |
| 86 | +Hello, I am dog1. |
| 87 | +``` |
| 88 | + |
| 89 | +可以看到,加了 `__` 的 `__name` 是不能访问的,而原来的 `greet` 仍可以正常访问。 |
| 90 | + |
| 91 | +需要注意的是,在 Python 中,以双下划线开头,并且以双下划线结尾(即 `__xxx__`)的变量是特殊变量,特殊变量是可以直接访问的。所以,不要用 `__name__` 这样的变量名。 |
| 92 | + |
| 93 | +另外,如果变量名前面只有一个下划线 `_`,表示**不要随意访问这个变量**,虽然它可以直接被访问。 |
| 94 | + |
| 95 | +# 获取对象信息 |
| 96 | + |
| 97 | +当我们拿到一个对象时,我们往往会考察它的类型和方法等,比如: |
| 98 | + |
| 99 | +``` |
| 100 | +>>> a = 123 |
| 101 | +>>> type(a) |
| 102 | +int |
| 103 | +>>> b = '123' |
| 104 | +>>> type(b) |
| 105 | +str |
| 106 | +``` |
| 107 | + |
| 108 | +当我们拿到一个类的对象时,我们用什么去考察它呢?回到前面的例子: |
| 109 | + |
| 110 | +```python |
| 111 | +class Animal(object): |
| 112 | + def __init__(self, name): |
| 113 | + self.name = name |
| 114 | + def greet(self): |
| 115 | + print 'Hello, I am %s.' % self.name |
| 116 | +``` |
| 117 | + |
| 118 | +- 第 1 招:使用 `type` |
| 119 | + |
| 120 | +使用 `type(obj)` 来获取对象的相应类型: |
| 121 | + |
| 122 | +``` |
| 123 | +>>> dog1 = Animal('dog1') |
| 124 | +>>> type(dog1) |
| 125 | +__main__.Animal |
| 126 | +``` |
| 127 | + |
| 128 | +- 第 2 招:使用 `isinstance` |
| 129 | + |
| 130 | +使用 `isinstance(obj, type)` 判断对象是否为指定的 type 类型的实例: |
| 131 | + |
| 132 | +``` |
| 133 | +>>> isinstance(dog1, Animal) |
| 134 | +True |
| 135 | +``` |
| 136 | + |
| 137 | +- 第 3 招:使用 `hasattr/getattr/setattr` |
| 138 | + |
| 139 | + - 使用 `hasattr(obj, attr)` 判断对象是否具有指定属性/方法; |
| 140 | + - 使用 `getattr(obj, attr[, default])` 获取属性/方法的值, 要是没有对应的属性则返回 default 值(前提是设置了 default),否则会抛出 AttributeError 异常; |
| 141 | + - 使用 `setattr(obj, attr, value)` 设定该属性/方法的值,类似于 obj.attr=value; |
| 142 | + |
| 143 | +看下面例子: |
| 144 | + |
| 145 | +```python |
| 146 | +>>> hasattr(dog1, 'name') |
| 147 | +True |
| 148 | +>>> hasattr(dog1, 'x') |
| 149 | +False |
| 150 | +>>> hasattr(dog1, 'greet') |
| 151 | +True |
| 152 | +>>> getattr(dog1, 'name') |
| 153 | +'dog1' |
| 154 | +>>> getattr(dog1, 'greet') |
| 155 | +<bound method Animal.greet of <__main__.Animal object at 0x10c3564d0>> |
| 156 | +>>> getattr(dog1, 'x') |
| 157 | +--------------------------------------------------------------------------- |
| 158 | +AttributeError Traceback (most recent call last) |
| 159 | +<ipython-input-241-42f5b7da1012> in <module>() |
| 160 | +----> 1 getattr(dog1, 'x') |
| 161 | + |
| 162 | +AttributeError: 'Animal' object has no attribute 'x' |
| 163 | +>>> getattr(dog1, 'x', 'xvalue') |
| 164 | +'xvalue' |
| 165 | +>>> setattr(dog1, 'age', 12) |
| 166 | +>>> dog1.age |
| 167 | +12 |
| 168 | +``` |
| 169 | + |
| 170 | +- 第 4 招:使用 `dir` |
| 171 | + |
| 172 | +使用 `dir(obj)` 可以获取相应对象的**所有**属性和方法名的列表: |
| 173 | + |
| 174 | +```python |
| 175 | +>>> dir(dog1) |
| 176 | +['__class__', |
| 177 | + '__delattr__', |
| 178 | + '__dict__', |
| 179 | + '__doc__', |
| 180 | + '__format__', |
| 181 | + '__getattribute__', |
| 182 | + '__hash__', |
| 183 | + '__init__', |
| 184 | + '__module__', |
| 185 | + '__new__', |
| 186 | + '__reduce__', |
| 187 | + '__reduce_ex__', |
| 188 | + '__repr__', |
| 189 | + '__setattr__', |
| 190 | + '__sizeof__', |
| 191 | + '__str__', |
| 192 | + '__subclasshook__', |
| 193 | + '__weakref__', |
| 194 | + 'age', |
| 195 | + 'greet', |
| 196 | + 'name'] |
| 197 | +``` |
| 198 | + |
| 199 | +# 小结 |
| 200 | + |
| 201 | +- 类是具有相同**属性**和**方法**的一组对象的集合,实例是一个个具体的对象。 |
| 202 | +- 方法是与实例绑定的函数。 |
| 203 | +- 获取对象信息可使用下面方法: |
| 204 | + - `type(obj)`:来获取对象的相应类型; |
| 205 | + - `isinstance(obj, type)`:判断对象是否为指定的 type 类型的实例; |
| 206 | + - `hasattr(obj, attr)`:判断对象是否具有指定属性/方法; |
| 207 | + - `getattr(obj, attr[, default])` 获取属性/方法的值, 要是没有对应的属性则返回 default 值(前提是设置了 default),否则会抛出 AttributeError 异常; |
| 208 | + - `setattr(obj, attr, value)`:设定该属性/方法的值,类似于 obj.attr=value; |
| 209 | + - `dir(obj)`:可以获取相应对象的**所有**属性和方法名的列表: |
| 210 | + |
| 211 | +# 参考资料 |
| 212 | + |
| 213 | +- [Python:类和对象object | Hom](http://gohom.win/2015/10/20/pyObject/) |
| 214 | + |
| 215 | + |
0 commit comments