В ответ на вопрос о том, как правильно использовать изменяемые значения аргументов по умолчанию, я предлагаю следующий пример:
Изменяемое значение по умолчанию может быть полезно для программирования простых в использовании, импортируемых команд, созданных вами. Изменяемый метод по умолчанию сводится к наличию частных статических переменных в функции, которую вы можете инициализировать при первом вызове (очень похоже на класс), но без необходимости прибегать к глобальным переменным, без использования оболочки и без необходимости создавать экземпляр объект класса, который был импортирован. Он по-своему элегантен, надеюсь, вы согласитесь.
Рассмотрим эти два примера:
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()
Разве это не так гладко и чисто, насколько это возможно? Эти изменяемые значения по умолчанию действительно могут пригодиться.
========================
Поразмыслив над своим ответом какое-то время, я не уверен, что ясно понял разницу между использованием изменяемого метода по умолчанию и обычным способом выполнения того же самого.
Обычный способ - использовать импортируемую функцию, которая обертывает объект Class (и использует глобальный). Итак, для сравнения, здесь метод на основе классов, который пытается делать то же самое, что и изменяемый метод по умолчанию.
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()
Сравнивая два метода, преимущества использования изменяемого значения по умолчанию в функции должны быть яснее. Изменяемый метод по умолчанию не требует глобальных переменных, его внутренние переменные не могут быть установлены напрямую. И хотя изменяемый метод принимал переданный аргумент для одного цикла, а затем игнорировал его, метод Class был навсегда изменен, потому что его внутренняя переменная напрямую открыта извне. А какой метод проще программировать? Я думаю, это зависит от вашего уровня комфорта с методами и сложности ваших целей.