# å®å¶ç±»åéæ³æ¹æ³
å¨ Python ä¸ï¼æä»¬å¯ä»¥ç»å¸¸çå°ä»¥åä¸å线 `__` å
裹起æ¥çæ¹æ³ï¼æ¯å¦æå¸¸è§ç `__init__`ï¼è¿äºæ¹æ³è¢«ç§°ä¸º**éæ³æ¹æ³ï¼magic methodï¼æç¹æ®æ¹æ³ï¼special methodï¼**ãç®åå°è¯´ï¼è¿äºæ¹æ³å¯ä»¥ç» Python çç±»æä¾ç¹æ®åè½ï¼æ¹ä¾¿æä»¬å®å¶ä¸ä¸ªç±»ï¼æ¯å¦ `__init__` æ¹æ³å¯ä»¥å¯¹å®ä¾å±æ§è¿è¡åå§åã
宿´çç¹æ®æ¹æ³å表å¯å¨[è¿é](https://docs.python.org/2/reference/datamodel.html#special-method-names)æ¥çï¼æ¬æä»ç»é¨å常ç¨çç¹æ®æ¹æ³ï¼
- `__new__`
- `__str__` , `__repr__`
- `__iter__`
- `__getitem__` , `__setitem__` , `__delitem__`
- `__getattr__` , `__setattr__` , `__delattr__`
- `__call__`
# new
å¨ Python ä¸ï¼å½æä»¬å建ä¸ä¸ªç±»çå®ä¾æ¶ï¼ç±»ä¼å
è°ç¨ `__new__(cls[, ...])` æ¥å建å®ä¾ï¼ç¶å `__init__` æ¹æ³å对该å®ä¾ï¼selfï¼è¿è¡åå§åã
å
³äº `__new__` å `__init__` æå ç¹éè¦æ³¨æï¼
- `__new__` æ¯å¨ `__init__` ä¹å被è°ç¨çï¼
- `__new__` æ¯ç±»æ¹æ³ï¼`__init__` æ¯å®ä¾æ¹æ³ï¼
- éè½½ `__new__` æ¹æ³ï¼éè¦è¿åç±»çå®ä¾ï¼
ä¸è¬æ
åµä¸ï¼æä»¬ä¸éè¦éè½½ `__new__` æ¹æ³ãä½å¨æäºæ
åµä¸ï¼æä»¬æ³**æ§å¶å®ä¾çå建è¿ç¨**ï¼è¿æ¶å¯ä»¥éè¿éè½½ `__new_` æ¹æ³æ¥å®ç°ã
让æä»¬çä¸ä¸ªä¾åï¼
```python
class A(object):
_dict = dict()
def __new__(cls):
if 'key' in A._dict:
print "EXISTS"
return A._dict['key']
else:
print "NEW"
return object.__new__(cls)
def __init__(self):
print "INIT"
A._dict['key'] = self
```
å¨ä¸é¢ï¼æä»¬å®ä¹äºä¸ä¸ªç±» `A`ï¼å¹¶éè½½äº `__new__` æ¹æ³ï¼å½ `key` å¨ `A._dict` 䏿¶ï¼ç´æ¥è¿å `A._dict['key']`ï¼å¦åå建å®ä¾ã
æ§è¡æ
åµï¼
```
>>> a1 = A()
NEW
INIT
>>> a2 = A()
EXISTS
INIT
>>> a3 = A()
EXISTS
INIT
```
# str & repr
å
çä¸ä¸ªç®åçä¾åï¼
```python
class Foo(object):
def __init__(self, name):
self.name = name
>>> print Foo('ethan')
<__main__.Foo object at 0x10c37aa50>
```
å¨ä¸é¢ï¼æä»¬ä½¿ç¨ print æå°ä¸ä¸ªå®ä¾å¯¹è±¡ï¼ä½å¦ææä»¬æ³æå°æ´å¤ä¿¡æ¯å¢ï¼æ¯å¦æ name 乿å°åºæ¥ï¼è¿æ¶ï¼æä»¬å¯ä»¥å¨ç±»ä¸å å
¥ `__str__` æ¹æ³ï¼å¦ä¸ï¼
```python
class Foo(object):
def __init__(self, name):
self.name = name
def __str__(self):
return 'Foo object (name: %s)' % self.name
>>> print Foo('ethan') # ä½¿ç¨ print
Foo object (name: ethan)
>>>
>>> str(Foo('ethan')) # ä½¿ç¨ str
'Foo object (name: ethan)'
>>>
>>> Foo('ethan') # ç´æ¥æ¾ç¤º
<__main__.Foo at 0x10c37a490>
```
å¯ä»¥çå°ï¼ä½¿ç¨ print å str è¾åºçæ¯ `__str__` æ¹æ³è¿åçå
容ï¼ä½å¦æç´æ¥æ¾ç¤ºå䏿¯ï¼é£è½ä¸è½ä¿®æ¹å®çè¾åºå¢ï¼å½ç¶å¯ä»¥ï¼æä»¬åªéå¨ç±»ä¸å å
¥ `__repr__` æ¹æ³ï¼æ¯å¦ï¼
```python
class Foo(object):
def __init__(self, name):
self.name = name
def __str__(self):
return 'Foo object (name: %s)' % self.name
def __repr__(self):
return 'Foo object (name: %s)' % self.name
>>> Foo('ethan')
'Foo object (name: ethan)'
```
å¯ä»¥çå°ï¼ç°å¨ç´æ¥ä½¿ç¨ `Foo('ethan')` ä¹å¯ä»¥æ¾ç¤ºæä»¬æ³è¦çç»æäºï¼ç¶èï¼æä»¬åç°ä¸é¢ç代ç ä¸ï¼`__str__` å `__repr__` æ¹æ³çä»£ç æ¯ä¸æ ·çï¼è½ä¸è½ç²¾ç®ä¸ç¹å¢ï¼å½ç¶å¯ä»¥ï¼å¦ä¸ï¼
```python
class Foo(object):
def __init__(self, name):
self.name = name
def __str__(self):
return 'Foo object (name: %s)' % self.name
__repr__ = __str__
```
# iter
å¨æäºæ
åµä¸ï¼æä»¬å¸æå®ä¾å¯¹è±¡å¯è¢«ç¨äº `for...in` 循ç¯ï¼è¿æ¶æä»¬éè¦å¨ç±»ä¸å®ä¹ `__iter__` å `next`ï¼å¨ Python3 䏿¯ `__next__`ï¼æ¹æ³ï¼å
¶ä¸ï¼`__iter__` è¿åä¸ä¸ªè¿ä»£å¯¹è±¡ï¼`next` è¿å容å¨çä¸ä¸ä¸ªå
ç´ ï¼å¨æ²¡æåç»å
ç´ æ¶æåº `StopIteration` å¼å¸¸ã
çä¸ä¸ªææ³¢é£å¥æ°åçä¾åï¼
```python
class Fib(object):
def __init__(self):
self.a, self.b = 0, 1
def __iter__(self): # è¿åè¿ä»£å¨å¯¹è±¡æ¬èº«
return self
def next(self): # è¿å容å¨ä¸ä¸ä¸ªå
ç´
self.a, self.b = self.b, self.a + self.b
return self.a
>>> fib = Fib()
>>> for i in fib:
... if i > 10:
... break
... print i
...
1
1
2
3
5
8
```
# getitem
ææ¶ï¼æä»¬å¸æå¯ä»¥ä½¿ç¨ `obj[n]` è¿ç§æ¹å¼å¯¹å®ä¾å¯¹è±¡è¿è¡åå¼ï¼æ¯å¦å¯¹ææ³¢é£å¥æ°åï¼æä»¬å¸æå¯ä»¥ååºå
¶ä¸çæä¸é¡¹ï¼è¿æ¶æä»¬éè¦å¨ç±»ä¸å®ç° `__getitem__` æ¹æ³ï¼æ¯å¦ä¸é¢çä¾åï¼
```python
class Fib(object):
def __getitem__(self, n):
a, b = 1, 1
for x in xrange(n):
a, b = b, a + b
return a
>>> fib = Fib()
>>> fib[0], fib[1], fib[2], fib[3], fib[4], fib[5]
(1, 1, 2, 3, 5, 8)
```
æä»¬è¿æ³æ´è¿ä¸æ¥ï¼å¸ææ¯æ `obj[1:3]` è¿ç§åçæ¹æ³æ¥åå¼ï¼è¿æ¶ `__getitem__` æ¹æ³ä¼ å
¥çåæ°å¯è½æ¯ä¸ä¸ªæ´æ°ï¼ä¹å¯è½æ¯ä¸ä¸ªåç对象 sliceï¼å æ¤ï¼æä»¬éè¦å¯¹ä¼ å
¥çåæ°è¿è¡å¤æï¼å¯ä»¥ä½¿ç¨ `isinstance` è¿è¡å¤æï¼æ¹åç代ç å¦ä¸ï¼
```python
class Fib(object):
def __getitem__(self, n):
if isinstance(n, slice): # 妿 n æ¯ slice 对象
a, b = 1, 1
start, stop = n.start, n.stop
L = []
for i in xrange(stop):
if i >= start:
L.append(a)
a, b = b, a + b
return L
if isinstance(n, int): # 妿 n æ¯ int å
a, b = 1, 1
for i in xrange(n):
a, b = b, a + b
return a
```
ç°å¨ï¼æä»¬è¯è¯ç¨åçæ¹æ³ï¼
```python
>>> fib = Fib()
>>> fib[0:3]
[1, 1, 2]
>>> fib[2:6]
[2, 3, 5, 8]
```
ä¸é¢ï¼æä»¬åªæ¯ç®åå°æ¼ç¤ºäº getitem çæä½ï¼ä½æ¯å®è¿å¾ä¸å®åï¼æ¯å¦æ²¡æå¯¹è´æ°å¤çï¼ä¸æ¯æå¸¦ step åæ°çåçæä½ `obj[1:2:5]` ççï¼è¯»è
æå
´è¶£çè¯å¯ä»¥èªå·±å®ç°ççã
`__geitem__` ç¨äºè·åå¼ï¼ç±»ä¼¼å°ï¼`__setitem__` ç¨äºè®¾ç½®å¼ï¼`__delitem__` ç¨äºå é¤å¼ï¼è®©æä»¬çä¸é¢ä¸ä¸ªä¾åï¼
```python
class Point(object):
def __init__(self):
self.coordinate = {}
def __str__(self):
return "point(%s)" % self.coordinate
def __getitem__(self, key):
return self.coordinate.get(key)
def __setitem__(self, key, value):
self.coordinate[key] = value
def __delitem__(self, key):
del self.coordinate[key]
print 'delete %s' % key
def __len__(self):
return len(self.coordinate)
__repr__ = __str__
```
å¨ä¸é¢ï¼æä»¬å®ä¹äºä¸ä¸ª Point ç±»ï¼å®æä¸ä¸ªå±æ§ coordinateï¼åæ ï¼ï¼æ¯ä¸ä¸ªåå
¸ï¼è®©æä»¬çç使ç¨ï¼
```python
>>> p = Point()
>>> p['x'] = 2 # 对åºäº p.__setitem__('x', 2)
>>> p['y'] = 5 # 对åºäº p.__setitem__('y', 5)
>>> p # 对åºäº __repr__
point({'y': 5, 'x': 2})
>>> len(p) # 对åºäº p.__len__
2
>>> p['x'] # 对åºäº p.__getitem__('x')
2
>>> p['y'] # 对åºäº p.__getitem__('y')
5
>>> del p['x'] # 对åºäº p.__delitem__('x')
delete x
>>> p
point({'y': 5})
>>> len(p)
1
```
# getattr
彿们è·å对象çæä¸ªå±æ§ï¼å¦æè¯¥å±æ§ä¸åå¨ï¼ä¼æåº AttributeError å¼å¸¸ï¼æ¯å¦ï¼
```python
class Point(object):
def __init__(self, x=0, y=0):
self.x = x
self.y = y
>>> p = Point(3, 4)
>>> p.x, p.y
(3, 4)
>>> p.z
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)