Skip to content

Commit 996307f

Browse files
committed
update
1 parent e855fe0 commit 996307f

File tree

1 file changed

+231
-0
lines changed
  • bornforthis/column/python60

1 file changed

+231
-0
lines changed

bornforthis/column/python60/02.md

Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,11 +286,242 @@ Python 使用关键字 class 定制自己的类,self 表示类实例对象本
286286

287287
一个自定义类内包括属性、方法,其中有些方法是自带的。
288288

289+
**类(对象):**
289290

291+
```python
292+
class Dog(object):
293+
pass
294+
```
295+
296+
以上定义一个 Dog 对象,它继承于根类 object,pass 表示没有自定义任何属性和方法。
297+
298+
下面创建一个 Dog 类型的实例:
299+
300+
```python
301+
wangwang = Dog()
302+
```
303+
304+
Dog 类现在没有定义任何方法,但是刚才说了,它会有自带的方法,使用 `__dir__()` 查看这些自带方法:
305+
306+
```python
307+
In [26]: wangwang.__dir__()
308+
Out[26]:
309+
['__module__',
310+
'__dict__',
311+
'__weakref__',
312+
'__doc__',
313+
'__repr__',
314+
'__hash__',
315+
'__str__',
316+
'__getattribute__',
317+
'__setattr__',
318+
'__delattr__',
319+
'__lt__',
320+
'__le__',
321+
'__eq__',
322+
'__ne__',
323+
'__gt__',
324+
'__ge__',
325+
'__init__',
326+
'__new__',
327+
'__reduce_ex__',
328+
'__reduce__',
329+
'__subclasshook__',
330+
'__init_subclass__',
331+
'__format__',
332+
'__sizeof__',
333+
'__dir__',
334+
'__class__']
335+
```
336+
337+
有些地方称以上方法为魔法方法,它们与创建类时自定义个性化行为有关。比如:
338+
339+
- `__init__` 方法能定义一个带参数的类;
340+
- `__new__` 方法自定义实例化类的行为;
341+
- `__getattribute__` 方法自定义读取属性的行为;
342+
- `__setattr__` 自定义赋值与修改属性时的行为。
343+
344+
**类的属性:**
345+
346+
```python
347+
def __init__(self, name, dtype):
348+
self.name = name
349+
self.dtype = dtype
350+
```
351+
352+
通过 `__init__`,定义 Dog 对象的两个属性:name、dtype。
353+
354+
**类的实例:**
355+
356+
```python
357+
wangwang = Dog('wangwang','cute_type')
358+
```
359+
360+
`wangwang``Dog` 类的实例。
361+
362+
**类的方法:**
363+
364+
```python
365+
def shout(self):
366+
print('I\'m %s, type: %s' % (self.name, self.dtype))
367+
```
368+
369+
**注意:**
370+
371+
- 自定义方法的第一个参数必须是 self,它指向实例本身,如 Dog 类型的实例 dog;
372+
- 引用属性时,必须前面添加 self,比如 `self.name` 等。
373+
374+
总结以上代码:
375+
376+
```python
377+
In [40]: class Dog(object):
378+
...: def __init__(self,name,dtype):
379+
...: self.name=name
380+
...: self.dtype=dtype
381+
...: def shout(self):
382+
...: print('I\'m %s, type: %s' % (self.name, self.dtype))
383+
384+
In [41]: wangwang = Dog('wangwang','cute_type')
385+
386+
In [42]: wangwang.name
387+
Out[42]: 'wangwang'
388+
389+
In [43]: wangwang.dtype
390+
Out[43]: 'cute_type'
391+
392+
In [44]: wangwang.shout()
393+
I'm wangwang, type: cute_type
394+
```
395+
396+
看到创建的两个属性和一个方法都被暴露在外面,可被 wangwang 调用。这样的话,这些属性就会被任意修改:
397+
398+
```python
399+
In [49]: wangwang.name='wrong_name'
400+
401+
In [50]: wangwang.name
402+
Out[50]: 'wrong_name'
403+
```
404+
405+
如果想避免属性 name 被修改,可以将它变为私有变量。改动方法:属性前加 2 个 `_` 后,变为私有属性。如:
406+
407+
```python
408+
In [51]: class Dog(object):
409+
...: def __init__(self,name,dtype):
410+
...: self.__name=name
411+
...: self.__dtype=dtype
412+
...: def shout(self):
413+
...: print('I\'m %s, type: %s' % (self.name, self.dtype))
414+
```
415+
416+
同理,方法前加 2 个 `_` 后,方法变为“私有方法”,只能在 Dog 类内被共享使用。
417+
418+
但是这样改动后,属性 name 不能被访问了,也就无法得知 wangwang 的名字叫啥。不过,这个问题有一种简单的解决方法,直接新定义一个方法就行:
419+
420+
```python
421+
def get_name(self):
422+
return self.__name
423+
```
424+
425+
综合代码:
426+
427+
```python
428+
In [52]: class Dog(object):
429+
...: def __init__(self,name,dtype):
430+
...: self.__name=name
431+
...: self.__dtype=dtype
432+
...: def shout(self):
433+
...: print('I\'m %s, type: %s' % (self.name, self.dtype))
434+
...: def get_name(self):
435+
...: return self.__name
436+
...:
437+
438+
In [53]: wangwang = Dog('wangwang','cute_type')
439+
440+
In [54]: wangwang.get_name()
441+
Out[54]: 'wangwang'
442+
```
443+
444+
但是,通过此机制,改变属性的可读性或可写性,怎么看都不太优雅!因为无形中增加一些冗余的方法,如 `get_name`
445+
446+
下面,通过另一个例子,解释如何更优雅地改变某个属性为只读或只写。
447+
448+
自定义一个最精简的 Book 类,它继承于系统的根类 object:
449+
450+
```python
451+
class Book(object):
452+
def __init__(self, name, sale):
453+
self.__name = name
454+
self.__sale = sale
455+
```
456+
457+
使用 Python 自带的 property 类,就会优雅地将 name 变为只读的。
458+
459+
```python
460+
@property
461+
def name(self):
462+
return self.__name
463+
```
464+
465+
使用 @property 装饰后 name 变为属性,意味着 `.name` 就会返回这本书的名字,而不是通过 `.name()` 这种函数调用的方法。这样变为真正的属性后,可读性更好。
466+
467+
```python
468+
In [101]: class Book(object):
469+
...: def __init__(self, name, sale):
470+
...: self.__name = name
471+
...: self.__sale = sale
472+
...: @property
473+
...: def name(self):
474+
...: return self.__name
475+
476+
In [102]: a_book = Book('magic_book',100000)
477+
478+
In [103]: a_book.name
479+
Out[103]: 'magic_book'
480+
```
481+
482+
property 是 Python 自带的类,前三个参数都是函数类型。更加详细的讨论放在后面讨论装饰器时再展开。
483+
484+
```python
485+
In [104]: help(property)
486+
Help on class property in module builtins:
487+
488+
class property(object)
489+
| property(fget=None, fset=None, fdel=None, doc=None)
490+
```
491+
492+
如果使 name 既可读又可写,就再增加一个装饰器 `@name.setter` 。
493+
494+
```python
495+
In [105]: class Book(object):
496+
...: def __init__(self, name, sale):
497+
...: self.__name = name
498+
...: self.__sale = sale
499+
...: @property
500+
...: def name(self):
501+
...: return self.__name
502+
...: @name.setter
503+
...: def name(self,new_name):
504+
...: self.__name = new_name
505+
506+
In [106]: a_book = Book('magic_book',100000)
507+
508+
In [107]: a_book.name = 'magic_book_2.0'
509+
510+
In [108]: a_book.name
511+
Out[108]: 'magic_book_2.0'
512+
```
513+
514+
注意这种装饰器写法:name.setter,name 已经被包装为 property 实例,调用实例上的 setter 函数再包装 name 后就会可写。对于 Python 入门者,可以暂时不用太纠结这部分理论,使用 Python 一段时间后,再回过头来自然就会理解。
515+
516+
## 小结
290517

518+
今天学习 Python 的四大基本数据类型。数值型 int、float 等;容器型 list、dict、tuple、set 等;字符型 str 与正则表达式介绍;自定义类的基本语法规则,class、属性和方法等。
291519

520+
**动画对应短视频下载链接:**
292521

522+
https://pan.baidu.com/s/1MrnrXEnl54XDYYwkZbSqSA
293523

524+
提取码:634k
294525

295526

296527

0 commit comments

Comments
 (0)