import sections


In [1]:
from functools import wraps
import logging as Log
from inspect import Signature, Parameter

Log.basicConfig(format='%(asctime)s %(message)s', level=Log.INFO)

__author__ = 'chois'

In [29]:
"""
Node 为迭代对象

"""

class Node:
    def __init__(self, value):
        self._value = value
        self._children = []

    def __repr__(self):
        return 'Node({!r})'.format(self._value)

    def add_child(self, node):
        self._children.append(node)

    def __iter__(self):
        return iter(self._children)

    def depth_first(self):
        return DepthFirstIterator(self)


class DepthFirstIterator(object):
    '''
    Depth-first traversal
    '''

    def __init__(self, start_node):
        self._node = start_node
        self._children_iter = None
        self._child_iter = None

    def __iter__(self):
        Log.info(f'iter:{self._children_iter}')
        return self

    def __next__(self):
#         Log.info(f'next---:{self._children_iter}')
        # Return myself if just started; create an iterator for children
        if self._children_iter is None:
            self._children_iter = iter(self._node)
            return self._node
        # If processing a child, return its next item
        elif self._child_iter is not None:
            try:
                nextchild = next(self._child_iter)
                return nextchild
            except StopIteration:
                self._child_iter = None
                return next(self)
        # Advance to the next child and start its iteration
        else:
            self._child_iter = next(self._children_iter).depth_first()
            return next(self)

In [30]:
root = Node(0)
child1 = Node(1)
child2 = Node(2)
root.add_child(child1)
root.add_child(child2)
child1.add_child(Node(3))
child1.add_child(Node(4))
child2.add_child(Node(5))
child2.add_child(Node(6))
child3.add_child(Node(7))
child3.add_child(Node(8))

In [31]:
for ch in root.depth_first():
    Log.info(ch)


2017-09-10 10:25:38,255 iter:None
2017-09-10 10:25:38,259 Node(0)
2017-09-10 10:25:38,267 Node(1)
2017-09-10 10:25:38,271 Node(3)
2017-09-10 10:25:38,275 Node(4)
2017-09-10 10:25:38,283 Node(2)
2017-09-10 10:25:38,287 Node(5)
2017-09-10 10:25:38,295 Node(6)

In [1]:
from functools import wraps

class Coordinate(object):
    def __init__(self, x, y):
        self.x = x
        self.y = y
    def __repr__(self):
        return  f'Coord: {self.__dict__}'

    
def check(func):
    # functools.wraps 修饰器将func的func.__name__, func.__doc__等属性
    #     添加到check属性中, 对_check函数的__name__, __doc__进行修饰
    @wraps(func)
    def _check(a, b):
        # 对下文func调用的参数做提前预修饰
        if a.x < 0 or a.y < 0:
            a = Coordinate(a.x if a.x>0 else 0, a.y if a.y > 0 else 0)
        if b.x < 0 or b.y < 0:
            b = Coordinate(b.x if b.x>0 else 0, b.y if b.y > 0 else 0)
        # func 的参数a, b 被上文修饰后传入func方法内部
        ret = func(a, b)
        #  判断输出结果的正负情况
        if ret.x < 0 or ret.y < 0:
            print('ret')
            return Coordinate(ret.x if ret.x >0 else 0, ret.y if ret.y >0 else 0)
        return ret
    return _check
# 等效于 a, b 参数同时传递给 _check(a, b) 和 func(a, b)
# check(func)
#  @check 修饰器运行路径: check -> _check(此处_check 方法完成对 func 函数参数修饰, 及调用) -> func -> add
# check ->{
#   def _check():
    
#   return  _check
# }-> add/sub
@check
def add(x, y):
    """add doc"""
    return Coordinate(x.x + y.x, x.y + y.y)
        
    
@check
def sub(x, y):
    """sub doc"""
    return Coordinate(x.x - y.x, x.y - y.y)

one = Coordinate(100, 200)
tow = Coordinate(200, 300)
three = Coordinate(100, -100)

In [3]:
coord = add(one, tow); coord
# print(add.__name__, add.__doc__)


Out[3]:
Coord: {'x': 300, 'y': 500}

In [15]:
coord1 = sub(tow, three); coord1


Out[15]:
Coord: {'x': 100, 'y': 300}

In [109]:
class Fib(object):
    def __init__(self, n):
        self.a = 0
        self.b = 1
        self.end = n
    
    def __iter__(self):
