python3中 operator模块用法介绍


官方 operator 模块

operator 模块提供了一套与Python的内置运算符对应的高效率函数 . 许多函数名与特殊方法名相同,只是没有双下划线。为了向后兼容性,也保留了许多包含双下划线的函数。函数包含的种类有:对象的比较运算、逻辑运算、数学运算以及序列运算。

这个模块提供了很多和Python 一样的操作符, 这里 只是封装一个函数 进行调用

举个例子

 import operator
 
 b = operator.add(3,5)
 print(b)  # 8 
 

概述

operator 模块 封装了很多操作相关的函数, 比如 加,减 乘除 ,比较运算 ,逻辑运算 ,矩阵相乘. 还有一些封装好的类, 用起来 效率 比较高效. 本文 根据个人的使用经验 简单介绍一下, 这些类的常用用法.

将运算符映射到函数

表显示抽象操作如何对应于Python语法中的操作符号以及operator模块中的函数。

操作句法功能
a + badd(a, b)
串联seq1 + seq2concat(seq1, seq2)
成员测试obj in seq包含(seq, obj)
a / btruediv(a, b)
整除a // bfloordiv(a, b)
按位与a & band_(a, b)
按位异或a ^ bxor(a, b)
按位取反〜 ainvert(a)
按位或a | bor_(a, b)
取幂a ** bpow(a, b)
身份运算a 是 bis_(a, b)
身份运算a 是 不是 bis_not(a, b)
索引分配obj [k] = vsetitem(obj, k, v)
索引删除del obj [k]delitem(obj, k)
索引取值obj[k]getitem(obj, k)
左移a blshift(a, b)
取模a % bmod(a, b)
a * bmul(a, b)
矩阵乘法a @ bmatmul(a, b)
取负- aneg(a)
逻辑非不是 anot_(a)
取正+ apos(a)
右移a >> brshift(a, b)
切片赋值seq [i:j] = 值setitem(seq, slice(i, j), values)
删除切片del seq [i:j]delitem(seq, slice(i, j))
切片seq[i:j]getitem(seq, slice(i, j))
取模(同%)s % objmod(s, obj)
a - bsub(a, b)
真相测试objtruth(obj)
小于a blt(a, b)
小于等于a ble(a, b)
等于a == beq(a, b)
不等于a != bne(a, b)
大于等于a > = bge(a, b)
大于a > bgt(a, b)

1基本方法 介绍

DESCRIPTION
    This module exports a set of functions implemented in C corresponding
    to the intrinsic operators of Python.  For example, operator.add(x, y)
    is equivalent to the expression x+y.  The function names are those
    used for special methods; variants without leading and trailing
    '__' are also provided for convenience.



1 比较运算符

>  >=   <   <=  !=   
对应函数的名称
gt  ge  lt   le  ne 



2 逻辑运算符

与(&&) ,(|) ,(!), 异或 (^)  , is  , is not ,truth 


对应函数的名称 
and_  , or_ ,  not_  ,  xor



3 一些数学运算符 和一些  按位 运算符  bitwise Operations

+ - * /  //(整除)   %(取余) mod ,   


matmul (矩阵相乘),   mul 



floordiv  
index 

mod


取绝对值 abs   ,  pos   , neg
 
inv   ~ 取反 
and_  按位与





4 一些操作 

contact     contains 

def concat(a, b):
    "Same as a + b, for a and b sequences."
    if not hasattr(a, '__getitem__'):
        msg = "'%s' object can't be concatenated" % type(a).__name__
        raise TypeError(msg)
    return a + b

def contains(a, b):
    "Same as b in a (note reversed operands)."
    return b in a

def countOf(a, b):
    "Return the number of times b occurs in a."
    count = 0
    for i in a:
        if i == b:
            count += 1
    return count

def delitem(a, b):
    "Same as del a[b]."
    del a[b]

def getitem(a, b):
    "Same as a[b]."
    return a[b]

