Արմատային խնդիրն այն է, որ __eq__
մեթոդը պետք է ընդունի ցանկացած օբյեկտ. my_object == 3
անելը օրինական է գործարկման ժամանակ և միշտ պետք է վերադարձնի False: Դուք կարող եք դա տեսնել ինքներդ՝ ստուգելով object
Tyshed-ում. __eq__
-ի ստորագրությունը տրվում է որպես def __eq__(self, o: object) -> bool: ...
Այսպիսով, այս աշխատանքը կատարելու համար __eq__
-ի իրականացման ճիշտ ձևը կլինի հետևյալը.
def __eq__(self, other: object) -> bool:
if not isinstance(other, Person):
# If we return NotImplemented, Python will automatically try
# running other.__eq__(self), in case 'other' knows what to do with
# Person objects.
return NotImplemented
return self.id == other.id
Եվ իրականում, եթե դուք թարմացնեք mypy-ի այն տարբերակը, որն օգտագործում եք, այն կտպագրի գրություն, որում խորհուրդ է տրվում ձեր ծածկագիրը ձևավորել այս կերպ:
Այնուամենայնիվ, այս մոտեցման խնդիրն այն է, որ mypy-ն այլևս չի բողոքի, եթե դուք ինչ-որ հիմար բան անեք, ինչպիսին Person() == 3
ն է: Տեխնիկապես, դա պետք է վերադարձնի bool, բայց պրագմատիկորեն, ձեր կոդը, հավանաբար, ունի սխալ, եթե դուք համեմատում եք անձի օբյեկտը int-ի հետ:
Բարեբախտաբար, mypy-ը վերջերս ձեռք բերեց մի գործառույթ, որը կարող է նշել այս տեսակի սխալները՝ --strict-equality
: Այժմ, երբ դուք գործարկում եք mypy-ն այդ դրոշակով, Person() == 3
-ը կատարելով mypy-ի ելքային սխալներ կստեղծվեն, ինչպիսիք են Non-overlapping equality check (left operand type: "Person", right operand type: "int")
, նույնիսկ եթե դուք սահմանեք __eq__
-ը վերը նկարագրված ձևով:
Նկատի ունեցեք, որ դուք պետք է օգտագործեք mypy-ի վերջին տարբերակը master-ից՝ այս դրոշն օգտագործելու համար մինչև mypy-ի հաջորդ տարբերակը (0.680) թողարկվի: Դա պետք է տեղի ունենա գրելու պահից մոտավորապես 2-ից 3 շաբաթվա ընթացքում:
Եթե __eq__
-ը վերը նկարագրված ձևով սահմանելը այն չէ, ինչ դուք կարող եք անել ինչ-ինչ պատճառով, ես անձամբ խորհուրդ կտայի ճնշել տիպի սխալը՝ Անձը Any
-ով փոխարինելու փոխարեն:
Այսպիսով, հիմնականում, արեք սա.
def __eq__(self, other: 'Person') -> bool: # type: ignore
return self.id == other.id
... միգուցե հակիրճ նշումի հետ մեկտեղ, թե ինչու եք ճնշում սխալը:
Այստեղ հիմնավորումն այն է, որ __eq__
-ի այս սահմանումը, խիստ ասած, անապահով է (այն խախտում է ինչ-որ բան, որը հայտնի է որպես Լիսկովի փոխարինման սկզբունք) -- և եթե դուք պետք է անապահով որևէ բան անեք, հավանաբար ավելի լավ է հստակորեն նշել, որ դուք ավելի շուտ տապալում է տիպային համակարգը, այլ ոչ թե թաքցնում այն՝ օգտագործելով Any-ը:
Եվ գոնե այս կերպ, դուք դեռ կարող եք Person() == 3
-ի նման արտահայտությունները դարձնել տիպային սխալ. Այդ պահին դուք կարող եք նաև օգտագործել object
-ը և կառուցեք ձեր կոդը ճիշտ վարվելու համար:
21.02.2019