• 掌握这些知识,你的python水平能更上一层楼(续)


    笔者的上一篇python文章阅读量不错,看来python爱好者很多,所以再写一篇,以飨读者。

    先接着上一篇讲一个问题,下面这段code有没有问题?

    def countcalls(func):
        count = 0
        def wrapper(*args, **kwargs):
            count += 1
            print('num of calls: {}'.format(count))
            return func(*args, **kwargs)
        return wrapper
    
    @countcalls
    def foo(x):
        print (x+1)
    
    foo(1)

    运行时会发现:

    UnboundLocalError: local variable 'count' referenced before assignment

    原因是count在wrapper下面除非global,不然是不可见的,那么就没有初始化了。但是这是不能加global的,因为它不是global,如果移出函数外,那么结果又不对了。怎么解决呢?

    python3的解决方案:

    nonlocal count
    count += 1

    python2的解决方案:

    def countcalls(func):
        def wrapper(*args, **kwargs):
            wrapper.count += 1
            print('num of calls: {}'.format(wrapper.count))
            return func(*args, **kwargs)
        wrapper.count = 0
        return wrapper

    基于class的decorator

    class PrintLog:
        def __init__(self, func):
            self.func = func
        def __call__(self, *args, **kwargs):
            print ('CALLING: {}'.format(self.func.__name__))
            return self.func(*args, **kwargs)

    主要是__call__决定的,任何object只要定义了__call__方法就能当函数用。下面对比一下:

    class PrintLog:
        def __init__(self, func):
            self.func = func
        def __call__(self, *args, **kwargs):
            print ('CALLING: {}'.format(self.func.__name__))
            return self.func(*args, **kwargs)
    
    def printlog(func):
        def wrapper(*args, **kwargs):
            print("CALLING: " + func.__name__)
            return func(*args, **kwargs)
        return wrapper
    
    @printlog
    def f(n):
        return n+2
    
    @PrintLog
    def f_class(n):
        return n+2
    CALLING: f
    5
    CALLING: f_class
    5

    完全等效。__call__就相当于wrapper function

    magic methods

    相当于是python中的syntax sugar,让+,-,*,/啥的拿过来就用,举例如下:

    class Angle:
        def __init__(self, value):
            self.value = value % 360
        def __add__(self, other_angle):
            return Angle(self.value + other_angle.value)
    
    a = Angle(45)
    b = Angle(90)
    c = a + b
    print (c.value)
    135

    常用方法如下:

    数学运算
    __add__    a + b
    __sub__    a - b
    __mul__    a * b
    __truediv__    a/b(浮点除)
    __mod__    a % b
    __pow__    a ** b
    位运算
    __lshift__    a << b
    __rshift__    a >> b
    __and__    a & b
    __xor__    a ^ b
    __or__    a | b
    比较运算
    __eq__  a == b
    __ne__  a != b
    __lt__  a < b
    __le__  a <= b
    __gt__  a > b
    __ge__  a >= b

    举个例子:

    class Money(object):
        def __init__(self, dollar, cent):
            self.dollars = dollar
            self.cents = cent
        def __str__(self):
            return "$" + str(self.dollars) + "." + "{:02}".format(self.cents)
        def __repr__(self):
            return "Money(" + str(self.dollars) + ", " + str(self.cents) + ")"
        def __add__(self, other):
            cents = (self.cents + other.cents) % 100
            dollars = self.dollars + other.dollars + (self.cents + other.cents)/100
            return Money(dollars, cents)
        def __sub__(self, other):
            if self.cents < other.cents:
                cents = 100 + self.cents - other.cents
                dollars = self.dollars - other.dollars - 1
            else:
                cents = self.cents - other.cents
                dollars = self.dollars - other.dollars
            return Money(dollars, cents)
        def __mul__(self, other):
            cents = (self.cents * other) % 100
            dollars = self.dollars * other + (self.cents * other) / 100
            return Money(dollars, cents)
        def __eq__(self, other):
            return self.dollars == other.dollars and self.cents == other.cents
        def __ge__(self, other):
            return self.dollars >= other.dollars and self.cents >= other.cents
        def __lt__(self, other):
            return self.dollars < other.dollars and self.cents < other.dollars

    __str__和__repr__也是会时常用到的方法,它们都会放回string。__str__被用在print()时,同时str()也会调用它。而__repr__则是告诉你如何重现这个object,python命令行交互中输入object会调用__repr__,同时repr会调用它。

    python collection类型

    __getitem__相当于[index]

    据两个例子大家就明白了,第一个例子是关于list,第二个例子是针对dict

    class UniqueList:
        def __init__(self, items):
            self.items = []
            for item in items:
                self.append(item)
    
        def append(self, item):
            if item not in self.items:
                self.items.append(item)
    
        def __getitem__(self, index):
            return self.items[index]
    
    ul = UniqueList([2,2,2,3,3,3,4,4,4])
    
    print ul[0]
    print ul[1]
    print ul[2]
    2
    3
    4

    当然在具体实现的过程中对于index 要有input check,有问题需要raise IndexException,negative index要考虑语义的支持。

    class MultiDict:
        def __init__(self):
            self.data = {}
    
        def insert(self, key, value):
            if key not in self.data:
                self.data[key] = []
            self.data[key].append(value)
    
        def get_values(self, key):
            return self.data[key]
    
        def get(self, key):
            return self.get_values(key)[-1]
    
        def __getitem__(self, key):
            return self.get_values(key)[-1]
    
    md = MultiDict()
    md.insert("a", 1)
    md.insert("a", 2)
    print md['a']#2

    Iterator

    回到list那个例子,你觉得下面这个语法能够工作吗?

    for i in ul:
        print i

    答:可以的,通过__getitem__我们不小心实现了iterator,事实上只要__getitem__能够接受0,1,2,... 并且在访问越界的时候raise IndexException,就相当于实现了iterator

    Iterator的另一种实现是:

    def __iter__(self):
         return self
    
    def __next__(self):
         ...
             raise StopIteration
          return ...

    可见__getitem__显得更简洁。

  • 相关阅读:
    django路由层(一)
    计算机基础2
    Django模板语言
    Django框架介绍
    Python--格式化输出,运算符
    Python---基础
    Tensorflow--TensorflowBoard
    Tensorflow--图和会话
    Tensorflow--Tensor
    Tensorflow--基础结构
  • 原文地址:https://www.cnblogs.com/huashao1985/p/8629329.html
Copyright © 2020-2023  润新知