The prefix operator (*) asterisk in Python. Python中的星号操作符

发布时间 2023-12-17 03:54:47作者: Dennyyu

今天看Python 3 object-oriented programming一书中看到作者用了这样一个例子:

import math
class Point:
    def __init__(self,x,y):
        self.x = x
        self.y = y
    def distance(self,p2):
        return math.aqrt((self.x-p2.x)**2 + (self.y-p2.y)**2)

class Polygon:
    def __init__(self, points=None):
        points = points if points else []
        self.vertices = []
        for point in points:
            if isinstance(point, tuple):
                point = Point(*point) ## what is the asterisk * used for?
            self.vertices.append(point)

这里的(*)operrator 其实就只是解包的意思,因为前一步if判断point是否是tuple的实例, 此时用*解包传参至Point class的初始化函数.

Unpacking by asterisk *

这里复习一下解包(unpacking). 在一般的教程中,这样介绍unpacking

# 列表解包
a = [1,2,3,4]
b = [*a,5]
print(*b) # 输出1 2 3 4 5
# 字符解包
a = "Hello World"
print(*a.replace(" ",'')) #输出H e l l o W o r l d
# Tuple解包
a = (1,2,3,4)
print(*a) #输出1 2 3 4

那么不禁要问, 什么object可以用*解包? 测试*能用在哪些object上经常会被提示错误,'TypeError: Value after * must be an iterable, not type'; 所以只要是iterable应该就可以用* 来unpacking啦. 见下面的例子


class a:
    def __init__(self,number):
        self.number = number
    def __repr__(self) -> str:
        return str(self.number)

class A:
    def __init__(self,element_list):
        self.lenth = len(element_list)
        self.elements = element_list
    def __iter__(self):
        return iter(self.elements) # return the an interable

X1,X2,X3,X4,X5 = a(1),a(2),a(3),a(4),a(5)
X = A([X1,X2,X3,X4,X5])
print(*X) # output 1 2 3 4 5

实现了一个a类和一个A类, A包含了多个a类,封装在elements中.当运行到print(*X)时, 首先调用的X对象的__iter__()函数, 如果X不是iterable,则会立即报错.随后由于我们A class返回的是一个iter(element_list),作用相当于iter([1,2,3]),列表的__iter__, next 方法都是内置的.此时开始对列表进行迭代运行,print(X1)-->print(X2)...., print()函数会自动invoke class的__repr__方法. 因此最终看到输出结果 1 2 3 4 5

Passing arguments to function

此外,*的另一个作用是在定义一个函数时限定那些可以是位置参数,关键词参数. 与此相呼应的也 forword slash '/' 操作符, 具体作用如下:


def function(key1,key2,* or /, key3,key4):
    pass
左边 分割 右边
位置参数 / 位置参数或关键词参数
位置参数或关键参数 * 关键词参数

举个栗子

def function(key1,key2,*,key3,key4): # 定义时使用了*, 左边的传值可以是依靠位置传值或者关键字,但是左边的参数必须得用关键词传参
    print(f"key1 is {key1}")
    print(f"key2 is {key2}")
    print(f"key3 is {key3}")
    print(f"key4 is {key4}")

function(1,2,3,4) #TypeError: function() takes 2 positional arguments but 4 were given
function(1,2,key3=3,key4=4)
'''
输出:
key2 is 2
key3 is 3
key4 is 4
'''