def indexOf(a, b):
    "Return the first index of b in a."
    for i, j in enumerate(a):
        if j == b:
            return i
    else:
        raise ValueError('sequence.index(x): x not in sequence')

def setitem(a, b, c):
    "Same as a[b] = c."
    a[b] = c

def length_hint(obj, default=0):
    """
    Return an estimate of the number of items in obj.
    This is useful for presizing containers when building from an iterable.

    If the object supports len(), the result will be exact. Otherwise, it may
    over- or under-estimate by an arbitrary amount. The result will be an
    integer >= 0.
    """
    if not isinstance(default, int):
        msg = ("'%s' object cannot be interpreted as an integer" %
               type(default).__name__)
        raise TypeError(msg)

    try:
        return len(obj)
    except TypeError:
        pass

    try:
        hint = type(obj).__length_hint__
    except AttributeError:
        return default

    try:
        val = hint(obj)
    except TypeError:
        return default
    if val is NotImplemented:
        return default
    if not isinstance(val, int):
        msg = ('__length_hint__ must be integer, not %s' %
               type(val).__name__)
        raise TypeError(msg)
    if val < 0:
        msg = '__length_hint__() should return >= 0'
        raise ValueError(msg)
    return val



# In-place Operations *********************************************************
# 注意这些 并不能原地修改 值.,...  主要是Python ,函数 参数的传递方式, 
# 我感觉是值 copy 一份到 , 函数里面. 所以 值并没有变. 可以看看例子.


def iadd(a, b):
    "Same as a += b."
    a += b
    return a

def iand(a, b):
    "Same as a &= b."
    a &= b
    return a

def iconcat(a, b):
    "Same as a += b, for a and b sequences."
    if not hasattr(a, '__getitem__'):
        msg = "'%s' object can't be concatenated" % type(a).__name__
        raise TypeError(msg)
    a += b
    return a

def ifloordiv(a, b):
    "Same as a //= b."
    a //= b
    return a

def ilshift(a, b):
    "Same as a <<= b."
    a <<= b
    return a

def imod(a, b):
    "Same as a %= b."
    a %= b
    return a

def imul(a, b):
    "Same as a *= b."
    a *= b
    return a

def imatmul(a, b):
    "Same as a @= b."
    a @= b
    return a

def ior(a, b):
    "Same as a |= b."
    a |= b
    return a

def ipow(a, b):
    "Same as a **= b."
    a **=b
    return a

def irshift(a, b):
    "Same as a >>= b."
    a >>= b
    return a

def isub(a, b):
    "Same as a -= b."
    a -= b
    return a

def itruediv(a, b):
    "Same as a /= b."
    a /= b
    return a

def ixor(a, b):
    "Same as a ^= b."
    a ^= b
    return a

2 三个类介绍

operator 中 有三个类, attrgetter , itemgetter ,methocaller 这三个类.

2-1 attrgetter 介绍

通过 attrgetter 可以 获取 对象的属性, 然后进行 排序 操作 .

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
@User    : frank 
@Time    : 2019/7/29 22:53
@File    : custom_sort.py
@Email   : frank.chang@xinyongfei.cn

operator  中 可以使用  attrgetter 获取 对象的 属性

attrgetter('xxx')  来获取对象的属性 .

