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

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

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

26 май 2014

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

__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__ е конструктора на всеки клас?

We lied!

__new__

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

type(KindaFaultyPair(1, 2)) # tuple

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

__new__ (2)

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

type(Pair(1, 2)) # Pair

Метакласове

type

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

We lied!

Забележка

В Пайтън 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

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

__slots__

Не съм сигурен, че искаме да ви говорим за това

Въпроси?