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

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

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

8 април 2013

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

__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)

__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.

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

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__

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

Въпроси?