# 魔术

### 构造方法

1.`__init__`：指明一个对象初始化的行为，它获取任何传给构造器的参数

2.调用`x = SomeClass()` 的时候， `__init__` 并不是第一个被调用的方法，事实上，第一个被调用的是 `__new__`

3.对象的生命周期结束的时候， `__del__` 会被调用

### 比较

`__eq__(self, other)`定义等于操作符(==)的行为。

```
def __eq__(self, other): # 定义内置方法 ，判定类相等
    return self.__dict__ == other.__dict__ # 判断的是两对象空间的属性值是否相等
```

`__ne__(self, other)`定义不等于操作符(!=)的行为。

`__lt__(self, other)`定义小于操作符(<)的行为。

`__gt__(self, other)`定义大于操作符(>)的行为。

`__le__(self, other)`定义小于等于操作符(<)的行为。

`__ge__(self, other)`定义大于等于操作符(>)的行为。

### 一元操作

`__pos__(self)`实现取正操作，例如 `+some_object`。

`__neg__(self)`实现取负操作，例如 `-some_object`。

`__abs__(self)`实现内建绝对值函数 `abs()` 操作。

`__invert__(self)`实现取反操作符 `~`。

`__round__(self， n)`实现内建函数 `round()` ，n 是近似小数点的位数。

`__floor__(self)`实现 `math.floor()` 函数，即向下取整。

`__ceil__(self)`实现 `math.ceil()` 函数，即向上取整。

`__trunc__(self)`实现 `math.trunc()` 函数，即距离零最近的整数。

### 算数操作

`__add__(self, other)`实现加法操作。

`__sub__(self, other)`实现减法操作。

`__mul__(self, other)`实现乘法操作。

`__floordiv__(self, other)`实现使用 `//` 操作符的整数除法。

`__div__(self, other)`实现使用 `/` 操作符的除法。

`__truediv__(self, other)`实现 `_true_` 除法，这个函数只有使用 `from __future__ import division` 时才有作用。

`__mod__(self, other)`实现 `%` 取余操作。

`__divmod__(self, other)`实现 `divmod` 内建函数。

`__pow__`实现 `**` 操作符。

`__lshift__(self, other)`实现左移位运算符 <<`;`。

`__rshift__(self, other)`实现右移位运算符>> 。

`__and__(self, other)`实现按位与运算符 `&` 。

`__or__(self, other)`实现按位或运算符 `|` 。

`__xor__(self, other)`实现按位异或运算符 `^` 。

### 反射算数运算

some\_object + other：是“常见”的加法；

反射是一样的意思，只不过是运算符交换了一下位置:other + some\_object；

`__radd__(self, other)`实现反射加法操作。

`__rsub__(self, other)`实现反射减法操作。

`__rmul__(self, other)`实现反射乘法操作。

`__rfloordiv__(self, other)`实现使用 `//` 操作符的整数反射除法

### 增强赋值运算

a += b

`__iadd__(self, other)`实现加法赋值操作。

`__isub__(self, other)`实现减法赋值操作。

..........

### 类型转换操作

`__int__(self)`实现到int的类型转换。

`__long__(self)`实现到long的类型转换。

`__float__(self)`实现到float的类型转换。

`__complex__(self)`实现到complex的类型转换。

`__oct__(self)`实现到八进制数的类型转换。

`__hex__(self)`实现到十六进制数的类型转换。

### 类的表示

`__str__(self)`定义对类的实例调用 `str()` 时的行为， 产生人类可读的输出。

`__repr__(self)`将对象转化为供解释器读取的形式，产生机器可读的输出，方便print。

### 访问控制

`__getattr__(self, name)`当用户试图访问一个根本不存在（或者暂时不存在）的属性时，你可以通过这个魔法方法来定义类的行为。这个可以用于捕捉错误的拼写并且给出指引，使用废弃属性时给出警告，只有当试图访问不存在的属性时它才会被调用，所以这不能算是一个真正的封装的办法。

`__setattr__(self, name, value)`它允许你自定义某个属性的赋值行为。

`__delattr__(self, name)`这个魔法方法和 `__setattr__` 几乎相同，只不过它是用于处理删除属性时的行为。

`使用注意!!!!`

```python
# 错误形式
def __setattr__(self, name. value):
    self.name = value
    # 因为每次属性幅值都要调用 __setattr__()，所以这里的实现会导致递归
    # 这里的调用实际上是 self.__setattr('name', value)。因为这个方法一直
    # 在调用自己，因此递归将持续进行，直到程序崩溃

# 正确形式
def __setattr__(self, name, value):
    self.__dict__[name] = value # 使用 __dict__ 进行赋值
    # 定义自定义行为
```

## 自定义序列

`让Python类表现得像是内建序列类型（字典，元组，列表，字符串等）`

