( 2020. november 18.)

Üdvözlet!, Ez a blog arról szól, hogyan lehet egy régi monolit projekt Python 3 migrációját leállás nélkül elvégezni. Ehhez 2 részünk van.
Első blog: Ez a blog arról tartalmaz információkat, hogy miért kell áttérnie a Python 3-ra, és ritka esetkülönbség van a Python 2-ben és a Python 3-ban, valamint Kompatibilis megoldások azok számára, .
(Második blog): Hogyan költözött a HealthifyMe a Python 3-ba anélkül, hogy a folyamatos fejlesztésnél leállást kellett volna tapasztalnia. >
Bevezetés
A Python az HealthifyMe elsődleges kódoló nyelve. Az összes új projekthez Python 3-at használunk, de a régi projektünk még mindig a Python 2.7 és a Django (1.11) verziókkal futott. Monolit projektünk 7 éves, több mint 2 millió soros python kóddal. Néhány ok, amiért átálltunk a Python 3-ra:
- A Python 2 támogatása elesett: 2020. január után a Python 2 támogatása nem biztosított.
- Python 3 elfogadása: As A legtöbb vállalatnál a nyílt forráskódú projekt már átveszi a Python 3-at. Új könyvtárakat, eszközöket, modulokat, keretrendszereket írnak a Python 3-ba.
A meglévő nyílt forráskódú projekt szintén átállt, és új funkciók, javítások, biztonsági fejlesztések jönnek a Python 3-ban. - Szoftverbiztonság: A szoftver biztonságának biztosítása törvényi követelmény, különösen, ha személyes adatokkal foglalkozik a GDPR területén. A szoftver naprakészen tartása érthető módon nagyon magas helyen szerepel a biztonsági legjobb gyakorlatok között, és egy elavult Python tolmács garantáltan garantálja vörös zászlóként jelenik meg a biztonsági ellenőrzés során. Az olyan biztonsági tesztelő eszközök, mint a Black Duck, számos sérülékenységről, kihasználásról és biztonsági problémáról számoltak be a Python 2-ben. A legtöbbet a legújabb Python 3 verziók (3.7.5, 3.8.0) javítják.
- Teljesítmény és új funkciók : A Python 3 jobban teljesít, mint a Python 2. A Python 3-at használó új szoftvertermék 12\% -os CPU-teljesítménynövelést és 30\% -os javulást jelentett a memóriaforrások használatában .
is, a Python 3 ad nekünk:
* natív aszinkron programozás.
* típusú kommentárok a statikus kódelemzés és az általános használhatóság javítására használhatók.
* láncolt kivételek , amelyek különösen hasznosak a hibakeresés során.
* egyéb hasznos funkciók , amelyek sokkal hatékonyabbá teszik a Python kódolását.
Ez a lista folytatódik, és biztosan bővülni fog minden új Python 3 kiadással.
Ez néhány ok arra, hogy áttérjünk a Python 3-ra. Körülbelül 12–15 fejlesztői háttércsoportunk van. Ez az alapprojektünk, napi 7–10 verziókkal, hibajavításokkal, fejlesztésekkel, biztonsági javításokkal, új funkciók fejlesztésével stb. A legfontosabb kihívás nem az volt, hogy megállítsuk a jelenlegi fejlesztési folyamatot. Meg kellett győződnünk arról, hogy projektünk kompatibilis-e a Python 3.X-szel, anélkül, hogy megszakítanánk a Python 2.X-vel való kompatibilitást. Az átállást 1 fejlesztő vezette (természetesen más fejlesztők segítségével).
Ebben a cikkben megpróbáljuk bemutatni az összes megtett lépést, a felmerült problémákat és még néhány részletet .
Különbség a Python 2 és a Python 3 között.
A közös különbséget itt találhatjuk meg:

