比较运算相关的魔法方法包括:__lt__()(<)、__le__()(<=)、__gt__()(>)、__ge__()(>=)、__eq__()(==)、__ne__()(!=)。通过重写这些魔法方法,可以实现对两个字符串长度而非编码值的快速比较。
最后,当我们不想让某个魔法方法生效时,只需将其赋值为None,此时若该魔法方法被触发,程序便会报错。通过这种手段,我们就可以阻止某些不希望的情形(如成员关系判断等)出现,抑制了Python可能引发误会的代偿机制,进而避免了难以调试的bug,真是未雨绸缪的好主意啊! Learning....
Support 小古比鱼
本帖最后由 Ensoleile 于 2023-1-13 00:22 编辑
代偿
#__contains__()主要用于实现成员关系的检测,对应in、not in
class C:
def __init__(self, data):
self.data = data
def __contains__(self, item):
print('hello')
return item in self.data
c =C()
print(3 in c)
#hello
#True
#对应self.data,3对应__contains__()魔法方法中的item
#__contains__()代偿 P189 -> __iter__() + __next__() -> __getitem__()
class C:
def __init__(self, data):
self.data = data
def __iter__(self):
print('iter', end='->')
self.i = 0
return self
def __next__(self):
print('next', end='->')
if self.i == len(self.data):
raise StopIteration
item = self.data
self.i += 1
return item
c =C()
print(3 in c)
#iter->next->next->next->True
#首先调用iter将列表变为迭代器,再按个使用next拿出数据比较,直到找到的时候返回True
print(6 in c)
#iter->next->next->next->next->next->next->False
class C:
def __init__(self, data):
self.data = data
def __getitem__(self, item):# item对应的不是3 in c中的3,而是迭代时的0,1,2....
print('getitem', end='->')
return self.data
c = C()
print(3 in c)
# getitem->getitem->getitem->True
print(6 in c)
# getitem->getitem->getitem->getitem->getitem->getitem->False
#__bool__():布尔测试 -> __len__()
class D:
def __bool__(self):
print('bool')
return True
d = D()
print(bool(d))
# bool
# True
class D:
def __init__(self, data):
self.data = data
def __len__(self):
print('len')
return len(self.data)
d = D('fishc')
print(bool(d))
# len
# True 长度非零则直接返回True
d = D([])
print(bool(d))
# len
# False
#跟比较运算相关的魔法方法:P189 < <= > >= == !=
class S(str):
def __lt__(self, other):
return len(self) < len(other)
def __gt__(self, other):
return len(self) > len(other)
def __eq__(self, other):
return len(self) == len(other)
s1 = S('FishC')
s2 = S('fishc')
print(s1 < s2)#False
print(s1 > s2)#False
print(s1 == s2)#True
print(s1 != s2)#True
#__eq__()只会拦截等值判断(==),返回长度比较结果,不会拦截不等值判断(!=),故不等于号两边比较的依然是字符串ASCII码是否相同
print(s1 <= s2)#True
print(s1 >= s2)#False
#如果不想让某个魔法方法生效,可以直接将其赋值为None
class S(str):
def __lt__(self, other):
return len(self) < len(other)
def __gt__(self, other):
return len(self) > len(other)
def __eq__(self, other):
return len(self) == len(other)
__le__ = None
__ge__ = None
__ne__ = None
s1 = S('FishC')
s2 = S('fishc')
try:
s1 != s2
except TypeError as e:
print(e)
#'NoneType' object is not callable
#这种做法也适用与代偿实现,定义第一个魔法方法为None后可以使代偿不实现
class C:
def __init__(self, data):
self.data = data
def __iter__(self):
print('iter', end='->')
self.i = 0
return self
def __next__(self):
print('next', end='->')
if self.i == len(self.data):
raise StopIteration
item = self.data
self.i += 1
return item
__contains__ = None#__contains__ -> __iter__() + __next__() -> __getitem__()
c = C()
try:
print(3 in c)
except TypeError as e:
print(e)
#'C' object is not a container Ensoleile 发表于 2023-1-7 15:27
代偿
鱼油你好,我有些地方有点看不懂,不知能不能请你解惑一下。
你的第34行代码:按个使用next拿出数据比较,比如next拿出1,则item = 1,return item后执行什么操作呢?如果是3 in item的话好像不行吧,next()返回的类型是int,这样3 in 3 我试过了会报错。
还有就是为什么没找到会继续使用next寻找?而找到了又是如何输出True而不继续遍历完列表呢?
Tzz123 发表于 2023-2-16 13:01
鱼油你好,我有些地方有点看不懂,不知能不能请你解惑一下。
你的第34行代码:按个使用next拿出数据比较 ...
return item 后比较 3 == item , 不相等就继续__next__ , 3 in3 报错是因为后面的参数需要可迭代对象 ,没找到继续找是因为代偿机制 ,找到了就相当于 3 == 3 为True。总结为一句话就是in运算符的机制需要后面的参数为可迭代对象。 ## __contains\_\_(self, item)
用于实现成员关系的检测,对应的运算符是in 和 not in
```python
class C:
def __init__(self, data):
self.data = data
def __contains__(self, item):
print("嗨~")
return item in self.data
c = C()
3 in c
嗨~
True
6 in c
嗨~
False
```
### 代偿
Python在找不到`__iter__()`和`__next__()`魔法方法的情况下就会去查找`__getitem__()`方法
如果说没有实现`__contains__()`,但又使用了in和not in,namepython就会去查找`__iter__()`和`__next__()`魔法方法
```python
class C:
def __init__(self, data):
self.data = data
def __iter__(self):
print("Iter", end = ' -> ')
self.i = 0
return self
def __next__(self):
print("Next", end = ' -> ')
if self.i == len(self.data):
raise StopIteration
item = self.data
self.i += 1
return item
c = C()
3 in c
```
只要return和要找的值一样就结束了
如果没有`__iter__()`和`__next__()`,会去找`__getitem__()`的魔法方法
```python
class C:
def __init__(self, data):
self.data = data
def __getitem__(self, index):
print("Getitem", end = ' -> ')
return self.data
c = C()
3 in c
Getitem -> Getitem -> Getitem -> True
6 in c
Getitem -> Getitem -> Getitem -> Getitem -> Getitem -> Getitem -> False
```
## __bool\_\_()
```python
class D:
def __bool__(self):
print("Bool")
return True
d = D()
bool(d)
Bool
True
```
代偿,如果没有定义`__bool__()`魔法方法,那么Python就会去找找是否存在`__len__()`这个魔法方法,返回值非零则是True
```python
class D:
def __init__(self, data):
self.data = data
def __len__(self):
print("Len")
return len(self.data)
d =D("Solo")
bool(d)
Len
True
bool(d)
Len
False
```
## 比较运算
1. < `__lt__(self, other)`
2. <= `__le__(self, other)`
3. \> `__gt__(self, other)`
4. \>= `__ge__(self, other)`
5. ==`__eq__(self, other)`
6. != `__ne__(self, other)`
字符串默认比较编码值大小,修改为比较长度
```python
class S(str):
def __lt__(self, other):
return len(self) < len(other)
def __gt__(self, other):
return len(self) > len(other)
def __eq__(self, other):
return len(self) == len(other)
__le__ = None
__ge__ = None
s1 = S("Solo")
s2 = S("solo")
s1 < s2
False
s1 > s2
False
s1 == s2
True
s1 != s2 ##没有定义!=方法
True
s1 <= s2
Traceback (most recent call last):
File "<pyshell#235>", line 1, in <module>
s1 <= s2
TypeError: 'NoneType' object is not callable
```
def __contains__(self, name):
for student in self.students.values():
if student.name == name:
return student
这里返回student,是不是相当于触发之后,要进行布尔运算,得出布尔值?
页:
[1]