Раньше я думал, что создание объектов во время выполнения будет лучшим подходом. Теперь я менее уверен, так как вы теряете некоторые полезные функции, хотя это может стоить того, что было бы просто для предотвращения путаницы новичков. Недостатками этого являются:
1. Производительность
def foo(arg=something_expensive_to_compute())):
...
Если используется оценка времени вызова, тогда дорогая функция вызывается каждый раз, когда ваша функция используется без аргумента. Вы либо заплатили бы дорогостоящую цену за каждый вызов, либо должны вручную кэшировать значение извне, загрязняя пространство имен и добавляя многословие.
2. Принудительные связанные параметры
Полезный трюк заключается в привязке параметров лямбда к привязке current переменной при создании лямбда. Например:
funcs = [ lambda i=i: i for i in range(10)]
Возвращает список функций, возвращающих 0,1,2,3 ... соответственно. Если поведение изменено, они вместо этого привяжут i
к значению времени вызова для i, поэтому вы получите список функций, которые все вернули 9
.
Единственным способом реализации этого в противном случае было бы создать дальнейшее закрытие с привязкой i, то есть:
def make_func(i): return lambda: i
funcs = [make_func(i) for i in range(10)]
3. Introspection
Рассмотрим код:
def foo(a='test', b=100, c=[]):
print a,b,c
Мы можем получить информацию о аргументах и значениях по умолчанию с помощью модуля inspect
, который
>>> inspect.getargspec(foo)
(['a', 'b', 'c'], None, None, ('test', 100, []))
информация очень полезна для таких вещей, как создание документов, метапрограммирование, декораторы и т. д.
Теперь предположим, что поведение по умолчанию может быть изменено так, что это эквивалентно:
_undefined = object() # sentinel value
def foo(a=_undefined, b=_undefined, c=_undefined)
if a is _undefined: a='test'
if b is _undefined: b=100
if c is _undefined: c=[]
Однако мы потеряли способность интроспекции и посмотрим, какие аргументы по умолчанию равны . Поскольку объекты не были построены, мы никогда не сможем их захватить, не называя функцию. Самое лучшее, что мы могли бы сделать, это сохранить исходный код и вернуть его как строку.
GCHandle
s фиксирует ваши буферы, а некоторые другие неуправляемые ресурсы освобождаются путем обратного вызова порта завершения. Неуправляемая структура OVERLAPPED
будет зависать до тех пор, пока IAsyncResult
не будет завершена. Это может быть приемлемым, если сетевая нагрузка в вашем приложении невелика, но может стать проблемой, если ваше приложение обрабатывает множество подключений в секунду, поскольку финализация происходит только после полной коллекции GC и в отдельном потоке.
NB: это детали реализации, полученные с помощью Reflector. Предостережение emptor.
EndRead
, если вы не профилируете свое приложение и не обнаружите, что исключениеEndRead
вызывает значительные потери производительности. – Anton Tykhyy 23 June 2011 в 14:36