import os


class Dog(object):
    def __init__(self):
        self.name = "Dog"

    def bark(self):
        return "woof!"


class Cat(object):
    def __init__(self):
        self.name = "Cat"

    def meow(self):
        return "meow!"


class Human(object):
    def __init__(self):
        self.name = "Human"

    def speak(self):
        return "'hello'"


class Car(object):
    def __init__(self):
        self.name = "Car"

    def make_noise(self, octane_level):
        return "vroom%s" % ("!" * octane_level)

"""
Explanation: 适配器模式(Adapter pattern)是一种结构型设计模式，帮助我们实现两个不兼容接口之间的兼容。
首先，解释一下不兼容接口的真正含义。如果我们希望把一个老组件用于一个新系统中，或者把一个新组件用于一个老系统中，不对代码进行任何修改两者就能够通信的情况很少见。但又并非总是能修改代码，或因为我们无法访问这些代码(例如，组件以外部库的方式提供)，或因为修改代码本身就不切实际。在这些情况下，我们可以编写一个额外的代码层，该代码层包含让两个接口之间能够通信需要进行的所有修改。这个代码层就叫适配器。
现在有四个类：
End of explanation
"""


class Adapter(object):
    """
    Adapts an object by replacing methods.
    Usage:
    dog = Dog
    dog = Adapter(dog, dict(make_noise=dog.bark))
    """
    def __init__(self, obj, adapted_methods):
        """We set the adapted methods in the object's dict"""
        self.obj = obj
        self.__dict__.update(adapted_methods)

    def __getattr__(self, attr):
        """All non-adapted calls are passed to the object"""
        return getattr(self.obj, attr)


def main():
    objects = []
    dog = Dog()
    objects.append(Adapter(dog, dict(make_noise=dog.bark)))
    cat = Cat()
    objects.append(Adapter(cat, dict(make_noise=cat.meow)))
    human = Human()
    objects.append(Adapter(human, dict(make_noise=human.speak)))
    car = Car()
    car_noise = lambda: car.make_noise(3)
    objects.append(Adapter(car, dict(make_noise=car_noise)))

    for obj in objects:
        print("A", obj.name, "goes", obj.make_noise())


if __name__ == "__main__":
    main()

"""
Explanation: 可能小伙伴们会觉得设计模式这块的东西略微有些复杂，完全不用感到灰心，如果不是想要将软件开发作为自己的职业的话，可能一辈子也不需要了解，或者不经意间用到也不知道。但是这部分内容可以用来复习类的概念知识。
这四个类的的接口各不一样，现在需要实现一个适配器，将这些不同类的接口统一起来：
End of explanation
"""


def add(x, y):
    print('add')
    return x + y

def sub(x, y):
    print('sub')
    return x - y

def mul(x, y):
    print('mul')
    return x * y

def div(x, y):
    print('div')
    return x / y

"""
Explanation: 回顾一下所掌握的装饰器的知识，现在有以下函数
End of explanation
"""


from functools import wraps
def debug(func):
    msg = func.__qualname__
    @wraps(func)
    def wrapper(*args, **kwargs):
        print(msg)
        return func(*args, **kwargs)
    return wrapper

@debug
def add(x, y):
    return x + y
@debug
def sub(x, y):
    return x - y
@debug
def mul(x, y):
    return x * y
@debug
def div(x, y):
    return x / y

add(3,4)

"""
Explanation: 每次函数都要输出一个print语句告知用户当前在哪个函数中，这样的操作实在是太麻烦，可否实现一个装饰器，自动输出当前所在的函数名称？
End of explanation
"""


from functools import wraps
def debug(prefix = ''):
    def decorate(func):
        msg = prefix + func.__qualname__
        @wraps(func)
        def wrapper(*args, **kwargs):
            print(msg)
            return func(*args, **kwargs)
        return wrapper
    return decorate

@debug(prefix='++++++')
def add(x, y):
    return x + y
@debug(prefix='------')
def sub(x, y):
    return x - y
@debug(prefix='******')
def mul(x, y):
    return x * y
@debug(prefix='//////')
def div(x, y):
    return x / y

add(3,4)

sub(3,2)

"""
Explanation: 现在想要对于上面的装饰器做一下功能增强，把一些必要的参数传递给装饰器函数，以增加装饰器函数的灵活性，比如说，对于加法函数，可以传入'+++++'作为参数传入，相应的减法函数传入‘----’，乘法函数传入‘****’，除法函数传入'/////'。
End of explanation
"""


import os
import sqlite3

db_filename = 'todo.db'
schema_filename = 'todo_schema.sql'

db_is_new = not os.path.exists(db_filename)

with sqlite3.connect(db_filename) as conn:
    if db_is_new:
        print('Creating schema')
        with open(schema_filename, 'rt') as f:
            schema = f.read()
        conn.executescript(schema)

        print('Inserting initial data')

        conn.executescript("""
        insert into project (name, description, deadline)
        values ('pymotw', 'Python Module of the Week',
                '2016-11-01');

        insert into task (details, status, deadline, project)
        values ('write about select', 'done', '2016-04-25',
                'pymotw');

        insert into task (details, status, deadline, project)
        values ('write about random', 'waiting', '2016-08-22',
                'pymotw');

        insert into task (details, status, deadline, project)
        values ('write about sqlite3', 'active', '2017-07-31',
                'pymotw');
        """)
    else:
        print('Database exists, assume schema does, too.')

下面请尝试检索上面所创建数据库中的全部数据：（使用fetchall）

import sqlite3

db_filename = 'todo.db'

with sqlite3.connect(db_filename) as conn:
    cursor = conn.cursor()

    cursor.execute("""
    select id, priority, details, status, deadline from task
    where project = 'pymotw'
    """)

    for row in cursor.fetchall():
        task_id, priority, details, status, deadline = row
        print('{:2d} [{:d}] {:<25} [{:<8}] ({})'.format(
            task_id, priority, details, status, deadline))

"""
Explanation: 装饰器的内容都是很套路的函数操作，一般情况下就是用于简化重复代码：即“don't repeat yourself‘， 不要写重复的代码。
SQLite作为一个常见的数据库，也是python的标准库，用途非常广泛，适用于数据量较小的规模，但是又必须使用数据库的场景，sqlite的连接和CRUD操作可以参考标准库的文档。
现在用以下方式创建两个表，然后往里插入一些数据：
-- todo_schema.sql
-- Schema for to-do application examples.
-- Projects are high-level activities made up of tasks
create table project (
    name        text primary key,
    description text,
    deadline    date
);
-- Tasks are steps that can be taken to complete a project
create table task (
    id           integer primary key autoincrement not null,
    priority     integer default 1,
    details      text,
    status       text,
    deadline     date,
    completed_on date,
    project      text not null references project(name)
);
注意，需要将以上sql代码放到一个名为'todo_schema.sql'的文件之中。
End of explanation
"""


