Python——参数(2)

44 篇文章 0 订阅
44 篇文章 21 订阅
min调用 

通过一个练习来说明实际应用中的一个参数匹配工具

假设想要编写一个函数,这个函数能够计算任意参数集合和任意对象数据类型集合中的最小值。也就是说:
(1)这个函数应该接受零个或多个参数:希望传递多少就可以传递多少。
(2)此外,这个函数应该能够使用所有的Python对象类型:数字、字符串、列表、字典的列表、文件甚至None。

第一个要求提供了一个能够充分展示*的特性的自然示例:我们能够将参数收集到一个元祖中,并且可以通过简单的loop依次步进处理每一个参数。第二部分的问题定义很简单:因为每个对象类型支持对比,没有必要对每种类型都创建一个函数(一个多态的应用)。我们能够不论其类型进行简单地比较,并且让Python执行正确的比较。

===================================================================

满分

下面是编写这个操作的三种方法:

(1)第一个函数获取了第一个参数(args是一个元祖),并且使用分片去掉第一个得到了剩余的参数(一个对象同自己比较是没有意义的,特别是这个对象是一个较大的结构时)
(2)第二个版本让Python自动获取第一个参数以及其余的参数,因此避免了进行一次索引和分片
(3)第三个版本通过对内置函数list的调用让一个元祖转换为一个列表,之后调用list内置的sort方法来实现比较。

Sort方法是用C语言进行编写的,所以有时它要比其他的程序运行的快,而前两种方法的线性搜索将会让它们在绝大多数时间都要更快。

下述是三种方法的代码:

def min1(*args):
    res = args[0]
    for arg in args[1:]:
        if arg < res:
            res = arg
    return res

def min2(first,*rest):
    for arg in rest:
        if arg<first:
            first = arg
    return first

def min3 (*args):
    tmp = list(args)
    tmp.sort()
    return tmp[0]

print(min1(3,4,1,2))
print(min2("bb","aa"))
print(min3([2,2],[1,1],[3,3]))
程序输出:

>>> 
1
aa
[2, 2]
===================================================================
加分点
通用化单个函数计算无论最小值还是最大值都可以,也是可能的,这样的函数需要使用到评估对比表达式。例如,内置函数eval或者传入一个任意的比较函数。

下述代码显示的后者的原理:

def minmax(test,*args):
    res = args[0]
    for arg in args[1:]:
        if test(arg,res):
            res = arg
    return res

def lessthan(x,y):return x<y
def grtrthan(x,y):return x>y

print(minmax(lessthan,4,2,1,5,6,3))
print(minmax(grtrthan,4,2,1,5,6,3))
程序输出:
>>> 
1
6
这里,函数作为另一种参数对象传入了一个函数。
===================================================================

一个更有用的例子:通用set函数

模拟实现set的intersect和union函数

def intersect(*args):
    res = []
    for x in args[0]:
        for other in args[1:]:
            if x not in other:
                break
        else:
            res.append(x)
    return res

def union(*args):
    res = []
    for seq in args:
        for x in seq:
            if not x in res:
                res.append(x)
    return res

s1,s2,s3 = 'SPAM','SCAM','SLAM'

print(intersect(s1,s2),union(s1,s2))
print(intersect([1,2,3],(1,4)))
print(intersect(s1,s2,s3))
print(union(s1,s2,s3))
程序输出:
>>> 
['S', 'A', 'M'] ['S', 'P', 'A', 'M', 'C']
[1]
['S', 'A', 'M']
['S', 'P', 'A', 'M', 'C', 'L']
===================================================================
模拟Python3.0 print函数

使用*args任意位置元祖以及**args任意关键字参数字典来模拟Python3.0 print函数所做的大多数工作

'''
Emulate most of the 3.0 print function
call signature:print30(*args,sep=' ',end='\n',file = none)
'''
import sys

def print30(*args,**kargs):
    sep = kargs.get('sep',' ')
    end = kargs.get('end','\n')
    file = kargs.get('file',sys.stdout)
    output = ''
    first = True
    for arg in args:
        output += (''if first else sep)+str(arg)
        first = False
    file.write(output+end)


print30(1,2,3)
print30(1,2,3,sep='')
print30(1,2,3,sep='...')
print30(1,[2],(3,),sep='...')
print30(4,5,6,sep='',end='')
print30(7,8,9)
print30()
print30(1,2,3,sep='??',end='.\n',file=sys.stderr)
程序输出:
>>> 
1 2 3
123
1...2...3
1...[2]...(3,)
4567 8 9

1??2??3.
另外,也可以使用默认的keyword_only关键字参数来实现,这种方法似乎更符合内置print的特征:
def print30(*args,sep=' ',end='\n',file=sys.stdout):
    output = ''
    first = True
    for arg in args:
        output += ('' if first else sep) + str(arg)
        first = False
    file.write(output+end)
因为第一种方式**kargs收集字典的做法,并没有检测机制,print30(1,2,3,sp='')出现了错误的参数,但是这样的调用依然通过,显然不严谨。但是我们可以利用dict.pop删除收到的条目,并且手动检查,手动抛出异常:

def print30(*args,**kargs):
    sep = kargs.pop('sep',' ')
    end = kargs.pop('end','\n')
    file = kargs.pop('file',sys.stdout)
    if kargs:raise TypeError('extra keywords:%s'%kargs)
    output = ''
    first = True
    for arg in args:
        output += (''if first else sep)+str(arg)
        first = False
    file.write(output+end)
这个版本和利用keyword-only关键字参数的做法对等。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值