为了回答可变默认参数值的良好用途问题,我提供以下示例:
可变默认值可用于编写易于使用、可导入的您自己创建的命令。可变的默认方法相当于在函数中拥有私有的静态变量,您可以在第一次调用时初始化(非常像一个类),但不必求助于全局变量,不必使用包装器,也不必实例化导入的类对象。正如我希望你会同意的那样,它以自己的方式优雅。
考虑这两个例子:
def dittle(cache = []):
from time import sleep # Not needed except as an example.
# dittle's internal cache list has this format: cache[string, counter]
# Any argument passed to dittle() that violates this format is invalid.
# (The string is pure storage, but the counter is used by dittle.)
# -- Error Trap --
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
# -- Initialize Function. (Executes on first call only.) --
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")
# -- Normal Operation --
cache[1]+=1 # Static cycle count.
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) # Since we imported it, we might as well use it.
print(" Wheew! Ready to continue.\n")
sleep(1.0)
elif cache[1] == 4:
cache[0] = "It's Good to be Alive!" # Let's change the private message.
# =================== MAIN ======================
if __name__ == "__main__":
for cnt in range(2):dittle() # Calls can be loop-driven, but they need not be.
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.")
# Even an insider's attempt to feed a valid format will be accepted
# for the one call only, and is then is discarded when it goes out
# of scope. It fails to interrupt normal operation.
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")
# Nothing to declare, nothing to instantize, nothing to remember.
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) # Since we imported it, we might as well use it.
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()
# =================== MAIN ======================
if __name__ == "__main__":
print(" We have emulated a python command with our own 'dittle()' command.\n")
for cnt in range(2):dittle() # Call can be loop-driver, but they need not be.
print(" Attempting to pass arguments to dittle()")
try: # The user must catch the fatal error. The mutable default user did not.
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
# Nothing to declare, nothing to instantize, nothing to remember.
dittle()
dittle()
dittle()
dittle()
dittle()
通过比较这两种方法,在函数中使用可变默认值的优势应该更加明显。可变默认方法不需要全局变量,它的内部变量不能直接设置。虽然 mutable 方法在一个循环中接受了一个知识渊博的传递参数然后不理会它,但 Class 方法被永久更改了,因为它的内部变量直接暴露在外部。至于哪种方法更容易编程?我认为这取决于您对方法的熟悉程度以及您目标的复杂程度。