下面时latex源代码,大家可以自己编译一下:
\subsubsection{成员关系:$\_\_contains\_\_, \_\_iter\_\_, \_\_getitem\_s\_$}
\par{
\begin{itemize}
\item 首先再强调一个特别的地方,为什么:for i in Class()这样的语句能够被执行?因为这Class()是一个类,并且for语句调用了$\_\_iter\_\_$方法,于是这个for循环实际就是$\_\_iter\_\_$方法的调用,所以自然可以执行啦。
\item 另外注意,$\_\_iter\_\_$方法被调用时,会一直调用到raise StopIteration,所以比如只有for i in iter([1, 2, 3]): 但是实际上$\_\_next\_\_$会执行4次,只是最后一次到raise StopIteration,for循环不打印出来罢了。
\item 总的来说,$\_\_contains\_\_$会拦截成员关系,比如形如x in class()的判断会优先使用$\_\_contains\_\_$,但是如果$\_\_contains\_\_$没有在类里被重载,那么就会优先使用$\_\_iter\_\_$, 但如果$\_\_iter\_\_$也没使用,就会使用$\_\_getitem\_\_$重载符。如果都没有,就自然使用默认的重载符功能。
\item $\_\_contains\_\_$:一个重载关系符号in的操作,比如:
\begin{lstlisting}[language = {python}]
class Person(object):
def __init__(self,name,age):
self.name = name
self.age = age
def __contains__(self,param1):
return True if param1 in self.__dict__.keys() else False
>>> p = Person('Robby Krieger',23)
>>> 'name' in p
True
#这里在in左边的对象是__contains__中的可变参数,右边的实例p即参数中的self参数。
\end{lstlisting}
\item 猜测注释掉$\_\_contains\_\_$后,in的实现过程是,首先还是会考虑$\_\_iter\_\_$方法,依靠它和$\_\_next\_\_$逐一返回迭代值和in右边的属比较,直到True或者False停止。
\item 所以可见,尽管注释掉$\_\_contains\_\_$后,也不是$\_\_iter\_\_$直接替换$\_\_contains\_\_$,而是还有一些别的操作,结合$\_\_contains\_\_$一起做出结果判断。
\item $\_\_iter\_\_$和yield结合起来用可以代替$\_\_iter\_\_$和$\_\_next\_\_$组合。因为这样for循环每次调用时,会受到yield一次又一次返回的值。
\end{itemize}
}
\subsubsection{$\_\_getattr\_\_$ and $\_\_setattr\_\_$}
\par{
\begin{itemize}
\item 首先$\_\_getattr\_\_$是在进行实例.属性(某个不存在属性)这样的点操作时会调用的方法。
\item 其次$\_\_setattr\_\_$:
首先注意下面这个属性赋值的重载方法:
\begin{lstlisting}[language = {Python}]
def __setattr__(self, key, value):
object.__setattr__(self, key, value)
#这里直接接一句object.__setattr__(self, key, value)表示其实根本不需要重载。
#这个重载主要就是想,对于value是base类型的的哪些,我们做一些特殊操作,即假如 value 是 Base 检查, 放到队列中
#而数据类型本身因为object.__setattr__(self, key, value)的出现,仍然使用原来的赋值操作。
if isinstance(value, Base):
p: Base = value
if p.pin_type == PinType.Input:
self.__in_data.insert(p.index, p)
else:
self.__out_data.insert(p.index, p)
pass
#其次如果是 object.__setattr__(self, attr, value + 10),首先它能比避免循环是因为调用父类的赋值方法进行赋值,且又不是把value赋值给attr,而是把value+10赋值给attr,从而完成重载。
\end{lstlisting}
\item $\_\_delattr\_\_$和$\_\_setattr\_\_$用法类似,要不用$\_\_dict\_\_$要不用父类来避免循环调用。
\end{itemize}
}
\subsubsection{字符串显示$\_\_repr\_\_$ and $\_\_str\_\_$}
\begin{itemize}
\item $\_\_repr\_\_$: 将会在函数str(), 或者打印这个类的时候被调用。
\item $\_\_str\_\_$支持print()和str()时候的调用,不过print()和str()下$\_\_str\_\_$被重载时,会优先于$\_\_repr\_\_$。但是其他场景只会用$\_\_repr\_\_$(如交互式和命令行显示)
\item 所以$\_\_repr\_\_$用于全场景,而 $\_\_str\_\_$优先使用于打印和str()函数。
\item 注意这俩重载符只会返回字符串,所以如果时其他类型,注意使用str()函数或者$ \% $符号
\end{itemize}
\subsubsection{右侧加法和原位置加法$\_\_radd\_\_$ and $\_\_iadd\_\_$}
\par{
\begin{itemize}
\item 简单来说,$\_\_radd\_\_$用来处理实例在左边的情况。
\item 如果想处理实例在右边的情况,要么重写$\_\_radd\_\_$调用$\_\_add\_\_$,要么直接在类里面声明:$\_\_radd\_\_$ = $\_\_add\_\_$
\end{itemize}
}