zoukankan      html  css  js  c++  java
  • Python 语言中 asterisk 符号用法小结

    对于 asterisk 符号的使用,本文分为预定义(predefined)和自定义(customized)两部分进行介绍。预定义部分,是指 Python 语言中已经预先定义好的部分,直接用就可以了;自定义,是指定制的,需要程序员自定义相应的功能。注意,这里讨论的 asterisk 符号的使用包括 * 符号和 ** 符号两种类型。

    一、预定义

    下面介绍 asterisk 符号在数值类型、非数值内置类型、函数定义和赋值中的用法。

    1. 数值类型中 asterisk 符号的用法

    在整型和浮点型等数值类型中,* 符号作为乘法运算符,** 符号作为乘方运算符。

    具体的示例程序,如下:

    x, y = 2, 4
    res1 = x * y  # 8
    res2 = x ** y  # 16
    res1 *= x  # 16
    res2 **= x  # 256

    2. 非数值内置类型中 asterisk 符号的用法

    所有的非数值内置类型都不支持 ** 符号;而对于 * 符号,只有 tuple 或 list 类型支持 * 符号操作符,而 set 或 dict 类型不支持,具体如下:

    元组(tuple)或列表(list)类型,* 符号可使非数值类型变量重复指定次数;

    而集合(set)和字典类型(dict)是不支持 * 符号操作符的,会抛出 "TypeError: unsupported operand type(s)" 异常。具体示例如下:

    # list examples
    print([] * 3) # []
    print(list() * 3) # []
    print([0] * 3) # [0, 0, 0]
    
    # tuple examples
    print(() * 3)  # ()
    print(tuple() * 3)  # ()
    print((0,) * 3)  # (0, 0, 0)
    
    # set examples, throw TypeError Exception
    try: 
        set() * 3
        set([]) * 3
        {0} * 3
    except TypeError as e:
        print(e)
    pass
    
    # dict examples, throw TypeError Exception
    try: 
        {} * 3
        dict() * 3
        {0: '0'} * 3
    except TypeError as e:
        print(e)
        pass   

    注意,(0,) 是元组类型,而(0)是整型,不是元组类型,区别只在于缺少了一个逗号(,)。

    3. asterisk 符号在函数定义中的用法

    在 Python 函数定义中,* 符号表示允许函数接受数量可变的参数(arguments);** 符号表示允许函数接受数量可变的关键字参数(keyword arguments)。具体示例如下:

    def func(*args, **kwargs):
        print('args:', args)
        print('kwargs:', kwargs)
        
    func((0,1,2), 3, 4, 5, key=0, value='0')  
    # args: ((0, 1, 2), 3, 4, 5)
    # kwargs: {'key': 0, 'value': '0'}

    注意,在 Python 函数定义中,带有 * 符号参数,必须在带有 ** 符号参数之前。

    在 Python 3 中,有一个新用法,称为 bare asterisk/star。即,在函数定义中,参数之间,有一个光秃秃的 * 符号。这种用法的含义是 bare star 的后面,只能接受关键字参数。更多解释参见 PEP 3102 -- Keyword-Only Arguments。具体示例如下:

    def compare1(x, y, *, key=None):
        print('x:', x)
        print('y:', y)
        print('key:', key)
        return x > y
    
    def compare2(x, y, *, z, key=None):
        print('x:', x)
        print('y:', y)
        print('key:', key)
        if z < 0: z *= -1
        return z if x > y else -1
    
    compare1(3, 5)
    compare2(3, 5, key=2, z=2)
    try:
        compare2(3, 5, 2)
    except TypeError as e:
        print(e)

    4. asterisk 符号在赋值中的用法

    在调用函数时,采用 * 符号可以拆解一些内置类型,使之变成一个个单独的元素再传入函数中。具体示例如下:

    def func(*args):
        print('args:', args)
    
    params = ['RGBA', (1,2,3), [1,2,3], {1,2,3}]
    
    # call function with arguments(* included)
    print("
    call function with arguments(* included)")
    for args in params:
        func(*args)
    
    # call function with arguments(* not included)
    print("
    call function with arguments(* not included)")
    for args in params:
        func(args)    

    在 Python 3 中,还可以把带有 * 符号的操作数(operand),或者说是变量,放到赋值符号的左侧,从而扩展了迭代器(iterator)的拆解赋值。具体示例如下:

    iterators = [(0,1,2,3,4), 'ABCDE', [0,1,2,3,4], {0,1,2,3,4}]
    for item in iterators:
        x, *y, z = item
        print('
    item:', item)
        print('x: %s, y: %s, z: %s' % (x,y,z))
        print('-' * 50)

    二、自定义

    对于自定义的类,可以通过定义相应的魔法方法(magic method),实现asterisk符号运算符(operator)。asterisk 符号相关的操作符与魔法方法的具体对应关系,如表1所示。

     

    表1. asterisk 符号操作符与 magic 方法对应关系表
    操作符 魔法方法 原始的表现形式 解释
    * __mul__(self, other) self * other 前向(forward)相乘方法
    * __rmul__(self, other) other * self 反转(reverse)相乘方法
    *= __imul__(self, other) self *= other 原地(in-place)相乘方法
    ** __pow__(self, other[, modulo]) self ** other 前向乘方方法
    ** __rpow__(self, other[, modulo]) other ** self 反转乘方方法
    **= __ipow__(self, other[, modulo]) self **= other 原地乘方方法

    注,反转相乘方法和反转乘方方法只有在self实例没有定义对应的前向方法时调用;modulo 为可选参数,表示对 modulo 参数取模。

    下面定义了一个 Length 类,实现将长度的单位都转换为米(meter)后,再进行相乘或乘方运算。具体示例代码,如下:

    class Length(object):
        __metric = {"mm": 0.001, "cm": 0.01, "m": 1, "km": 1000,
                    "in": 0.0254, "ft": 0.3048, "yd": 0.9144,
                    "mi": 1609.344}
        
        def __init__(self, value, unit="m"):
            self.value = value
            self.unit = unit
            
        def convert2meters(self):
            return self.value * Length.__metric[self.unit]
        
        def __str__(self):
            """Informal string representation for a user"""
            return str(self.convert2meters())
        
        def __repr__(self):
            """Official/Formal string representation for a programmer"""
            return "Length(" + str(self.value) + ", '" + self.unit + "')"
        
        def __add__(self, other):
            meters = self.convert2meters() + other.convert2meters()
            return Length(meters/Length.__metric[self.unit], self.unit)
        
        def __mul__(self, other):
            """Regard the other object as a multiplier upon self"""
            meters = self.convert2meters() * other.convert2meters()
            return Length(meters/Length.__metric[self.unit], self.unit)
     
        def  __imul__(self, other):
            """In-place multiplication"""
            meters = self.convert2meters() * other.convert2meters()
            self.value = meters/Length.__metric[self.unit]
            return self
        
        def __pow__(self, other):
            """Regard the other object as an exponent upon self"""
            meters = self.convert2meters() ** other.convert2meters()
            return Length(meters/Length.__metric[self.unit], self.unit)
        
        def __ipow__(self, other):
            """In-place power"""
            meters = self.convert2meters() ** other.convert2meters()
            self.value = meters/Length.__metric[self.unit]
            return self
     
           
    if __name__ == '__main__':
        x = Length(4)
        print(x)
        y = eval(repr(x))
    
        # Test * symbol operator
        z1 = Length(4.5, "yd") * Length(1)
        z1 *= x
        print(repr(z1))
        print(z1)
        # Test ** operator  
        z2 = y ** x
        z2 **= Length(1)
        print(repr(z2))
        print(z2)
    View Code

    参考资料

    [1] Numeric Type Special Methods in Chapter 24. Creating or Extending Data Types.

    https://www.linuxtopia.org/online_books/programming_books/python_programming/python_ch24s04.html

    [2] Magic Methods and Operator Overloading. https://www.python-course.eu/python3_magic_methods.php

  • 相关阅读:
    2020牛客暑期多校(三)
    贪心算法
    高级搜索题集
    状态压缩dp
    [kuangbin带你飞]专题二 搜索进阶
    [kuangbin带你飞]专题一 简单搜索
    HDU 1695 GCD(求两区间的互质数对+容斥原理)
    UVA 10200 Prime Time(简单素数判定预处理)
    HDU 1452 FZU 1053 Happy 2004(逆元函数+因子和函数+大指数取模化简公式)
    低三位的数是8的倍数就可以被8整除
  • 原文地址:https://www.cnblogs.com/klchang/p/13832435.html
Copyright © 2011-2022 走看看