我在这里不知所措。 我正在尝试在for循环中定义一个函数。该函数使用在循环内定义的变量,看起来可能类似于:
myFuns = []
for i in range(10):
j = i + 4
def fun(): print(j)
myFuns += [fun]
在此循环结束时,我在myFuns中的函数有所不同,但它们执行相同的操作,显然,这不是传递给fun()的新变量j,而是对j的引用。>
我很高兴知道如何传递j的值,而不仅仅是引用。
我不知道在循环中创建的变量是否会超过循环寿命,所以这对我来说是新领域...
答案 0 :(得分:3)
j
是一个自由变量,当fun
被称为 时将查询其值; fun
不会将j
的当前值烘烤到其定义中。此外,由于缺少任何其他包含作用域,因此对fun
的调用将引用全局作用域中的j
,其中其最后一个设置值是其在循环的最后一次迭代中的值。
要在定义j
时在fun
中实际存储myFuns = []
for i in range(10):
j = i + 4
def fun(j=j):
print(j)
myFuns.append(fun) # Don't use += [...] for a single item
的固定值,您需要将其作为具有默认值的参数传递:
# Here, j is a free variable in _, but its value comes from the local
# variable j defined by make_fun, not the global scope.
def make_fun(j):
def _():
return j
return _
myFuns = [make_fun(i) for i in range(10)]
但是,闭包可能更合适:
public class Listener {
private async Task HandleRequestAsync(RestoreRequest request, RestoreWorker worker) {
Response response = await worker.ExecuteAsync(request).ConfigureAwait(false);
}
}
public class RestoreWorker {
public async Task<Response> ExecuteAsync(RestoreRequest request) {
RestoreService restoreService = new restoreService(request);
restoreService.Progress.ProgressChanged += async (sender, info) => await request.UpdateStatusAsync(new State(StateEnum.Running) { ProgressCurrent = info.Current, ProgressTotal = info.Total }).ConfigureAwait(false);
await restoreService.RestoreAsync(request.Id, request.Name).ConfigureAwait(false);
return new Response();
}
public Progress<ProgressInfo> Progress { get; } = new Progress<ProgressInfo>();
}
public class RestoreRequest {
public async Task UpdateStatusAsync(Status status) {
Message message = new Message { Status = status };
await sender.SendAsync(message).ConfigureAwait(false);
}
}
public class RestoreService {
private static readonly IRestoreClient restoreClient = ServiceProxyFactory.CreateServiceProxy<IRestoreClient>(new Uri($"{FabricConfig.ApplicationName}/RestoreClient"));
private async Task <Project> GetProjectByNameAsync(string name){
//return the project
}
private async Task RestoreAsync(string id, string name) {
await restoreClient.RestoreAsync(id, name).ConfigureAwait(false);
}
}
public class RestoreClient : IRestoreClient {
private async Task RestoreAsync(string id, string name) {
Project project = await GetProjectByNameAsync(name).ConfigureAwait(false);
project = await UpdateDbAsync(project.Id).ConfigureAwait(false);
if (project == null) {
throw new Exception("Could not find project.");
}
}
private async Task UpdateDbAsync(string id) {
try {
List<string> input = CreateScripts();
await ExecuteScriptsOnDbAsync(input).ConfigureAwait(false);
} catch (SqlException) {
throw new Exception($"Project with id: '{id}' could not be created.");
}
}
private async Task ExecuteScriptsOnDbAsync(List<string> scripts) {
using (var conn = new SqlConnection(connectionString)) {
try {
await conn.OpenAsync().ConfigureAwait(false);
using (var sqlCommand = new SqlCommand { Connection = conn }) {
sqlCommand.CommandTimeout = SqlCommandCommandTimeout;
foreach (string script in scripts) {
sqlCommand.CommandText = script;
await sqlCommand.ExecuteNonQueryAsync().ConfigureAwait(false);
}
}
} catch (SqlException ex) {
Log.Fatal(ex, $"Cannot execute script on {Name}");
throw;
}
}
}
}