14. Метапрограмиране

14. Метапрограмиране

14. Метапрограмиране

11 май 2015

Преговор: атрибути

__dict__

__getattribute__

__getattr__

__setattr__

__delattr__

Преговор: атрибути (2)

dir

getattr

setattr

hasattr

delattr

Дескриптори: Теория

def __get__(self, instance, owner): ...
def __set__(self, instance, value): ...
def __delete__(self, instance): ...

Дескриптори: Практика

class B:
    def __get__(self, instance, owner):
        return "You came to the wrong neighborhood, motherflower!"

    def __set__(self, instance, value):
        print("What!? You think you can change my personality just like that!?")

    def __delete__(self, instance):
        print("Can't touch me!")

class A:
    foo = B()

a = A()
print(a.foo)
a.foo = 'bar'
del a.foo

Bound methods

>>> increment = (1).__add__
>>> map(increment, [0, 1, 2, 3])
[1, 2, 3, 4]

Bound methods: Проста имплементация!

class MyMethod:
    def __init__(self, func):
        self.func = func

    def __get__(self, instance, owner):
        if instance:
            return lambda: self.func(instance)
        else:
            return lambda explicit_instance: self.func(explicit_instance)

class Python:
    name = 'Monty'
    greet = MyMethod(lambda self: 'My name issss %s' % self.name)

Bound methods: Проста имплементация!

snake = Python()
snake.greet() # 'My name issss Monty'
snake.name = 'Nagini'
Python.greet() # TypeError: <lambda>() takes exactly 1 argument (0 given)
Python.greet(snake) # 'My name issss Nagini'

Още достъп до атрибути

Редът за обхождане на базови класове

class A(int): pass

class B: pass

class C(A, B, int): pass

C.__mro__
# <class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>,
# <class 'int'>, <class 'object'>

Всичко за достъп до атрибути

за пълната информация...

Кодът на object в Python 3.3.1

And now for something completely different

Как бихме могли да имплементираме клас Pair, наследник на tuple?

class FaultyPair(tuple):
    def __init__(self, a, b):
        self[0] = a
        self[1] = b

class FaultierPair(tuple):
    def __init__(self, a, b):
        self = (a, b)

В __init__ не можем да постигнем нищо

Конструктори

Помните ли как ви повторихме няколко пъти, че __init__ не е точно конструктора на всеки клас?

__new__

class LessFaultyPair(tuple):
    def __new__(klass, x, y):
         return (x, y)

type(LessFaultyPair(1, 2)) # tuple

Но ние не искахме точно това...

__new__ (2)

class Pair(tuple):
    def __new__(klass, x, y):
         return tuple.__new__(klass, (x, y))

type(Pair(1, 2)) # Pair

Мета класове

Shit just got real

Мета класове

type

Помните ли как ви казахме, че type може само да връща типа на обект?

We lied!

Забележка

В Python type значи няколко неща

Типът на типовете

Класовете са просто инстанции на type.

type(name, bases, dict)

Начини да направим клас

Foo = type('Foo', (A, B, C), {'x':1, 'y':2})

Долното е синтактична захар за горното...

class Foo(A, B, C):
    x = 1
    y = 2

Мета

class metacls(type):
     def __new__(mcs, name, bases, dict):
         dict['foo'] = 'metacls was here'
         return type.__new__(mcs, name, bases, dict)

Foo = metacls('Foo', (A, B, C), {'x':1, 'y':2})
type(Foo) # metacls

Мета със захар

class Foo(A, B, C, metaclass=metacls):
    x = 1
    y = 2

Един пример

class R(metaclass=ReverseNames):
    def forward(self):
        print('forward')

>>> r = R()
>>> r.forward()
AttributeError: 'R' object has no attribute 'forward'
>>> r.drawrof()
forward

dafuq!?

class ReverseNames(type):
   def __new__(klass, name, bases, _dict):
       reversed = [(k[::-1], v) for k, v in _dict.items()]
       return type.__new__(klass, name, bases, dict(reversed))

Tim Peters on metaclasses

[Metaclasses] are deeper magic than 99% of the users should ever worry about. If you wonder whether you need them, you don't (the people who actually need them know with certainty that they need them, and don't need an explanation about why).

— Tim Peters

Предефиниране на "десните" оператори

Bryan O'Sullivan on metaprogramming

Metaprogramming is the language feature that helps you write code that you won't be able to understand once the cocaine wears off.

— Bryan O'Sullivan (@bos31337) May 4, 2010

Въпроси?