Contenu connexe Similaire à 2018 PyCon Korea - Ring (20) 2018 PyCon Korea - Ring3. user item
.
user.get_items()
user.get_cached_items(storage) .
item . .
user.invalidate_items() user.delete_cached_items(storage)
.
Ring user.get_items.delete() .
23. •
“
. (... ...) .”
( ) -
24. •
“
. (... ...) .”
( ) -
26. # 60 * 15
# cache_page: Django HTTP decorator
27. # 60 * 15
PyCon Django , ?
# cache_page: Django HTTP decorator
28. # 60 * 15
PyCon Django , ?
..?
# cache_page: Django HTTP decorator
32. Ring
• Sub-function control
• Methods & descriptor support
• Key Consistency
• Backend: memcache, redis, diskcache, shelve, dict
• asyncio support
• Fully customizable
• Django integration
34. Sub-functions
•
from django…
import cache_page
@cache_page(60)
def view(request):
return ...
import ring
@ring.dict(
{}, expire=60)
def function(v):
return ...
Ring Django per-view cache
35. Sub-functions
•
• &
value = function(10) value = function(10)
import ring
@ring.dict({})
def function(v):
return ...
import functools
@functools.lru_cache()
def function(v)
return ...
Ring lru_cache
38. Sub-functions
• & • python-memcached
value = function(10)
value = function
.get_or_update(10)
key = create_key(10)
value = client.get(key)
if value is None:
value = function(10)
client.set(key)
40. Sub-functions
• &
•
•
•
•
• ...
value = function(10)
function.delete(10)
value = function.update(10)
value = function.execute(10)
value = function.get(10)
43. Sub-functions
• get_many
• set_many, update_many, get_or_update_many …
@ring.memcache(...)
def f(a, b):
...
# getting data for f(1, 2), f(1, 3), f(a=2, b=2)
data = f.get_many((1, 2), (1, 3), {'a': 2, 'b': 2})
# data sequence(list)
44. Sub-functions
• get_many
• set_many, update_many, get_or_update_many …
@ring.memcache(...)
def f(a, b):
return a * 100 + b
# getting data for f(1, 2), f(1, 3), f(a=2, b=2)
data = f.get_many((1, 2), (1, 3), {'a': 2, 'b': 2})
assert data == [102, 103, 202]
45. Sub-functions
• get_many
• execute_many, set_many, update_many, get_or_update_many …,
@ring.memcache(...)
def f(a, b):
return a * 100 + b
# getting data for f(1, 2), f(1, 3), f(a=2, b=2)
data = f.get_many((1, 2), (1, 3), {'a': 2, 'b': 2})
assert data == [102, 103, 202]
47. Ring
• Sub-function control
• Methods & descriptor support
• Key Consistency
• Backend: memcache, redis, diskcache, shelve, dict
• asyncio support
• Fully customizable
• Django integration
48. Methods & Descriptors
class UserAPI(object):
url_prefix = 'https://...'
secret_key = '...'
def __init__(self, user_id):
self.user_id = user_id
# cache?
@classmethod
def api_status(cls):
return request(
f'{cls.url_prefix}/status')
# cache?
def get_user(self, n):
return request(
f'{cls.url_prefix}/users/{n}')
49. Methods & Descriptors
• ?
• ( )
•
• In-house
class UserAPI(object):
url_prefix = 'https://...'
secret_key = '...'
def __init__(self, user_id):
self.user_id = user_id
# cache?
@classmethod
def api_status(cls):
return request(
f'{cls.url_prefix}/status')
# cache?
def get_user(self, n):
return request(
f'{cls.url_prefix}/users/{n}')
50. Methods & Descriptors
• Ring:
class UserAPI(object):
url_prefix = 'https://...'
secret_key = '...'
def __init__(self, user_id):
self.user_id = user_id
@ring.dict({}, expire=5)
@classmethod
def api_status(cls):
return request(
f'{cls.url_prefix}/status')
@ring.dict({}, expire=60)
def get_user(self, n):
return request(
f'{cls.url_prefix}/users/{n}')
51. Methods & Descriptors
• Ring:
• (free) function
• method
• classmethod
• staticmethod
• property
• custom descriptors
• hybridmethod?
hybridproperty?
• descriptor
class UserAPI(object):
url_prefix = 'https://...'
secret_key = '...'
def __init__(self, user_id):
self.user_id = user_id
@ring.dict({}, expire=5)
@classmethod
def api_status(cls):
return request(
f'{cls.url_prefix}/status')
@ring.dict({}, expire=60)
def get_user(self, n):
return request(
f'{cls.url_prefix}/users/{n}')
54. Ring
• Sub-function control
• Methods & descriptor support
• Key Consistency
• Backend: memcache, redis, diskcache, shelve, dict
• sync/asyncio support
• Fully customizable
• Django integration
56. Key consistency
•
• (expire, invalidate)
function(1)
function(v=1)
?
@functools.lru_cache(
maxsize=64)
def function(v):
return ...
57. Key consistency
•
• (expire, invalidate)
function(1)
function(v=1)@functools.lru_cache(
maxsize=64)
def function(v):
return ...
?
...
58. Key consistency
•
• (expire, invalidate)
function.delete(1)
function(v=1)@ring.dict({})
def function(v):
return ...
?
59. Key consistency
•
• (expire, invalidate)
function.delete(1)
function(v=1)@ring.dict({})
def function(v):
return ...
?
60. Key consistency
•
• (expire, invalidate)
>>> import sample
sample.f:1:2
sample.f:1:2
sample.f:1:2
import ring
@ring.dict({})
def f(a, *, b):
return ...
print(f.key(1, b=2))
print(f.key(a=1, b=2))
print(f.key(**{'a': 1, 'b': 2}))
61. Key consistency
•
• (expire, invalidate)
>>> import sample
sample.A.f:A():1
sample.A.g:A:2
sample.A.g:A:3
import ring
class A(object):
def __ring_key__(self):
return 'A()'
@ring.dict({})
def f(self, a):
pass
@ring.dict({})
@classmethod
def g(cls, a):
pass
a = A()
print(a.f.key(a=1))
print(a.g.key(a=2))
print(A.g.key(a=3))
63. Ring
• Sub-function control
• Methods & descriptor support
• Key Consistency
• Backend: memcache, redis, diskcache, shelve, dict
• asyncio support
• Fully customizable
• Django integration
66. Ring
• Sub-function control
• Methods & descriptor support
• Key Consistency
• Backend: memcache, redis, diskcache, shelve, dict
• asyncio support
• Fully customizable
• Django integration
69. Backends
• Q: ?
• A: 30
class MemcacheStorage(
fbase.CommonMixinStorage, fbase.StorageMixin, BulkStorageMixin):
def get_value(self, key):
value = self.backend.get(key)
if value is None:
raise fbase.NotFound
return value
def set_value(self, key, value, expire):
self.backend.set(key, value, expire)
def delete_value(self, key):
self.backend.delete(key)
def touch_value(self, key, expire):
self.backend.touch(key, expire)
def get_many_values(self, keys):
values = self.backend.get_multi(keys)
return [values.get(k, fbase.NotFound) for k in keys]
def set_many_values(self, keys, values, expire):
self.backend.set_multi({k: v for k, v in zip(keys, values)}, expire)
def delete_many_values(self, keys):
return self.backend.delete_multi(keys)
70. Ring
• Sub-function control
• Methods & descriptor support
• Key Consistency
• Backend: memcache, redis, diskcache, shelve, dict
• asyncio support
• Fully customizable
• Django integration
76. Data Encoder
dict(id=42, name='Name')
dict(id=42, name='Name')
@ring.dict({})
def user1(id):
return {
'id': id,
'name': 'Name'}
print(user1(42))
@ring.dict(
{}, coder='json')
def user2(id):
return {
'id': id,
'name': 'Name'}
print(user2(42))
77. Data Encoder
dict(id=42, name='Name')
# = json.dumps(user1(42))
b'{"id": id, "name": "Name"}'
d1 = {}
@ring.dict(d1)
def user1(id):
return {
'id': id,
'name': 'Name'}
print(d1[42])
d2 = {}
@ring.dict(d2, coder='json')
def user2(id):
return {
'id': id,
'name': 'Name'}
print(d2[42])
80. Data Encoder
# = json.dumps(user1(42))
'{"id": id, "name": "Name"}'
d1 = {}
@ring.dict(d1)
def user1(id):
return {
'id': id,
'name': 'Name'}
@user1.ring.encode
def user_encode(v):
return json.dumps(v)
@user1.ring.decode
def user_decode(v):
return json.loads(v)
print(d1[42])
case1: single function coder
81. Data Encoder
import json
import ring
ring.coder.register(
'json', (json.dumps, json.loads))
import pickle
import ring
ring.coder.register(
'pickle', (pickle.dumps, pickle.loads))
case2: reusable coder
93. inspect.signature
In [1]: def f(a, b, *args, x, y=10, **kw):
...: pass
...:
In [2]: import inspect
In [3]: s = inspect.signature(f)
Out[4]: <Signature (a, b, *args, x, y=10, **kw)>
In [6]: for name, parameter in s.parameters.items():
...: print(name, parameter.kind, parameter.default)
...:
a POSITIONAL_OR_KEYWORD <class 'inspect._empty'>
b POSITIONAL_OR_KEYWORD <class 'inspect._empty'>
args VAR_POSITIONAL <class 'inspect._empty'>
x KEYWORD_ONLY <class 'inspect._empty'>
y KEYWORD_ONLY 10
kw VAR_KEYWORD <class 'inspect._empty'>
94. qualname
• /
•
(py2 im_class !)
• Python 3.3+
>>> class C:
... def f(): pass
... class D:
... def g(): pass
...
>>> C.__qualname__
'C'
>>> C.f.__qualname__
'C.f'
>>> C.D.__qualname__
'C.D'
>>> C.D.g.__qualname__
'C.D.g'
95. annotation
• def f(a: int, b: int) -> int:
return a + b
print(f.__annotations__)
{'a': <class 'int'>, 'b': <class 'int'>, 'return': <class 'int'>}
• inspect.signature(f).return_annotation
int
• inspect.signature(f.get).return_annotation
Optional[int]
• inspect.signature(f.key).return_annotation
str
97. Methods & Descriptors
• Q: Ring method/descriptor ?
• A: https://github.com/youknowone/wirerope
• Rope:
(unbound Rope )
• Wire: (method),
(classmethod)
( bind Wire )
• hybridmethod, hybridproperty
98. Descriptor analysis
• :
• ?
• descriptor ?
• method property ?
• descriptor ?
(= method classmethod - hybrid )
• descriptor ?
• ?
99. Descriptor analysis
• :
• ?
• descriptor ?
• method property ?
• descriptor ?
(= method classmethod - hybrid )
• descriptor ?
• ?
2.7, 3.4-3.7 / PyPy2 PyPy3
def _f(owner):
return owner
100. Django app in single file
• Django ...
• ?
• 30 Django app
• https://github.com/youknowone/django-app-in-single-file