#TIL : Setter and getter behavior of class property in Python3

In previous TIL, I learned about the way to define getter and setter in Javascript

Today, I learned it in Pythonic way ;) (in Python3)

So here is example (the easy way to learn from a code) :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class A:
def __init__(self,x):
print ('init', x)
self.x = x

@property
def x(self):
print ('getter')
return self.__x

@x.setter
def x(self, x):
print ('setter', x)
if x < 0:
self.__x = 0
elif x % 2 == 0:
self.__x = x
else:
self.__x = x * 2

a = A(10)
print(a.x)
a.x = -1
print(a.x)
a.x = 2
print(a.x)
a.x = 7
print(a.x)

Output :

1
2
3
4
5
6
7
8
9
10
11
12
13
init 10
setter 10
getter
10
setter -1
getter
0
setter 2
getter
2
setter 7
getter
14

This is so cool feature, and even it has deleter property method, which triggers when we run del object.property :D

In reactive JS framework that they use getter and setter like a core of Reactive, let find out more next articles ;)

#TIL : Context Managers in Python

In Python, sometimes you will see this syntax

1
2
with something:
do_something_else(something)

Then you ask yourself, why I have to use this with syntax ? What runs inside that statement ?

Here is how it works, it’s called Context Managers in object

You can define context managers for a class of object to make sure some logic runs correctly without forgeting

Example :

1
2
3
4
5
6
7
8
9
10
11
12
13
class Animal:
def __init__(self, name):
self.name = name

def __enter__(self):
print("Enter the room !")

def __exit__(self, exc_type, exc_value, traceback):
print("Exit the room !")

kitty = Animal("Kitty Kat")
with kitty:
print(kitty.name)

Result

1
2
3
Enter the room !
Kitty Kat
Exit the room !

So, when you start using with keyword on a object, it runs __enter__ method, when everything inside with block is runned, __exit__ will be called !

It’s cool feature of Python !

#TIL : Do not use mutable objects as default parameters

I learned this from learn-python3

Example :

1
2
3
4
5
6
7
8
9
10
def append_if_multiple_of_five(number, magical_list=[]):
if number % 5 == 0:
magical_list.append(number)
return magical_list

print(append_if_multiple_of_five(100))
print(append_if_multiple_of_five(105))
print(append_if_multiple_of_five(123))
print(append_if_multiple_of_five(123, []))
print(append_if_multiple_of_five(123))

Result :

1
2
3
4
5
[100]
[100, 105]
[100, 105]
[]
[100, 105]

So default parameters in Python are shared between function calls if it isn’t passed from caller. So be careful because shared mutable object can affect your logic between function calls, where MAGIC was born !

One safe way to achieve the goal, use None as replacement like this

1
2
3
4
5
6
7
8
9
10
11
12
def append_if_multiple_of_five(number, magical_list=None):
if not magical_list:
magical_list = []
if number % 5 == 0:
magical_list.append(number)
return magical_list

print(append_if_multiple_of_five(100))
print(append_if_multiple_of_five(105))
print(append_if_multiple_of_five(123))
print(append_if_multiple_of_five(123, []))
print(append_if_multiple_of_five(123))

Result :

1
2
3
4
5
[100]
[105]
[]
[]
[]

#TIL : Exporting environment variables on virtual env activate

You can put common environment variables to the file venv/bin/activate. So everytime we active the virtual env, everything is on the way

1
2
3
4
5
6
7
# venv/bin/active content

# export your env vars here
export FLASK_APP=hello
export FLASK_ENV=development
export DATABASE=hello.sqlite3
export SECRET_KEY=secret_key_here

#TIL : HTTP2 supported for python requests library

The sophisticated http client in Python is requests, it has simple API but powerful features. You can use it for crawling, sending request to third-party API or writing tests.

Btw, at this moment it doesn’t support HTTP/2 protocol (actually we often doesn’t need its Server Push or Multi resource stream features). But sometime the API endpoint only supports HTTP/2 like Akamai Load Balacing service.

The hero is new library named hyper, it has been developing to support full HTTP/2 specs. But if all we need is requesting single request to a HTTP/2 server. It works like a charm.

Installation

1
2
$ pip install requests
$ pip install hyper

Usage

1
2
3
4
5
6
7
import requests
from hyper.contrib import HTTP20Adapter
s = requests.Session()
s.mount('https://', HTTP20Adapter())
r = s.get('https://cloudflare.com/')
print(r.status_code)
print(r.url)

This mean any url has prefix https:// will be hanlded by HTTP20Adaper of hyper library

Notice

If you run above example, you will see the result

1
2
200
https://cloudflare.com/

While you expected it would auto-follow redirect to the page https://www.cloudflare.com/

We can fix it by using the newer version than 0.7.0 to fix the header key bytestring issue

1
2
$ pip uninstall hyper
$ pip install https://github.com/Lukasa/hyper/archive/development.zip

Then try it out !!!

#TIL : Reference assign object variable

When you have a object x and assign y = x, y will be a ref of x (it looks like pointer of C). So changing property of y means changing property of x.

Ex :

1
2
3
4
x = {"a": 1, "b": 2}
y = x
y['a'] = 100
print x['a'] # Result is 100

So if you want clone the value, use copy lib :

1
2
3
4
5
import copy
x = {"a": 1, "b": 2}
y = copy.deepcopy(x)
y['a'] = 100
print x['a'] # Result is 1

#TIL : String Format Unicode params

1
2
unicode_thing = u"Xin chào mọi người"
a = '{}'.format(unicode_thing)

will cause the error UnicodeEncodeError: 'ascii' codec can't encode character u'\xe0' in position 6: ordinal not in range(128)

The solution is add u prefix the pattern (it means using unicode pattern) :

1
2
unicode_thing = u"Xin chào mọi người"
a = u'{}'.format(unicode_thing)