我需要类似于namedtuple
的类型,但需要可更改的字段。 namedlist
的行为应如下所示:
Something = namedlist('Something', ['a', 'b'])
st = Something(123, 456)
print st # Something(a=123, b=456)
a, b = st
print a, b, st.a, st.b # 123 456 123 456
st.a = 777
print st # Something(a=777, b=456)
st.b = 888
print st # Something(a=777, b=888)
在了解了描述符here和there之后,我得到了以下代码,如上所述:
class IndexAccessor(object):
def __init__(self, index):
self.index = index
def __get__(self, instance, owner):
return list.__getitem__(instance, self.index)
def __set__(self, instance, value):
list.__setitem__(instance, self.index, value)
def namedlist(classname, fields):
def init(self, *args):
list.__init__(self, args)
def repr(self):
return '%s(%s)' % (self.__class__.__name__, ', '.join(['%s=%s' % (k,list.__getitem__(self, i)) for i, k in enumerate(self._fields)]))
attrs = {'_fields': tuple(fields),
'__init__': init,
'__repr__': repr
}
for index, field in enumerate(fields):
attrs[field] = IndexAccessor(index)
return type(classname, (list,), attrs)
IndexAccessor
类对我来说有点像样板,所以我想知道代码是否可以改进以避免它。
我尝试用此
替换for index, field in enumerate(fields)
循环
for index, field in enumerate(fields):
def get(self):
return list.__getitem__(self, index)
def set(self, v):
list.__setitem__(self, index, v)
attrs[field] = property(get, set, None, 'Property "%s" mapped to item %d' % (field, index))
...但是这导致print a, b, st.a, st.b
语句产生123 456 456 456
而不是123 456 123 456
,我怀疑这与index
无法按要求生成有关。
奖励积分以获取答案,这些答案还可以提供简明的代码,以便在构造函数中进行基于名称的分配,如
Something = namedlist('Something', ['a', 'b'])
st = Something(a=123, b=456)
答案 0 :(得分:1)
for循环不起作用的原因是index
和get
函数中引用的set
变量未被复制。它是引用在for循环中设置的index
变量。所以所有属性访问都获得最后一个值。这可以通过将索引显式存储为默认参数来解决。
固定代码:
for index, field in enumerate(fields):
def get(self,index=index):
return list.__getitem__(self, index)
def set(self, v,index=index):
list.__setitem__(self, index, v)
attrs[field] = property(get, set, None, 'Property "%s" mapped to item %d' % (field, index))
要允许关键字参数,请将__init__
函数修改为以下内容:
def init(self, *args, **kwargs):
kwargs.update(zip(self._fields, args))
args = [kwargs[k] for k in self._fields]
list.__init__(self, args)
答案 1 :(得分:0)
我采取了另一种方法来解决此问题,可能值得与您一起发布。它更通用-可能会或可能不希望-会更短,但效率也可能较低。
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie()
.AddOpenIdConnect(options =>
{
options.Authority = Configuration["AuthoritySite"];
options.ClientId = Configuration["ClientId"];
options.ClientSecret = Configuration["ClientSecret"];
options.Scope.Clear();
// options.Scope.Add("Any:Scope");
options.ResponseType = OpenIdConnectResponseType.CodeIdTokenToken;
options.SaveTokens = true;
options.GetClaimsFromUserInfoEndpoint = true;
options.TokenValidationParameters = new TokenValidationParameters
{
// Compensate server drift
ClockSkew = TimeSpan.FromHours(12),
// Ensure key
IssuerSigningKey = CERTIFICATE,
// Ensure expiry
RequireExpirationTime = true,
ValidateLifetime = true,
// Save token
SaveSigninToken = true
};
});
services.AddAuthorization(options =>
{
options.AddPolicy("Mvc", policy =>
{
policy.AuthenticationSchemes.Add(OpenIdConnectDefaults.AuthenticationScheme);
policy.RequireAuthenticatedUser();
});
});
}