Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Wingardium Leviosa

Sponsored · Ship Features Fearlessly Turn features on and off without deploys. Used by thousands of Ruby developers.

Wingardium Leviosa

Python declarative magic basics

Avatar for Serge Matveenko

Serge Matveenko

April 25, 2014
Tweet

More Decks by Serge Matveenko

Other Decks in Programming

Transcript

  1. ➢ Описания: существительные и прилагательные, а не глаголы ➢ Независимость

    от реализации ➢ Валидация без компиляции ➢ Не нужно уметь программировать ➢ GUI для редактирования ➢ Потому что это модно :) Декларативное программирование
  2. ➢ Декораторы ➢ Метаклассы ◦ Атрибуты классов ◦ Аргументы классов

    ◦ Аннотации аргументов методов ➢ Import hooks ◦ Модификация AST ◦ Генерация кода ➢ Внешние описания ◦ YAML Декларативность в Python
  3. Декораторы @this_is_decorator(safe_mode=True) def method(arg1, arg2): # we will have just

    a few lines here return arg1 + arg2 @abstractclass class ObjectBase: def foo(self): return NotImplemented
  4. Метаклассы: атрибуты классов class ObjectMeta(type): def __new__(cls, name, bases, attrs):

    type_new = type.__new__(cls, name, bases, attrs) if attrs.get('sequence', False): # add sequence realization if attrs.get('sorted', False): # add sorted realization return type_new class ObjectBase(metaclass=ObjectMeta): pass class MyClass(ObjectBase): sequence = True sorted = False
  5. Метаклассы: аргументы классов class SequenceMeta(type): def __new__(cls, name, bases, attrs,

    sorted=False): type_new = type.__new__(cls, name, bases, attrs) if sorted: # add sorted realization return type_new class SortedSequence(metaclass=SequenceMeta, sorted=True): pass seq = SortedSequence()
  6. Метаклассы: аннотации import inspect class StrictMeta(type): def __new__(cls, name, bases,

    args): type_new = type.__new__(cls, name, bases, args) for attr_name in dir(type_new): method = getattr(type_new.attr_name) if callable(method): parameters = inspect.signature(method).parameters.values() # construct decorated method setattr(new_type, attr_name, method) return new_type class TextNumber(metaclass=StrictMeta): value = "0" def __add__(self, value: r'[\d\.]+'): # add implementation return self.value
  7. Import hooks: модификация AST # smart_sql.py class MyImporter: def load_module(self,

    name): # modify AST return module sys.path_hooks.insert(0, MyImporter) # prog.py import smart_sql query = ( id, Point(x, y) for id, x, y in "sql_table_name" if len([(x0, y0), (x, y)]) < 3)
  8. Import hooks: генерация кода # smart_sql.py class MyImporter: def find_module(self,

    fullname, path=None): # find path to DSL source file self.path = path return self def load_module(self, name): # generate and compile python module from DSL return module sys.meta_path.insert(0, MyImporter) # prog.py import smart_sql from dsl_queries import query result = query.find(radius)
  9. YAML # pytest-yamlwsgi test_index: - path: / assert_status: 200 assert_contains:

    Hello - path: / assert_contains: Hello - path: / assert_status: 200
  10. Django ORM from django.db import models class Musician(models.Model): first_name =

    models.CharField(max_length=50) last_name = models.CharField(max_length=50) instrument = models.CharField(max_length=100) class Album(models.Model): artist = models.ForeignKey(Musician) name = models.CharField(max_length=100) release_date = models.DateField() num_stars = models.IntegerField()
  11. Django class-based generic views class PublisherDetail(DetailView): context_object_name = 'publisher' queryset

    = Publisher.objects.all() class BookList(ListView): queryset = Book.objects.order_by('-publication_date') context_object_name = 'book_list' class AcmeBookList(ListView): context_object_name = 'book_list' queryset = Book.objects.filter(publisher__name='Acme') template_name = 'books/acme_list.html'
  12. Function annotations # http://code.activestate.com/recipes/578528/ @typecheck def happy1(a:int, b:list, c:tuple=(1,2,3)) ->

    float: return 3.14 @typecheck def happy_wo_annotation(a:int, b, c:tuple=(1,2,3)) -> float: return 3.14 @typecheck def unhappy1(a:int, b:str) -> float: return 314 # This can never succeed in return type