https://docs.python.org/ 3 / whatsnew / 3.0.html
https://sebastianraschka.com/Articles/2014\_python\_2\_3\_key\_diff.html
https://jaxenter.com/differences-python-2-3-148432.html
https: // python-future.org/compatible\_idioms.html
Most röviden leírjuk azokat a ritka és éles eseteket, amelyeket amikor az áttérés megkezdődött.
Adattípus-összehasonlítás:
1. A Python 2-ben egy integer
és none
összehasonlítása működni fog, így az none
-et kevésbé tekintjük mint egész szám, akár negatív is.Ezenkívül összehasonlíthatja az none
és a string
, a string
és a int
.
A Python 3-ban nem engedélyezett a különböző adattípus-összehasonlítás.
Ezt a fejlesztő többsége ismeri, de olyan éles esettel szembesültünk, ahol NotImplementedType
-et a int
és ez nem fog működni a Python 3-ban.
Kódrészlet:
class Base(object):
PHONE\_NO\_SIZE\_LIMIT = NotImplementedbase = Base()
if base.PHONE\_NO\_SIZE\_LIMIT > 10:
print("Pass correct phone number")
else:
print("Valid phone number")
Ha ezt elmentjük a phone\_number\_validation.py
paranccsal, és futtassa a kódot:
# Python 2
[email protected] ~ \% python phone\_number\_validation.py
Pass correct phone number# Python 3
[email protected] ~ \% python3.7 phone\_number\_validation.py
Traceback (most recent call last):
File "phone\_number\_validation.py", line 4, in
if base.PHONE\_NO\_SIZE\_LIMIT > 10:
TypeError: ">" not supported between instances of "NotImplementedType" and "int"
Kompatibilis Megoldás:
Ellenőriznünk kell, hogy a base.PHONE\_NO\_SIZE\_LIMIT
megvalósításra került-e, ha nem, akkor azt kezelnünk kell. Tetszik:
if isinstance(base.PHONE\_NO\_SIZE\_LIMIT, type(NotImplemented)):
# Have logic here, also exit/return here.
print("Phone size is not implemented")if base.PHONE\_NO\_SIZE\_LIMIT > 10:
print("Pass correct phone number")
else:
print("Valid phone number")
2. Min., Max. Matematikai függvények:
Összehasonlítás a vidék int
munkájában none
, int
– str
, none
str
-re a Python 3-ban, így a min és Max matematikai függvény is megváltozott a Python 3-ban.
# Python 2
>>> max([1, None, 2])
2
>>> max([1, None, 2, "abc"])
"abc"
>>> min([1, None, 2, "abc"])
None # Python 3
>>> max([1, None, 2])
Traceback (most recent call last):
File "", line 1, in
TypeError: ">" not supported between instances of "NoneType" and "int" >>> max([1, 2, "abc", None])
Traceback (most recent call last):
File "", line 1, in TypeError: ">" not supported between instances of "str" and "int"
Kompatibilis megoldás:
1. A listának egy típusú adatokat kell tartalmaznia, vagy string
vagy int
2. Egy típussal, ha none
létezik, saját módszerünk lehet ennek kezelésére.
def py2max(input\_list):
"""Get the maximum item from list."""
if not input\_list:
raise ValueError("List should not be empty")
formated\_input\_list = [rec for rec in input\_list if rec is not None]
return max(formated\_input\_list) if formated\_input\_list else None
Hex kódolás / dekódolás
Míg egy sztringet kódolunk a Python 2-ben, ha ezt követjük
Ez nem fog működni a Python 3-ban
# ENCODING# Python 2
>>> "msg\_to\_be\_encoded".encode("hex")
"6d73675f746f5f62655f656e636f646564"# Python 3
>>> "msg\_to\_be\_encoded".encode("hex")
Traceback (most recent call last):
File "", line 1, in
LookupError: "hex" is not a text encoding; use codecs.encode() to handle arbitrary codecs# DECODING# Python 2
>>> "6d73675f746f5f62655f656e636f646564".decode("hex") "msg\_to\_be\_encoded"# Python 3
>>> b"6d73675f746f5f62655f656e636f646564".decode("hex")
Traceback (most recent call last):
File "", line 1, in
LookupError: "hex" is not a text encoding; use codecs.decode() to handle arbitrary codecs# Also look at exception here in python 2 and python 3.# Python 3>>> b"6d73675f746f5f62655f656e636f646564".decode("hex")
Traceback (most recent call last):
File "", line 1, in
LookupError: "hex" is not a text encoding; use codecs.decode() to handle arbitrary codecs# Python 2>>> "6d73675f746f5f62655f656e636f64656".decode("hex")
Traceback (most recent call last):
File "", line 1, in
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/encodings/hex\_codec.py", line 42, in hex\_decode
output = binascii.a2b\_hex(input)
TypeError: Odd-length string
Kompatibilis megoldás:
A codecs
-t kell használnunk a Python 3-hoz és 2-hez. A Python 3 bevitelében és kimenetében mindkettő byte
adattípus.
# Python 2
>>> import codecs
>>> message = "msg\_to\_be\_encoded"
>>> codecs.encode(message.encode(), "hex")
"6d73675f746f5f62655f656e636f646564"# Python 3
>>> message = "msg\_to\_be\_encoded"
>>> codecs.encode(message.encode(), "hex")
b"6d73675f746f5f62655f656e636f646564"
Karakterlánc nagybetűvel:
string.uppercase
nem működik a Python 3-ban.
# Python 2
>>> import string
>>> string.uppercase
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"# Python 3
>>> import string
>>> string.uppercase
Traceback (most recent call last):
File "", line 1, in
AttributeError: module "string" has no attribute "uppercase"
Kompatibilis megoldás:
Használja a ascii\_uppercase
# Python 2
>>> import string
>>> string.ascii\_uppercase
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"# Python 3
>>> import string
>>> string.ascii\_uppercase
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
hasattr ():
hasattr()
hatalmas éles esetet mutat be a Python 2 és 3 írásakor kompatibilis kód. hasattr()
ellenőrzi az attribútum meglétét azáltal, hogy megpróbálja lekérni.
Python 2
hasattr ( object , name )
Az argumentumok objektumok és karakterláncok. Az eredmény igaz, ha a karakterlánc az objektum egyik attribútumának neve, hamis, ha nem. (Ez úgy valósul meg, hogy meghívjuk a getattr-t (objektum, név), és megnézzük, kivált-e kivételt vagy sem.)
Python 3
hasattr ( objektum , név ) Az argumentumok egy objektum és egy karakterlánc. Az eredmény igaz, ha a karakterlánc az objektum egyik attribútumának neve, hamis, ha nem. (Ezt úgy hajtják végre, hogy meghívják a getattr-t (objektum, név), és megvizsgálják, hogy felvet-e egy AttributeError -et. További részletek itt találhatók: (https://medium.com/@k.wahome/python-2-vs-3-hasattr-behaviour-f1bed48b068)
Mintakód
class Foo(dict):
def \_\_init\_\_(self):
super(Foo, self).\_\_init\_\_()
self.example\_dict = {}
def \_\_getitem\_\_(self, key):
try:
return super(Foo, self).\_\_getitem\_\_(key)
except KeyError:
return self.example\_dict[key] def \_\_getattr\_\_(self, key):
return self[key]foo = Foo()
if hasattr(foo, "not\_present\_key"):
pass
else:
print("Not Found")Mentse a fenti részletet a következővel:
hasattr\_test.py
# Python 2[email protected] ~ \% python hasattr\_test.py
Not Found# Python 3[email protected] ~ \% python3.7 hasattr\_test.py
Traceback (most recent call last):
File "hasattr\_test.py", line 8, in \_\_getitem\_\_
return super(Foo, self).\_\_getitem\_\_(key)
KeyError: "not\_present\_key"During handling of the above exception, another exception occurred:Traceback (most recent call last):
File "hasattr\_test.py", line 17, in
if hasattr(foo, "not\_present\_key"):
File "hasattr\_test.py", line 13, in \_\_getattr\_\_
return self[key]
File "hasattr\_test.py", line 10, in \_\_getitem\_\_
return self.example\_dict[key]
KeyError: "not\_present\_key"Kompatibilis megoldás:
A Python 2 és Python 3 kódok kompatibilitásának biztosításához meg kell változtatnunk a\_\_getattr\_\_
függvényt, mint az alábbiakban.def \_\_getattr\_\_(self, key):
try:
return self[key]
except KeyError:
raise AttributeErrorA dict a Python 3 rendszerbe kerül:
A Python 3.6+ verziótól kezdve a szótár alapértelmezett beillesztés rendezve .
# Python 2
>>> sample\_dict = {}
>>> sample\_dict["a"] = 1
>>> sample\_dict["b"] = 2
>>> sample\_dict["c"] = 3
>>> sample\_dict["d"] = 4
>>> sample\_dict
{"a": 1, "c": 3, "b": 2, "d": 4}# Python 3
>>> sample\_dict = {}
>>> sample\_dict["a"] = 1
>>> sample\_dict["b"] = 2
>>> sample\_dict["c"] = 3
>>> sample\_dict["d"] = 4
>>> sample\_dict
{"a": 1, "b": 2, "c": 3, "d": 4}Kompatibilis kód:
Ideális esetben ez nem törheti meg az alkalmazás kódját, mert rendezetlenre változott rendezett dict-re. Ha mégis, mindkét python verzióban ugyanarra az eredményre van szükségünk (a sorrend fontos, a tesztesemény sikertelen), akkor aOrderedDict
-et kell használnunk, hogy mindkét nyelv kimenete azonos maradjon.Kivonatolás:
A Python 2-ben a bemenet beírható
unicode
ésstr
, de a Python 3-ban ehhezbytes
Kompatibilis megoldás:
A Python 3 bemenetként, ahol a python 2unicode
ésstr
típusokkal működik.# Python 2
>>> import hashlib
>>> message = "healthify"
>>> hashlib.sha512(message.encode("utf-8")).hexdigest().lower()
"f910c1fa68087a546512ac3b175c99ee7eba21360fa4e579c2aed649c7e4a43466c56bceedcd60d783bc6e7d069a16f0b9c67140d6c129d2a1898af8cfb62719"# Python 3
>>> message = "healthify"
>>> hashlib.sha512(message.encode("utf-8")).hexdigest().lower()
"f910c1fa68087a546512ac3b175c99ee7eba21360fa4e579c2aed649c7e4a43466c56bceedcd60d783bc6e7d069a16f0b9c67140d6c129d2a1898af8cfb62719"\_\_div\_\_ operátor túlterhelése:
A Python 3-ban a Úgy tűnik, hogy a \_\_div\_\_ operátor nem létezik, mivel teljesen \_\_truediv\_\_ váltotta fel.
class item:
fats = 0.0
def \_\_div\_\_(self, other):
self.fats = self.fats / otherit = item()
it.fats = 34.0
it / 3
print(it.fats)# python 2 output
11.3333333333# Python 3 output
Traceback (most recent call last):
File "div\_overloading.py", line 16, in
print(AB / 3)
TypeError: unsupported operand type(s) for /: "Vector2" and "int"Kompatibilis megoldás:
A Python 3.x-ben a\_\_truediv\_\_
operátorokat kell túlterhelnünk, nem pedig a\_\_div\_\_
operátor. A kód kompatibilitásának megőrzéséhez meg kell tartanunk mindkét módszert, például:class item:
fats = 0.0 def \_\_div\_\_(self, other):
self.fats = self.fats / other
def \_\_truediv\_\_(self, other):
self.fats = self.fats / otherit = item()
it.fats = 34.0
it / 3
print(it.fats)# python 2 output
11.3333333333# Python 3 output
11.333333333333334Base64 kódolás:
Az base64 kódolást a
base64.b64encode(
használatával végezzük. A Python 2-ben átadhatjuk a) unicode
vagy astr
bemenetként. De a 3-as pythonban abytes
-re van szüksége bemenetként.# Python 2
>>> from base64 import b64encode
>>> b64encode("man")
"bWFu"
>>> b64encode(u"man")
"bWFu"# Python 3
>>> from base64 import b64encode
>>> b64encode("man")
Traceback (most recent call last):
File "", line 1, in
File "/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.7/lib/python3.7/base64.py", line 58, in b64encode
encoded = binascii.b2a\_base64(s, newline=False)
TypeError: a bytes-like object is required, not "str"Kompatibilis megoldás:
Rendelkezhetünk saját módszerrel az base64 kódoláshoz, és lehet bemenetstring
ésbytes
mindkettő.import base64
import six
def base64ify(bytes\_or\_str):
if six.PY3 and isinstance(bytes\_or\_str, str):
input\_bytes = bytes\_or\_str.encode("utf8")
else:
input\_bytes = bytes\_or\_str
try:
output\_bytes = base64.b64encode(input\_bytes)
except (UnicodeEncodeError, TypeError):
# This happens when the input message has
# non-ascii encodable characters in an unicode string
# `"`(ascii encodable) vs `’`(non-ascii encodable)
# In this case, we first need to encode it to utf-8
# and then do the base64 encoding
output\_bytes = base64.b64encode(input\_bytes.encode("utf-8"))
if six.PY3:
return output\_bytes.decode("ascii")
else:
return output\_bytesBeépített kerek módszer:
Python2 : A kerekítés távolságtól (így például a (0.5) kör 1,0 és a kerek (-0,5) -1,0)
Python 3 : A kerekítés történik a páros választás felé (így például a kerek (0,5) és a kerek (-0,5) egyaránt 0, az (1,5) pedig 2).# Python 2
>>> round(15.5)
16.0
>>> round(16.5)
17.0# Python 3
>>> round(15.5)
16
>>> round(16.5)
16Kompatibilis megoldás:
Létrehoztuk az o saját kerek módszer, amely ugyanúgy működik, mint a Python 2 kör a python 3-ban is.def py2\_round(x, d=0):
"""Round same as PY2 in PY3."""
p = 10 ** d
if x >= 0:
return float(math.floor((x * p) + 0.5)) / p
else:
return float(math.ceil((x * p) - 0.5)) / pstruct. csomag bemeneti típusa:
a bemeneti típus
str
, a Python 3byte
# Python 2
>>> import struct
>>> import struct
>>> string = "blab"
>>> s = struct.Struct(b"4s")
>>> packed\_data = s.pack(string)# Python 3
>>> import struct
>>> string = "blab"
>>> s = struct.Struct(b"4s")
>>> packed\_data = s.pack(string)
Traceback (most recent call last):
File "", line 1, in
struct.error: argument for "s" must be a bytes objectKompatibilis megoldás:
encode
a bemenet .a szövegértési változó
scope
changes:A Python 3-ban a listamegértési változó a befogadó hatókört használja, azt jelenti, hogy nem fogja tudni elérni a tervváltozót a függvényen kívül, ez volt a Python 2 esetében nem.
# Python 2
>>> def two\_or\_three():
... x = 3
... [0 for x in range(3)]
... return x
...
>>> two\_or\_three()
2>>> def two\_or\_three\_with\_method():
... def print\_number():
... print(x)
... [0 for x in range(3)]
... print\_number()
...
>>> two\_or\_three\_with\_method()
2# Python 3
>>> def two\_or\_three():
... x = 3
... [0 for x in range(3)]
... return x
...
>>> two\_or\_three()
3>>> def two\_or\_three\_with\_method():
... def print\_number():
... print(x)
... [0 for x in range(3)]
... print\_number()
...
>>> two\_or\_three\_with\_method()
Traceback (most recent call last):
File "", line 1, in
File "", line 5, in two\_or\_three
File "", line 3, in print\_number
NameError: name "x" is not definedKompatibilis megoldás:
Kerülnünk kell az ilyen eseteket. A második módszerhez (two\_or\_three\_with\_method
) át kell adnunk az x értéket argumentumként.math.floor és a math.ceil visszatér adattípus megváltozott:
A 2-es pythonban a padló és a mennyezet float-adattípust ad vissza, a 3-as pythonban viszont visszaadja az int adattípust.
# Python 2
>>> from math import floor,ceil
>>> floor(4.345)
4.0
>>> ceil(4.345)
5.0# Python 3
>>> from math import floor,ceil
>>> floor(4.345)
4
>>> ceil(4.345)
5Kompatibilis megoldás:
Megtehetjük a kimenetet úszóként készítse el a Python 3-ban. Ez nem lesz hatással a Python 2-re,float(floor(4.345))
python 2 pácolt objektum a Python 3-ba:
Megemlítve, hogy a kódot kompatibilisvé tesszük mindkét python verzió futtatásához. problémával szembesültünk, miközben az objektumot a Python 2-ben pácoljuk, de a szedést a Python 3-ban nem tudjuk eltávolítani. Ez a Redis Pickled gyorsítótárazott objektumokra is megtörténhet.
pickle.load(),
alapértelmezés az, hogy megpróbálja az összes karakterláncot ASCII-ként dekódolni, és a dekódolás meghiúsul. Lásd apickle.load() dokumentációt :
Az opcionális kulcsszó argumentumok fix\_imports , kódolás és hibák , amelyek a Python 2 által generált savanyúság-adatfolyam kompatibilitási támogatásának szabályozására szolgálnak. Ha a fix\_import igaz, A pickle megpróbálja feltérképezni a régi Python 2 neveket a Python 3 új neveihez. 2; ezek alapértelmezés szerint „ASCII”, illetve „szigorú”. A kódolás lehet „bájt”, hogy ezeket a 8 bites karakterlánc-példányokat bájtobjektumként olvassa fel.
https : // stackoverflow.com / questions / 28218466 / python-2-object-with-python-3 eltávolítása
Kompatibilis megoldás:
Az alábbi módszerrel objektumokat válogathatunk ki.def unpickling\_py2\_to\_py3(pickled\_value):
"""Unpickling python 2 pickled in to python 3."""
if isPY3():
try:
value = pickle.loads(pickled\_value)
except UnicodeDecodeError:
value = pickle.loads(pickled\_value, encoding="latin1")
else:
value = pickle.loads(pickled\_value)
return valueHarmadik fél könyvtárának javításai:
Projektünkben sok harmadik fél csomagját használjuk, miközben frissítjük őket, néhány éles esetet szembesítettünk . Ezt kihagyhatja, ha egyiket sem használja.
- Django :
a. Django migrációs fájlok
Amikor a Djangomakemigrations
programot futtatjuk a 3-as pythonban, új migrációs fájlokat láttunk. de ugyanez nem történt meg a 2. python esetében. Ennek több oka lehet.b előtag: A makemigráció során az új fájlok nagy része úgy jön létre, hogy nincsenek
b prefix
karakterláncok. Ez azért van, mert a modelljeiben és mezőiben használt összes karakterlánc (pl. A “verbose\_name”, “related\_name” stb.) következetesen bájtos karakterláncokat vagy szöveges (unicode) karakterláncokat kell tartalmaznia mind a Python 2, mind a 3. verzióban.Kompatibilis megoldás: Egy migráció elérésének legegyszerűbb módja új áttelepítéshez adjon hozzá
from \_\_future\_\_ import unicode\_literal
minden modellfájlhoz. Meglévő áttelepítési fájlok esetén vagy futtatjuk amakemigration
fájlt, és ennek csak egyszer kell megtörténnie, vagy eltávolíthatjuk ab prefix
fájlt a meglévő áttelepítési fájlokból. >Választási mező: A modellekben a dict.items () elemet használjuk. Mint tudjuk, hogy a dict a Python 3-ban lesz rendezve , így a dict.items () értékéből visszatérő értékek különböznek Python 2 és Python 3.
Kompatibilis megoldás: Mindkettő kompatibilitása érdekében rendeztük (dict. items ()) és a létrehozott migrációs fájl, amely már kompatibilis mindkét python verzióval.
b. “
Object” megjelenítés az adminisztrációs konzolban A Felügyeleti konzol 3 python esetében a
Object mezőértékként láthatjuk a karakterlánc helyett. ha azért történt, mert modellosztályunknak módszere van. def \_\_unicode\_\_(self):
return "MyModel: {}".format(self.name)Rendelkezhetünk str\_ \_\_str\_\_ módszerrel, amely mindkét Python 2 és Python 3 esetén működik. De ez nem fog sikerülni, ha az str verzió nem ASCII karakterekkel rendelkezik.
Kompatibilis Megoldás: itt kapta meg a megoldást , hozzáadta a
@python\_2\_unicode\_compatible
dekoratort modellekhez és módosított\_\_unicode\_\_
értékre\_\_str\_\_
.c . Django lekérdezési objektum szeletelése
A Django lekérdezési objektum szeletelő képességgel rendelkezik rekordok lekérésére. a Django (1.11) verzióhoz, a python 2 támogatja az int és az str szeletelését. A Python 3-ban csak az int-en keresztüli szeletelést támogatja.# Python 2
>>> from food import models
>>> foods = models.foods.objects.all()
>>> foods[1:2] # int slicing]>
>>> foods["1":"2"] # string slicing]># Python 3
In [2]: from food import models
In [3]: foods = models.Foods.objects.all()
In [4]: foods["1":"2"]
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)in
----> 1 foods["1":"2"]~/Venvs/py3\_venv/lib/python3.7/site-packages/django/db/models/query.py in \_\_getitem\_\_(self, k)
265 raise TypeError
266 assert ((not isinstance(k, slice) and (k >= 0)) or
--> 267 (isinstance(k, slice) and (k.start is None or k.start >= 0) and
268 (k.stop is None or k.stop >= 0))), \
269 "Negative indexing is not supported."TypeError: ">=" not supported between instances of "str" and "int"In [5]: foods[1:2]
Out[5]:]> Kompatibilis megoldás: Kerülje a karakterláncok szeletelését, ami egyébként sem jó megközelítés.
2. Redis : A Redis gyakran használt python csomag. A redis-py 3.0 sok új funkciót vezet be, de a folyamat során több visszafelé nem kompatibilis módosítást igényelt.
Kompatibilis megoldás:
https://pypi.org/project/redis/ innen megtudhatjuk a változásokat és a kompatibilitás módját kód. Saját Redis módszereket készítettünk, amelyek kompatibilisek mindkét Redis verzióval. Tetszikimport six
def redis\_zadd(redis\_connection, key, **values):
"""Redis method zadd for python 2 and python 3 compatibility."""
if six.PY3:
redis\_connection.zadd(key, values)
else:
redis\_connection.zadd(key, **values)def redis\_zincrby(redis\_connection, key, value, score):
"""Redis method zincrby for python 2 and python 3 compatibility."""
if six.PY3:
redis\_connection.zincrby(key, score, value)
else:
redis\_connection.zincrby(key, value, score)3. django-cacheops : A Cacheops egy sima alkalmazás, amely támogatja az automatikus vagy kézi lekérdezési gyorsítótárat és az automatikus, eseményalapú érvénytelenítést. Van egy gotcha, míg a Django gyorsítótárak az Redis számára tárolják az értékeket, ezáltal egy savanyúsági objektum lesz.
A Python 2-ben 3 különböző protokoll van (0, 1, 2), és az alapértelmezett: 0. A Python 3-ban 5 különböző protokoll van (0, 1, 2, 3, 4), és az alapértelmezett érték 3. A Python 3, ha egy savanyúság-objektumot készítünk, és a szedést le akarjuk szedni a Python 2-ben, nem fog működni, mert a
3
savanyú protokoll nem érhető el a Python 2-ben. > Kompatibilis megoldás:
Megadhatjuk a protokoll paraméterét a pickle.dump meghívásakor.
django-cacheops nincs lehetőség a savanyúsági protokoll megadására. Majomfoltozást használtunk ennek rendezésére.import cacheops
from cacheops.cross import pickle@cacheops.redis.handle\_connection\_failure
def \_custom\_cacheops\_redis\_set(self, cache\_key, data, timeout=None):
pickled\_data = pickle.dumps(data, 2) # Protocol 2 is valid in both Python version.
if timeout is not None:
self.conn.setex(cache\_key, timeout, pickled\_data)
else:
self.conn.set(cache\_key, pickled\_data)cacheops.RedisCache.set = \_custom\_cacheops\_redis\_setA fentiekben említettük a python szedésének szétválasztását is pácolt objektum a Python 3-ba . Adatokat szeretnénk megszerezni a Python 3-ban, szembesülhetünk az UnicodeDecodeErrorral a különböző python verziókban végzett szedés miatt.
ezt a patcheléssel is rendezikimport six
from cacheops.simple import CacheMiss
if six.PY3:
import pickle
else:
import cPickle as pickledef unpickling\_py2\_to\_py3(pickled\_value):
"""Unpickling python 2 pickled in to python 3."""
if six.PY3:
try:
value = pickle.loads(pickled\_value)
except UnicodeDecodeError:
value = pickle.loads(pickled\_value, encoding="latin1")
else:
value = pickle.loads(pickled\_value)
return valuedef \_custom\_cacheops\_redis\_get(self, cache\_key):
data = self.conn.get(cache\_key)
if data is None:
raise CacheMiss
return unpickling\_py2\_to\_py3(data)cacheops.RedisCache.get = \_custom\_cacheops\_redis\_get4. django-redis-cache : van egy módszerünk kulcsok törléséhez a minta alapján. A Python 2-ben a
1.6.5 verziót használjuk, a kulcs keresése / törlése vizsgálat nélkül történt, de a Python 3 esetében a verziót
2.1 ahol a mintakeresés a Redis szkennelésével történik, ez olyan lassúvá teszi. Ez okozta a problémát. A Git hub problémája ehhez .
Kompatibilis megoldás:
A problémát a minta törlésének régi módszerével rendeztük. a (z)cache.delete\_pattern(pattern)
hívás helyettpattern = cache.make\_key(pattern)
keys = cache.master\_client.keys(pattern)
if len(keys):
cache.master\_client.delete(*keys)Mi következik
be (második rész) ), ennek a blognak , ahol azt vizsgáljuk meg, hogyan lehet a Python 3-ra lépni anélkül, hogy a folyamatos fejlesztéssel leállást kellene igénybe venni.