针对可变默认参数值的好用途问题,我提供以下示例:
可变默认参数对于编写易于使用、可导入的自定义命令非常有用。这种可变默认方法相当于在函数中拥有私有静态变量,您可以在第一次调用时进行初始化(非常类似于类),但无需使用全局变量,也无需使用包装器,并且无需实例化已导入的类对象。从某种意义上说,它是优雅的,我希望您会同意。
考虑以下两个示例:
def dittle(cache = []):
from time import sleep
if type(cache) != list or cache !=[] and (len(cache) == 2 and type(cache[1]) != int):
print(" User called dittle("+repr(cache)+").\n >> Warning: dittle() takes no arguments, so this call is ignored.\n")
return
if not cache:
print("\n cache =",cache)
print(" Initializing private mutable static cache. Runs only on First Call!")
cache.append("Hello World!")
cache.append(0)
print(" cache =",cache,end="\n\n")
cache[1]+=1
outstr = " dittle() called "+str(cache[1])+" times."
if cache[1] == 1:outstr=outstr.replace("s.",".")
print(outstr)
print(" Internal cache held string = '"+cache[0]+"'")
print()
if cache[1] == 3:
print(" Let's rest for a moment.")
sleep(2.0)
print(" Wheew! Ready to continue.\n")
sleep(1.0)
elif cache[1] == 4:
cache[0] = "It's Good to be Alive!"
if __name__ == "__main__":
for cnt in range(2):dittle()
print(" Attempting to pass an list to dittle()")
dittle([" BAD","Data"])
print(" Attempting to pass a non-list to dittle()")
dittle("hi")
print(" Calling dittle() normally..")
dittle()
print(" Attempting to set the private mutable value from the outside.")
dittle([" I am a Grieffer!\n (Notice this change will not stick!)",-7])
print(" Calling dittle() normally once again.")
dittle()
dittle()
如果您运行此代码,您将看到dittle()函数在第一次调用时内部化,但在其他调用中不会内部化,它使用私有静态缓存(可变默认值)来在调用之间进行内部静态存储,拒绝试图劫持静态存储,对恶意输入具有弹性,并且可以根据动态条件(这里是函数被调用的次数)进行操作。
使用可变默认值的关键是不要做任何重新分配内存中变量的操作,而是始终在原地更改变量。
为了真正看到这种技术的潜在力量和有用性,请将此第一个程序保存到当前目录下,命名为“DITTLE.py”,然后运行下一个程序。它导入并使用我们的新dittle()命令,无需记住任何步骤或编程难题即可使用。
这是我们的第二个例子。将其编译并作为新程序运行。
from DITTLE import dittle
print("\n We have emulated a new python command with 'dittle()'.\n")
dittle()
dittle()
dittle()
dittle()
dittle()
现在这不是非常流畅和简洁吗?这些可变默认值确实非常方便。
========================
经过一段时间的思考,我不确定我是否清楚地说明了使用可变默认方法和常规方式完成相同事情之间的区别。
常规方式是使用一个可导入的函数来包装一个类对象(并使用全局变量)。因此,为了比较,这里提供了一个基于类的方法,试图做与可变默认方法相同的事情。
from time import sleep
class dittle_class():
def __init__(self):
self.b = 0
self.a = " Hello World!"
print("\n Initializing Class Object. Executes on First Call only.")
print(" self.a = '"+str(self.a),"', self.b =",self.b,end="\n\n")
def report(self):
self.b = self.b + 1
if self.b == 1:
print(" Dittle() called",self.b,"time.")
else:
print(" Dittle() called",self.b,"times.")
if self.b == 5:
self.a = " It's Great to be alive!"
print(" Internal String =",self.a,end="\n\n")
if self.b ==3:
print(" Let's rest for a moment.")
sleep(2.0)
print(" Wheew! Ready to continue.\n")
sleep(1.0)
cl= dittle_class()
def dittle():
global cl
if type(cl.a) != str and type(cl.b) != int:
print(" Class exists but does not have valid format.")
cl.report()
if __name__ == "__main__":
print(" We have emulated a python command with our own 'dittle()' command.\n")
for cnt in range(2):dittle()
print(" Attempting to pass arguments to dittle()")
try:
dittle(["BAD","Data"])
except:
print(" This caused a fatal error that can't be caught in the function.\n")
print(" Calling dittle() normally..")
dittle()
print(" Attempting to set the Class variable from the outside.")
cl.a = " I'm a griefer. My damage sticks."
cl.b = -7
dittle()
dittle()
将这个基于类的程序保存在您当前的目录中,命名为DITTLE.py,然后运行以下代码(与早期相同)。
from DITTLE import dittle
dittle()
dittle()
dittle()
dittle()
dittle()
通过比较这两种方法,使用函数中的可变默认值的优点应该更加清晰。可变默认值方法不需要全局变量,它的内部变量不能直接设置。而可变方法只接受一个有知识的传递参数进行单个周期,然后就忽略了它,类方法则因为其内部变量直接暴露给外部而被永久地改变。至于哪种方法更容易编程?我认为这取决于您对这些方法的熟悉程度和您的目标的复杂性。
__init__
函数的参数,该函数将其设置为实例变量;这是一个完全合理的需求,但如果使用可变类型作为默认值,就会出现严重问题。参考链接:http://stackoverflow.com/questions/43768055/python-class-instance-variable-isolation - Mark Ransom