# 2.4.4 类方法

本节目标：

* 掌握`@classmethod`，`@staticmethod`，`@property`几个装饰器。
* 完成本周的大\~作\~业\~

**Learning By Reading 难度：★ 重要性：★★★★★**

*   阅读材料，了解[类方法、静态方法](http://blog.csdn.net/handsomekang/article/details/9615239)和

    [属性函数](http://python.jobbole.com/80955)。

```python
class MyTurtle(turtle.Turtle):

    _all_turtles = {} # 用一个dict将小海龟名字和小海龟对象本身对应起来

    def __init__(self, name, *args, **kwds):
        super(MyTurtle).__init__(*args, **kwds)
        self.name = name
        MyTurtle._all_turtles[name] = self

    @property
    def n_turtles(self):
        return len(MyTurtle._all_turtles)

    @classmethod
    def get_by_name(cls, name):
        return cls._all_turtles[name]


ada = MyTurtle('ada')
another_ada = MyTurtle.get_by_name('ada')
if ada == another_ada:
    print("相等！")
print(ada.n_turtles) # 结果：1
```

注意`property`只能用在对象上，如果`MyTurtle.n_turtles`会返回一个`property`类型对象。

**Learning By Thinking 难度：★★★★ 重要性：★★★★**

*   `classmethod`、`staticmethod`、`property`都是装饰器，

    想想它们可以怎样实现。

**Learning By Doing 难度：★★★★ 重要性：★★**

*   试着实现`MyClassmethod`、

    `MyStaticmethod`、`MyProperty`，让它们基本具有和`classmethod`、`staticmethod`、`property`同样的功能。

我来选一个最难的`staticmethod`解释一下\~

先观察一下

```python
class MyClass(object):

    def method_1(self):
        pass

    @staticmethod
    def sm_1():
        pass

print(type(MyClass.method_1)) # function
print(type(MyClass.sm_1)) # function
print(type(MyClass().method_1)) # method
print(type(MyClass().sm_1)) # function
```

也就是说，普通的方法，当通过类名来调用时，它是一个`function`，而通过一个对象来调用时，是一个`method`。 但一个`staticmethod`怎么都是`function`。

所以我们的目标是实现一个让`function`不管被类还是被对象调用时都得到`function`的装饰器。

```python
class MyStaticmethod(object):

    def __init__(self, func):
        self.func = func

    def __get__(self, instance, owner):
        return self.func

class MyClass(object):

    @MyStaticmethod
    def some_staticmethod(some_value):
        return some_value
```

`__get__`是一个魔术方法，定义了当前对象如何被作为别的对象的属性获取， `a.b`等价于`a.b.__get__(a, a.__class__)`。

**Learning By Doing 难度：★★★★ 重要性：★★★**

之前我们定义了`n_turtles`这个`property`，`property`只能用对象调用，但“`MyTurtle`有多少个海龟”， 即`MyTurtle.n_turtles`，比“`ada`有多少海龟”，即`ada.n_turtles`听起来更合理一些。 你能设计一个继承了`property`的`ClassProperty`完成这个需求吗？

**Learning By Doing 难度：★★★★★ 重要性：★★★★★**

* 阶段性测试：
  1. 画一个随机生成的迷宫
  2. 把小海龟放在里面，让它自己走出来。
* 如何迷宫生成参考[这里](http://maskray.me/blog/2012-11-02-perfect-maze-generation)。