"""
from operator import attrgetter


class Student:
    pass

    def __init__(self, name, age, score):
        self.name = name
        self.age = age
        self.score = score

    def __str__(self):
        return '%s(name=%r,age=%r,score=%r)' % (self.__class__.__name__, self.name, self.age, self.score)

    __repr__ = __str__


if __name__ == '__main__':
    std1 = Student("A", 11, 23)
    std2 = Student("B", 13, 10)
    std3 = Student("C", 16, 15)
    std4 = Student("D", 34, 4)

    students = [std1, std2, std3, std4]

    # 按照分数 排序 , 升序
    print("按照分数 排序,升序:")
    students.sort(key=lambda student: student.score, reverse=False)
    print(students)

    # 按照 年龄排序 降序
    print("按照 年龄排序 降序:")
    print(sorted(students, key=attrgetter('age'), reverse=True))

    # 按照 分数 排序
    print("按照 分数 排序: ")
    print(sorted(students, key=attrgetter('score'), reverse=False))

结果如下:

按照分数 排序,升序
[Student(name='D',age=34,score=4), Student(name='B',age=13,score=10), Student(name='C',age=16,score=15), Student(name='A',age=11,score=23)]
按照 年龄排序 降序:
[Student(name='D',age=34,score=4), Student(name='C',age=16,score=15), Student(name='B',age=13,score=10), Student(name='A',age=11,score=23)]
按照 分数 排序: 
[Student(name='D',age=34,score=4), Student(name='B',age=13,score=10), Student(name='C',age=16,score=15), Student(name='A',age=11,score=23)]
from operator import attrgetter

class Point:

    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __str__(self):
        return 'Point({0},{1})'.format(self.x, self.y)


points = [Point(x, y) for x, y in zip([3, 2, 1, 0, 0.2], [0.1, -1, 5, 3, 1, 8])]

# 通过获取 points中 x 的值 进行排序. 
points = sorted(points, key=attrgetter('x'))

for p in points:
    print(p)
    
2-2 itemgetter 使用介绍

官方解释 :

Return a callable object that fetches item from its operand using the operand's __getitem__() method.

If multiple items are specified, returns a tuple of lookup values. For example:

After f = itemgetter(2), the call f(r) returns r[2].

After g = itemgetter(2, 5, 3), the call g(r) returns (r[2], r[5], r[3]).

这个 类会返回 一个 可调用对象 ,它会从 它的操作数里面取值,会调用 操作数的__getitem__() 方法 获取值.

如果 传入了多个 item , 那么 结果 就会返回一个元祖 .

返回使用操作数的__getitem__()方法从其操作数获取的可调用对象。如果指定了多个项,则返回查找值的元组。例如:

1 用来排序
from operator import itemgetter


def one_example():
  
    data = [
       # (name , age)
        ("frank", 10),
        ("frank1", 15),
        ("frank2", 19),
        ("frank3", 12),
        ("frank4", 17),
        ("frank5", 11),
        ("frank6", 18),

    ]

    data.sort(key=itemgetter(1), reverse=True)
    print(data)


[('frank2', 19), ('frank6', 18), ('frank4', 17), ('frank1', 15), ('frank3', 12), ('frank5', 11), ('frank', 10)]

2 通过 获取多个值

传入多个参数 可以获取多个值. 看下面的例子

itemgetter 里面 甚至 可以传入一个 slice 对象

>>> from operator import itemgetter
>>> itemgetter(1)('ABCDEFG')
'B'
>>> itemgetter(1, 3, 5)('ABCDEFG')
('B', 'D', 'F')
>>> itemgetter(slice(2, None))('ABCDEFG')
'CDEFG'

>>> inventory = [('apple', 3), ('banana', 2), ('pear', 5), ('orange', 1)]
>>> getcount = itemgetter(1)
>>> list(map(getcount, inventory))
[3, 2, 5, 1]

>>> getname = itemgetter(0)
>>> list(map(getname,inventory))
['apple', 'banana', 'pear', 'orange']

>>> sorted(inventory, key=getcount)
[('orange', 1), ('banana', 2), ('apple', 3), ('pear', 5)]

2-3 methodcaller 介绍
class methodcaller:
    """
    Return a callable object that calls the given method on its operand.
    After f = methodcaller('name'), the call f(r) returns r.name().
    After g = methodcaller('name', 'date', foo=1), the call g(r) returns
    r.name('date', foo=1).
    """
    __slots__ = ('_name', '_args', '_kwargs')

    def __init__(*args, **kwargs):
        if len(args) < 2:
            msg = "methodcaller needs at least one argument, the method name"
            raise TypeError(msg)
        self = args[0]
        self._name = args[1]
        if not isinstance(self._name, str):
            raise TypeError('method name must be a string')
        self._args = args[2:]
        self._kwargs = kwargs

    def __call__(self, obj):
        return getattr(obj, self._name)(*self._args, **self._kwargs)

    def __repr__(self):
        args = [repr(self._name)]
        args.extend(map(repr, self._args))
        args.extend('%s=%r' % (k, v) for k, v in self._kwargs.items())
        return '%s.%s(%s)' % (self.__class__.__module__,
                              self.__class__.__name__,
                              ', '.join(args))

    def __reduce__(self):
        if not self._kwargs:
            return self.__class__, (self._name,) + self._args
        else:
            from functools import partial
            return partial(self.__class__, self._name, **self._kwargs), self._args


举个例子

operator.methodcaller(name[, args…])

参考文档 cook_book_method_caller 链接

有以下场景 :

​ 你有一个字符串形式的方法名称,想通过它调用某个对象的对应方法。

import math
from operator import methodcaller


class Point:

    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __str__(self):
        return 'Point({0},{1})'.format(self.x, self.y)

    def distance(self, x, y):
        return math.hypot(self.x - x, self.y - y)


points = [Point(x, y) for x, y in zip([3, 2, 1, 0, 0.2], [0.1, -1, 5, 3, 1, 8])]


# 按离原点的距离排序 
points.sort(key=methodcaller('distance', 0, 0))

for p in points:
    print(p)
# operator.methodcaller() 创建一个可调用对象,并同时提供所有必要参数, 然后调用的时候只需要将实例对象传递给它即可,比如:  

import math
from operator import methodcaller

p = Point(3, 4)

methodcaller('distance', 0, 0)
operator.methodcaller('distance', 0, 0)
d= methodcaller('distance', 0, 0)
d
operator.methodcaller('distance', 0, 0)
d(p)
5.0

3 性能测试

测试 itemgetter , 和自己写 一个匿名函数之间排序 差异

时间的一个装饰器函数

from functools import wraps
import time 

now = time.time

def fn_timer(fn=None, *, prefix=""):
    """
    计算 fn 的运算时间

    :param fn: 函数
    :param prefix:
    :return:
    """
    if fn is None:
        return partial(fn_timer, prefix=prefix)

    @wraps(fn)
    def function_timer(*args, **kwargs):
        start = now()
        result = fn(*args, **kwargs)
        t = now() - start
        if t > 0.002:
            logger.info(f'{prefix}{fn.__name__} total running time {now() - start} seconds')
        return result

    return function_timer
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
@User    : frank 
@Time    : 2019/7/30 11:16
@File    : compare.py
@Email  : frank.chang@xinyongfei.cn
"""
import random
import operator