#         con = 0 
#         con += 1
#         Log.info('__iter__ at {!r}'.format(con))
        return self
    
    def __next__(self):
#         con = 0 
#         con += 1
#         Log.info('__next__ at {!r}'.format(con))
        self.a, self.b = self.b, self.a + self.b
        if self.a > self.end:
            raise StopIteration();
        else:
            return self.a
        
    def __repr__(self):
        return 'fib {!r}'.format(self.a)

fb = Fib(5)
# iter(fb)
# for _ in fb:
#     iter(fb)
# try:
for f in fb:
    Log.info(f)
# except StopIteration:
#     Log.info('end!')


2017-09-03 12:00:57,327 __iter__ at 1
2017-09-03 12:00:57,337 __next__ at 1
2017-09-03 12:00:57,345 1
2017-09-03 12:00:57,347 __next__ at 1
2017-09-03 12:00:57,359 1
2017-09-03 12:00:57,363 __next__ at 1
2017-09-03 12:00:57,371 2
2017-09-03 12:00:57,375 __next__ at 1
2017-09-03 12:00:57,383 3
2017-09-03 12:00:57,387 __next__ at 1
2017-09-03 12:00:57,403 5
2017-09-03 12:00:57,407 __next__ at 1

In [28]:
class CP(object):
    def __init__(self):
        self.x = 0
        pass

class C(CP):
        @property
        def xf(self):
            "I am the 'x' property."
            return self._x
        @x.setter
        def x(self, value):
            self._x = value
        @x.deleter
        def xf(self):
            del self._x
c= C()
# c.x = 2
# c.x
# c.x
# del c.x


---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-28-f2031abd2f2f> in <module>()
      4         pass
      5 
----> 6 class C(CP):
      7         @property
      8         def xf(self):

<ipython-input-28-f2031abd2f2f> in C()
      9             "I am the 'x' property."
     10             return self._x
---> 11         @x.setter
     12         def x(self, value):
     13             self._x = value

NameError: name 'x' is not defined

In [278]:
def f():
    try:
        yield 1
        try:
            yield 2
            1 / 0
            yield 3  # never get here
        except ZeroDivisionError:
            yield 4
            yield 5
            raise  # reactivate last activate except t0 yield 8
        except:
            yield 6
        yield 7  # the "raise" above stops this
    except:
        yield 8
    yield 9
#     ------------------------------------------
    try:
        x = 12
    finally:
        yield 10
    yield 11
Log.info(list(f()))


2017-09-03 23:11:29,319 [1, 2, 4, 5, 8, 9, 10, 11]

In [3]:
# A binary tree class.
class Tree:

    def __init__(self, label, left=None, right=None):
        self.label = label
        self.left = left
        self.right = right

    def __repr__(self, level=0, indent="    "):
        s = level*indent + f'{self.label}'
        if self.left:
            s = s + "\n" + self.left.__repr__(level+1, indent)
        if self.right:
            s = s + "\n" + self.right.__repr__(level+1, indent)
        return s

    def __iter__(self):
        return inorder(self)
    
# A recursive generator that generates Tree labels in in-order.
def inorder(t):
    if t:
        for x in inorder(t.left):
            yield x
        yield t.label
        for x in inorder(t.right):
            yield x


# Create a Tree from a list.
def tree(list):
    n = len(list)
    if n == 0:
        return []
    i = int(n / 2)
    return Tree(list[i], tree(list[:i]), tree(list[i+1:]))


# Show it off: create a tree
t = tree("1234567")
list(t)


Out[3]:
['1', '2', '3', '4', '5', '6', '7']

Binary Tree


In [33]:
class List(object):
    def __init__(self, center, left: list=None, right: list=None):
        self.center = center
        self.left = left
        self.right = right
    
    def __iter__(self):
        """iterator """
        return right_out(self)

def right_out(lst):
    """
    generator 
    """
#     二叉树算法
    if lst:
        
        for x in right_out(lst.right):  # 右子树遍历,直至[]返回
            yield x  # 不会返回x
        
        # 记录lst Node节点
        yield lst.center
        
        for x in right_out(lst.left):  # 左子树遍历,直至[]返回
            yield x  # 
            
            

def iter_tree(lst):
    """
    生成可以迭代对象的迭代器
    """
    n= len(lst)
    if n == 0:
        return []
    
    i = int(n/2)
