Áttérés Python 3-ra: Az HealthifyMe élmény.

( 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:

  1. A Python 2 támogatása elesett: 2020. január után a Python 2 támogatása nem biztosított.
  2. 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.
  3. 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.
  4. 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, intstr, 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 .encode(‘hex’) 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 AttributeError

A 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 a OrderedDict -et kell használnunk, hogy mindkét nyelv kimenete azonos maradjon.

Kivonatolás:

A Python 2-ben a bemenet beírható unicode és str, de a Python 3-ban ehhez bytes

Kompatibilis megoldás:
A Python 3 bemenetként, ahol a python 2 unicode és str 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.333333333333334

Base64 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 a str bemenetként. De a 3-as pythonban a bytes -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 bemenet string és bytes 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\_bytes

Beé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)
16

Kompatibilis 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)) / p

struct. csomag bemeneti típusa:

a bemeneti típus str, a Python 3 byte

# 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 object

Kompatibilis 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 defined

Kompatibilis 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)
5

Kompatibilis 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 a

pickle.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 value

Harmadik 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.

  1. Django :
    a. Django migrációs fájlok
    Amikor a Django makemigrations 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 a makemigration fájlt, és ennek csak egyszer kell megtörténnie, vagy eltávolíthatjuk a b 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. Tetszik

import 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\_set

A 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 rendezik

import 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\_get

4. 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 helyett

pattern = 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.

Vélemény, hozzászólás?

Az email címet nem tesszük közzé. A kötelező mezőket * karakterrel jelöltük