from collections import defaultdict
from util.tools import fn_timer
from config.APP import LOG_PATH
from util.log import configure_logging
configure_logging(LOG_PATH)


def create_mobile():
    prelist = ["130", "131", "132", "133", "134", "135", "136", "137", "138", "139",
               "147", "150", "151", "152", "153", "155", "156", "157", "158", "159",
               "186", "187", "188", "189"]

    mobile = random.choice(prelist) + "".join(random.choice("0123456789") for _ in range(8))
    return mobile


item = {
    "peer_number": "13121111111",
    "duration": 15,
    "details_id": "xxxxxxxxxxxxx",
    "dial_type": "DIALED",
    "fee": 0,
    "location": "上海",
    "time": "2011-11-14 12:27:07",
    "location_type": "国内被叫"
}

calls = []

for i in range(10_0000):
    copy = item.copy()

    copy['duration'] += random.randint(10, 60)
    copy['mobile'] = create_mobile()
    calls.append(copy)


# 记录手机号对应 通话时长
durations = defaultdict(int)


for call in calls:
    mobile = call.get('mobile', "")
    durations[mobile] = call.get('duration')

print(len(durations))


@fn_timer()
def sort_call(calls):
    # 按照duration 排序
    sorted_by_duration = sorted(calls, key=lambda e: e[1], reverse=True)
    ret = sorted_by_duration[0:20]
    return ret