#     Log.info('{}'.format(lst[i]))
#     List实例初始化
    return List(lst[i], iter_tree(lst[0:i]), iter_tree(lst[i+1:]))  # 返回迭代对象

l_t = iter_tree([1,2,3,4,5,6,7,8])
for x in l_t:
    Log.info(x)


2017-09-10 10:53:38,443 8
2017-09-10 10:53:38,451 7
2017-09-10 10:53:38,459 6
2017-09-10 10:53:38,471 5
2017-09-10 10:53:38,479 4
2017-09-10 10:53:38,483 3
2017-09-10 10:53:38,491 2
2017-09-10 10:53:38,495 1

decorator wrap


In [40]:
'''
本例验证函数与方法的区别
概要:
1.  函数(function)是Python中一个可调用对象(callable), 方法(method)是一种和self实例绑定的函数为方法
2.  一个可调用对象是方法和函数,和这个对象无关,判断条件:是否与类或实例绑定(bound method)
3.  实例方法,在类中未和类绑定,是函数。在实例中,此实例方法与实例绑定,即变成方法
4.  静态方法没有和任何类或实例绑定,所以静态方法是个函数
5.  装饰器不会改变被装饰函数或方法的类型
6.  类实现__call__方法,其实例也不会变成方法或函数,依旧是类的实例
7.  使用callalble() 只能判断对象是否可调用,不能判断是不是函数或方法
8.  判断对象是函数或方法应该使用type(obj)
'''

def class_method_decorator(func):
    """
    装饰器,测试使用,无功能
    :param func:
    :return:
    """
#     Log.info(msg=inspect.getfullargspec(func).args)
    if 'deg' in inspect.getfullargspec(func).args:
        Log.info(msg='deg')

    @wraps(func)
    def wrapper(*args, deg=False, **kwargs):
        
        if isinstance(args[0], TheClass):
            
            if 'sum_self' in kwargs.keys():
                Log.info(msg='func sum: {sum}'.format(sum=sum(kwargs['sum_self'])))
            if args[0].__dict__:
                Log.info(msg=f'self info: {args[0].__dict__}')
            if deg:
                Log.info(msg=f'debuging: {func.__name__}')
            return func(*args)
    sig = inspect.signature(func)
    params = list(sig.parameters.values())
    params.append(inspect.Parameter(
        'deg',
        inspect.Parameter.KEYWORD_ONLY,
        default=False
    ))
    wrapper.__signature__ = sig.replace(parameters=params)
    
    return wrapper


def the_function():
    """
    函数
    :return: 
    """
    pass


def the_function():
    """
    函数
    :return: 
    """
    pass


class TheClass:
    
    def __init__(self, a, b):
        self.a = a
        self.b = b
        self.lst = set()

    def __call__(self, *args, **kwargs):
        """"""
        for i in args:
            self.lst.add(i)
            
        return min(args)
    
    def __len__(self):
        return len(self.lst)

    @classmethod
    def class_method(cls):
        """
        类方法
        :return: 
        """
        pass

    def instance_method(self):
        """
        实例方法
        """
        return self

    @staticmethod
    def static_method():
        """
        静态方法
        :return: 
        """
        pass

    @class_method_decorator
    def decorated_func(self, *args):
        
        return (self.a + self.b) + sum(args)
    
the_class = TheClass(2, 3)

class_func = the_class.decorated_func(2, 4, deg=True, sum_self=[1, 2, 5, 1.666]) 
Log.info(msg=f'{type(the_class.decorated_func)}:{class_func}')
# Log.info('<info:{msg}> '.format(msg=the_class.decorated_func(deg=True)))


2017-09-10 11:00:35,637 func sum: 9.666
2017-09-10 11:00:35,637 self info: {'a': 2, 'b': 3, 'lst': set()}
2017-09-10 11:00:35,637 debuging: decorated_func
2017-09-10 11:00:35,637 <class 'method'>:11

In [39]:
Log.info(inspect.Signature(the_class.decorated_func))


---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-39-255f7b4f57be> in <module>()
----> 1 Log.info(inspect.Signature(the_class.decorated_func))

D:\Program Files\Python36\Lib\inspect.py in __init__(self, parameters, return_annotation, __validate_parameters__)
   2690                 kind_defaults = False
   2691 
-> 2692                 for idx, param in enumerate(parameters):
   2693                     kind = param.kind
   2694                     name = param.name

TypeError: 'method' object is not iterable