【日常】轻松一刻:python传参还能这么写

闲来没事,分享一个工作上遇到的糗事。

先把问题抛出来,假设现在需要定义一个函数myFunction(f,lst),其中参数f是一个函数,lst是一个列表,要求myFunction的运行结果是参数为的函数f依次接受lst中每一项为参数的运行结果,即myFunction(f,lst) = f(lst[0],lst[1], ... ,lst[n]),假设lst中有n+1个元素。

其实这个问题很容易,只是如果没有接触过这个知识点就很难想到该怎么写。因为lst的长度是未知的,并不能用显式表达出f(lst[0],lst[1], ... ,lst[n])

举个例子,如何编写myFunction函数使得下面的脚本能够正常运行👇

def f(a,b=1,c=2,d=3):
	print("a: {}".format(a))
	print("b: {}".format(b))
	print("c: {}".format(c))
	print("d: {}".format(d))

def myFunction(f,lst):
	""" Edit Start """
	""" Edit End """
	pass

lst1 = [1]
lst2 = [1,3]
lst3 = [1,3,5]
lst4 = [1,3,5,7]

myFunction(f,lst1)
myFunction(f,lst2)
myFunction(f,lst3)
myFunction(f,lst4)

笔者遇到这个问题时先去复习了一下动态参数的函数写法👇

def f1(a,*args,**kwargs):
	print(a)
	print(args)
	print(kwargs)

f1(1,2,3,4,b=1,c=2)

# 输出
"""
1
(2, 3, 4)
{'b': 1, 'c': 2}
"""

复习完之后发现好像没有什么用处,并不能解决这个问题,然后就写了一个又臭又长的myFunction函数👇

def f(a,b=1,c=2,d=3):
	print("a: {}".format(a))
	print("b: {}".format(b))
	print("c: {}".format(c))
	print("d: {}".format(d))

def myFunction(f,lst):
	""" Edit Start """
	if len(lst)==1: f(lst[0])
	elif len(lst)==2: f(lst[0],lst[1])
	elif len(lst)==3: f(lst[0],lst[1],lst[2])
	elif len(lst)==4: f(lst[0],lst[1],lst[2],lst[3])
	else: assert False
	""" Edit End """
	pass

lst1 = [1]
lst2 = [1,3]
lst3 = [1,3,5]
lst4 = [1,3,5,7]

myFunction(f,lst1)
myFunction(f,lst2)
myFunction(f,lst3)
myFunction(f,lst4)

写完之后笔者想想不行呀,万一以后f的参数列表超过4个怎么办,要是参数列表有几百上千那不得改得累死,一顿操作后笔者想出了一个绝妙的写法👇

def f(a,b=1,c=2,d=3):
	print("a: {}".format(a))
	print("b: {}".format(b))
	print("c: {}".format(c))
	print("d: {}".format(d))

def myFunction(f,lst):
	""" Edit Start """
	string = "f("
	for i in range(len(lst)):
		string += "lst[{}],".format(i)
	string += ")"
	eval(string)
	""" Edit End """
	pass

lst1 = [1]
lst2 = [1,3]
lst3 = [1,3,5]
lst4 = [1,3,5,7]

myFunction(f,lst1)
myFunction(f,lst2)
myFunction(f,lst3)
myFunction(f,lst4)

笔者想到可以用eval函数完美解决这个问题,eval函数可以将一段字符串当成代码直接运行,lst有多长不知道怎么办?直接把整个表达式用字符串表达出来就好了呗。

写完这个笔者还专门测试了一下发现这样的写法是不成立的👇

eval("f(lst[0],lst[1],lst[2],lst3)")      # 可行
f(eval("lst[0],lst[1],lst[2],lst[3]"))    # 不可行

然后就心满意足的push了代码。

写完之后笔者忽然想起在多进程multiprocess库的使用中似乎有相似的情形,创建进程时只要把函数和参数列表传入Process就可以直接运行函数了👇

import multiprocessing
def do(n) :
	#获取当前线程的名字
	name = multiprocessing.current_process().name
	print(name,'starting')
	print("worker ",n)

if __name__ == '__main__' :
	numList = []
	for i in range(5):
		p = multiprocessing.Process(target=do, args=(i,))
		numList.append(p)
		p.start()
		p.join()
		print("Process end.")

诶,那么multiprocess包里究竟是怎么写这个类似myFunction的函数的呢?是不是跟笔者写得一样妙?

出于好奇去查看了multiprocess的源码(python3.6/Lib/multiprocessing/process.py BaseProcess类节选👇)

class BaseProcess(object):
    '''
    Process objects represent activity that is run in a separate process

    The class is analogous to `threading.Thread`
    '''
    def _Popen(self):
        raise NotImplementedError

    def __init__(self, group=None, target=None, name=None, args=(), kwargs={},
                 *, daemon=None):
        assert group is None, 'group argument must be None for now'
        count = next(_process_counter)
        self._identity = _current_process._identity + (count,)
        self._config = _current_process._config.copy()
        self._parent_pid = os.getpid()
        self._popen = None
        self._target = target
        self._args = tuple(args)
        self._kwargs = dict(kwargs)
        self._name = name or type(self).__name__ + '-' + \
                     ':'.join(str(i) for i in self._identity)
        if daemon is not None:
            self.daemon = daemon
        _dangling.add(self)

    def run(self):
        '''
        Method to be run in sub-process; can be overridden in sub-class
        '''
        if self._target:
            self._target(*self._args, **self._kwargs)

看到run函数里的写法笔者猛得一惊,赶紧测试了一下👇

def f(a,b=1,c=2,d=3):
	print("a: {}".format(a))
	print("b: {}".format(b))
	print("c: {}".format(c))
	print("d: {}".format(d))

def myFunction(f,lst):
	""" Edit Start """
	f(*lst)
	""" Edit End """
	pass

lst1 = [1]
lst2 = [1,3]
lst3 = [1,3,5]
lst4 = [1,3,5,7]

myFunction(f,lst1)
myFunction(f,lst2)
myFunction(f,lst3)
myFunction(f,lst4)

所以其实直接在lst前加个*号就可以了。

实在是丢人现眼的写法,趁还没有人看到赶紧pull下来[汗]

©️2020 CSDN 皮肤主题: 编程工作室 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值