@fn_timer()
def sort_call2(calls):
    duration = operator.itemgetter(1)
    # 按照duration 排序
    sorted_by_duration = sorted(calls, key=duration, reverse=True)
    ret = sorted_by_duration[0:20]
    return ret


if __name__ == '__main__':
    sort_call2(calls=durations)
    sort_call(calls= durations)
    pass

测试 排序花费的时间 .

数据量itemgetter 单位(s)匿名函数 单位(s)
1000000.019397020339965820.023350000381469727
5000000.102560043334960940.12110304832458496
100_00000.2324969768524170.25639915466308594

从测试的性能可以看出 , itemgetter 还是要比匿名函数的效率要高一些. 对于一百万的数据的排序, 两百多毫秒 也就完成了 . 所以还是 库函数 的效率比自己写的效率要 高一些 呀.

4 总结

本文总结 , 简单介绍了 operator 模块 的一些 函数的用法 ,以及类的用法. attrgetter , itemgetter , methodcaller 三个类 的基本使用 .

5 参考文档

官方文档 中文版 https://docs.python.org/zh-cn/3/library/operator.html

官方文档 https://docs.python.org/3/library/operator.html

python cookbook 中 methodcaller 的使用 https://python3-cookbook.readthedocs.io/zh_CN/latest/c08/p20_call_method_on_object_by_string_name.html

分享快乐,留住感动. '2019-08-02 22:39:58' --frank
在Python,`operator`是一个内置的标准库,它提供了一组用于操作符的函数。这些函数可以用于执行各种操作,如比较、逻辑运算等。 下面是一些常用的`operator`函数及其使用方法: - `operator.add(a, b)`:返回a和b的和。 - `operator.sub(a, b)`:返回a和b的差。 - `operator.mul(a, b)`:返回a和b的积。 - `operator.truediv(a, b)`:返回a和b的商。 - `operator.floordiv(a, b)`:返回a和b的整除结果。 - `operator.mod(a, b)`:返回a和b的模数。 - `operator.pow(a, b)`:返回a的b次幂。 - `operator.eq(a, b)`:返回a是否等于b。 - `operator.ne(a, b)`:返回a是否不等于b。 - `operator.lt(a, b)`:返回a是否小于b。 - `operator.le(a, b)`:返回a是否小于等于b。 - `operator.gt(a, b)`:返回a是否大于b。 - `operator.ge(a, b)`:返回a是否大于等于b。 - `operator.not_(a)`:返回a的否定值。 - `operator.and_(a, b)`:返回a和b的逻辑与值。 - `operator.or_(a, b)`:返回a和b的逻辑或值。 - `operator.xor(a, b)`:返回a和b的异或值。 - `operator.neg(a)`:返回a的负值。 - `operator.pos(a)`:返回a的正值。 - `operator.abs(a)`:返回a的绝对值。 除了上述函数外,`operator`模块还提供了一些用于操作序列类型的函数,例如`operator.itemgetter()`和`operator.attrgetter()`。这些函数可以用于对序列进行排序、过滤和映射等操作。 示例代码: ```python import operator a = 10 b = 5 # 加法操作 print(operator.add(a, b)) # 输出 15 # 减法操作 print(operator.sub(a, b)) # 输出 5 # 乘法操作 print(operator.mul(a, b)) # 输出 50 # 除法操作 print(operator.truediv(a, b)) # 输出 2.0 # 取整除法操作 print(operator.floordiv(a, b)) # 输出 2 # 取模操作 print(operator.mod(a, b)) # 输出 0 # 幂操作 print(operator.pow(a, b)) # 输出 100000 # 判断相等 print(operator.eq(a, b)) # 输出 False # 判断不相等 print(operator.ne(a, b)) # 输出 True # 判断小于 print(operator.lt(a, b)) # 输出 False # 判断小于等于 print(operator.le(a, b)) # 输出 False # 判断大于 print(operator.gt(a, b)) # 输出 True # 判断大于等于 print(operator.ge(a, b)) # 输出 True ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值