# 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)。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://coding-girls-club.gitbook.io/python-turtle-tutorial/2-python-bian-cheng/2.4-ding-yi-lei-mi-gong/2.4.4-lei-fang-fa.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
