Upload
felipe-volpone
View
195
Download
2
Embed Size (px)
Citation preview
metaprogramação em python:
metaclass e decorators
@felipevolponegithub.com/felipevolpone
facebook.com/felipevolponelinkedin
por que
metaprogramação?
aprender
por que
é poderoso
reutilizar código
aumentar abstração
criar APIs mais ricas
decoratorshttps://www.python.org/dev/peps/pep-0318/
python 2.4
o que é!
!
@staticmethod def say_hello(): return "Hello TDC :)" !
#flask @app.route('/') def hello_rest(): return "Hello TDC :)"
como funciona
def log(func): def internal(): return func() return internal !
@log def say_hello(): return "Hello TDC"
!
def log(func): … !
#@log def say_hello(): return "Hello TDC" !
say_hello = log(say_hello)
#@log def say_hello(): return "Hello TDC" !
say_hello = log(say_hello)
def log(func): def internal(): return func() return internal !
#@log def say_hello(): return "Hello TDC" !
say_hello = log(say_hello)
def log(func): def internal(): return func() return internal !
#@log def say_hello(): return "Hello TDC" !
say_hello = log(say_hello)
def log(func): def internal(): return func() return internal !
#@log def say_hello(): return "Hello TDC" !
say_hello = log(say_hello)
def log(func): def internal(): return func() return internal !
#@log def say_hello(): return "Hello TDC" !
say_hello = log(say_hello)
def log(func): def internal(): return func() return internal !
#@log def say_hello(): return "Hello TDC" !
say_hello = log(say_hello)
}
print say_hello <function say_hello at 0x105909c80> !
say_hello = log(say_hello) print say_hello <function internal at 0x105909cf8>
def log(func): def internal(): return func() return internal !
#@log def say_hello(): return "Hello TDC" !
say_hello = log(say_hello) print say_hello()
def log(func): def internal(): return func() return internal !
def say_hello(): return "Hello TDC" !
say_hello = log(say_hello) print say_hello() > "Hello TDC"
def log(func): def internal(): return func() return internal !
def say_hello(): return "Hello TDC" !
say_hello = log(say_hello) print say_hello() > "Hello TDC"
from datetime import datetime !def log(func): def internal(): now = datetime.now() \ .strftime(“%d/%m/%Y %H:%M:%S") print "Funcao chamada: %s as %s" % (func.func_name, now) return func() return internal !print say_hello() > "Funcao chamada: say_hello as 17/07/2015 16:45:36" > "Hello TDC"
def log(func): def internal(): now = … print "Funcao chamada ..." return func() return internal !@log def say_hello(message): return message @log def goodbye(): return “goodbye" !print goodbye() > Funcao chamada: goodbye as 17/07/2015 16:30:23 > goodbye print say_hello("#python no TDC") > TypeError: internal() takes no arguments (1 given)
!
def log(func): def internal(*args, **kwargs): now = … print "Funcao chamada: …" return func(*args, **kwargs) return internal
args é iterável kwargs é {}
def example(func): def internal(*args, **kwargs): return func(*args, **kwargs) return internal !
@example def sum_base(a, b, base=12): return a+b+base !
print sum_base(6, 10, base=12) > 28
combinando decorators
@timestamp @log def say_message(msg): return msg !
sum_func = timestamp(log(say_message))
[email protected]('/about') def about(): return 'The about page' [email protected]('Failing test') def test_example(self): self.assertEquals(1, 2) !
def authentication(msg): ! def decorator(func): def internal(*args, **kwargs): user = get_session_user() if user.valid: return func(*args, **kwargs) else: raise Exception(msg) return internal ! return decorator
@authentication("User is not valid") def say_hello(): return "Hello TDC" !say_hello = \ authentication(“User is not valid")(say_hello) !#quando usuario nao eh valido print say_hello() > raise Exception(msg) Exception: User is not valid
@json @flask.get('/products/') def get_products(): return {'products': get_products()} !@html def get_static_file(file_path): return open(file_path) !@auth('admin') def delete_user(): pass !@convert_object @flask.post('/user/<id>') def get_user(model_user) # transforma json em objeto python model_user.put()
cobre 90% dos casos
def example(func): def internal(*args, **kwargs): """Useless decorator""" return func(*args, **kwargs) return internal !@example def say_hello(): """A simple function that says hello TDC""" return "Hello TDC" !print say_hello.func_name print say_hello.func_doc > "internal" > "Useless decorator"
def example(func): def internal(*args, **kwargs): "Useless decorator" return func(*args, **kwargs) internal.func_name = func.func_name internal.func_doc = func.func_doc return internal !@example def say_hello(): "Function that says hello TDC" return "Hello TDC" !print say_hello.func_name, say_hello.func_doc > “say_hello" "Function that says hello TDC"
import wrapt
http://pyvideo.org/video/2617/advanced-methods-for-creat
metaclasses
class User(object): pass !a = User() type(a) > __main__.User !type(User) > type !type(str) > type
isinstance(User, type) > True !isinstance(str, type) > True
metaclass class
class
class
User object type
metaclass class
subclass instance
str instance type
user
object
instance
"tdc2015"instance
__init__
__new__
instância
user = User()metac
lass
clas
s
1
2
4
__call____init__
1.1 1.2
class MyMetaclass(type): pass !class Person(object): __metaclass__ = MyMetaclass !print type(Person) > <class '__main__. MyMetaclass'>
exemplos
class Person(object): __metaclass__ = LogMetaclass ! def say_hello(self): return 'hello tdc'
import inspect, wrap !def log_decorator(func): @wrapt def inner(*args, **kwargs): print '[Logging] %s was called' % (func.func_name,) return func(*args, **kwargs) return inner !class LogMetaclass(type): ! def __init__(cls, *args, **kwargs): for prop in args[2]: #propriedades de person method = getattr(cls, prop) ! if inspect.ismethod(method): decorated_method = log_decorator(method) setattr(cls, prop, decorated_method) ! return type.__init__(cls, *args, **kwargs)
class Person(object): __metaclass__ = LogMetaclass ! def say_hello(self): return 'hello tdc' !u = Person() print u.say_hello() > "[Logging] say_hello was called" > “hello tdc"
import inspect !!class ModelBasicProtocol(type): ! def __new__(cls, name, parents, dct): ! if '__init__' in dct: init_function = dct['__init__'] init_inspection = inspect.getargspec(init_function) ! if init_inspection.defaults is None and len(init_inspection.args) > 1: raise Exception(‘The object must have a keywords arguments in __init__') ! return type.__new__(cls, name, parents, dct)
class TableProduct(object): __metaclass__ = ModelBasicProtocol ! def __init__(self, name): pass !e = TableProduct('Notebook') > Exception: A modelobject must have a keywords arguments in __init__
descriptors
https://speakerdeck.com/ramalho/python-encapsulation-with-descriptors-1
from google.appengine.ext import ndb !class Event(ndb.Model): name = ndb.StringProperty(required=True) description = ndb.TextProperty(required=True) logo = ndb.BlobKeyProperty(default=None) date = ndb.DateTimeProperty()
@felipevolpone