* 如：想实现一个不可变容器，需要定义 `__len__` 和 `__getitem__` ，可变容器的协议除了上面提到的两个方法之外，还需要定义 `__setitem__` 和 `__delitem__` 。
* 想让你的对象可以迭代，你需要定义 `__iter__` ，这个方法返回一个迭代器，需要定义 `__iter__` （返回它自己）和 `next` 方法。
* `__len__(self)`返回容器的长度，可变和不可变类型都需要实现。
* `__getitem__(self, key)`定义对容器中某一项使用 `self[key]` 的方式进行`读取操作`时的行为。
* `__setitem__(self, key)`定义对容器中某一项使用 `self[key]` 的方式进行`赋值操作`时的行为，它是可变容器类型必须实现的一个方法。
* `__iter__(self, key)`它应该返回当前容器的一个迭代器，最常见的是使用 `iter()` 函数调用，以及在类似 `for x in container:` 的循环中被调用。迭代器是他们自己的对象，需要定义 `__iter__`方法并在其中返回自己。
* `__reversed__(self)`定义了对容器使用 `reversed()` 内建函数时的行为。应该返回一个反转之后的序列。当你的序列类是有序时，类似列表和元组，再实现这个方法。
* `__contains__(self, item)`定义了使用 `in` 和 `not in` 进行成员测试时类的行为，如果 `__contains__` 没有定义，Python就会迭代整个序列，如果找到了需要的一项就返回 `True` 。
* `__missing__(self ,key)`它定义了当试图访问一个字典中不存在的键时的行为（目前为止是指字典的实例，例如我有一个字典 `d` ， `"george"` 不是字典中的一个键，当试图访问 `d["george']` 时就会调用 `d.__missing__("george")` ）

例子：实现了一些函数式结构的列表

```python
class FunctionalList:
    '''一个列表的封装类，实现了一些额外的函数式
    方法，例如head, tail, init, last, drop和take。'''

    def __init__(self, values=None):
        if values is None:
            self.values = []
        else:
            self.values = values

    def __len__(self):
        return len(self.values)

    def __getitem__(self, key):
        # 如果键的类型或值不合法，列表会返回异常
        return self.values[key]

    def __setitem__(self, key, value):
        self.values[key] = value

    def __delitem__(self, key):
        del self.values[key]

    def __iter__(self):# 迭代器
        return iter(self.values)

    def __reversed__(self):
        return reversed(self.values)

    def append(self, value):
        self.values.append(value)

    def head(self):
        # 取得第一个元素
        return self.values[0]

    def tail(self):
        # 取得除第一个元素外的所有元素
        return self.valuse[1:]

    def init(self):
        # 取得除最后一个元素外的所有元素
        return self.values[:-1]

    def last(self):
        # 取得最后一个元素
        return self.values[-1]

    def drop(self, n):
        # 取得除前n个元素外的所有元素
        return self.values[n:]

    def take(self, n):
        # 取得前n个元素
        return self.values[:n]
```

### 反射

`__instancecheck__(self, instance)`检查一个实例是否是你定义的类的一个实例（例如 `isinstance(instance, class)` ）。

`__subclasscheck__(self, subclass)`检查一个类是否是你定义的类的子类（例如 `issubclass(subclass, class)` ）。

### 上下文管理

`with` 声明创建时，上下文管理器允许类做一些设置和清理工作。上下文管理器的行为由下面两个魔法方法所定义：

`__enter__(self)`定义使用 `with` 声明创建的语句块最开始上下文管理器应该做些什么。

`__enter__` 的返回值会赋给 `with` 声明的目标，也就是 `as` 之后的名字。

`__exit__(self, exception_type, exception_value, traceback)`定义当 `with` 声明语句块执行完毕（或终止）时上下文管理器的行为。它可以用来处理异常，进行清理，或者做其他应该在语句块结束之后立刻执行的工作。

```python
class Foo(object):

    def __init__(self):
        print('实例化一个对象')

    def __enter__(self):
        print('进入')

    def __exit__(self, exc_type, exc_val, exc_tb):
        print('退出')

obj = Foo()

with obj:
    print('正在执行')

'''
实例化一个对象
进入
正在执行
退出
'''
```

### 拷贝

copy.copy 浅拷贝 只拷贝父对象，不会拷贝对象的内部的子对象。

copy.deepcopy 深拷贝 拷贝对象及其子对象

`__copy__(self)`返回一个对象的浅拷贝，这意味着拷贝出的实例是全新的，然而里面的数据全都是引用的。也就是说，对象本身是拷贝的，但是它的数据还是引用的（所以浅拷贝中的数据更改会影响原对象）。

`__deepcopy__(self, memodict=)`实例使用 `copy.deepcopy()` 时的行为。 `copy.deepcopy()` 返回一个对象的深拷贝，这个对象和它的数据全都被拷贝了一份。


---

# 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://im-qianuxn.gitbook.io/pytorch/ji-suan-ji/python/magic-way.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.
