设置一个成员变量string,其值为它的名字
Setting a member variable string whose value is its name
我想替换我的代码中的字符串文字,因为我想尽量减少拼写错误的风险,尤其是在字典键集中:
a['typoh'] = 'this is bad'
- 我不想输入两次(可能会漏掉值)
- 我希望它成为 "trackable" 各种 IDE s(即点击查看它的定义和转义完成)。
- 枚举已经出来了:'E.a.name' 得到 'a' 是愚蠢的。
有人告诉我这可以用 slots 来完成,但我不知道如何不使用小技巧。我可以想到以下几种方法:
这是一个不可接受的答案:
class TwiceIsNotNice(object):
this_is_a_string = 'this_is_a_string'
... (five thousand string constants in)
this_has_a_hard_to_spot_typographical_error =
'this_has_a_had_to_spot_typographical_error'
... (five thousand more string constants)
一种清晰但烦人的方法是使用 "Stringspace" class/object ,其中属性是通过传入的字符串列表设置的。这解决了最小化拼写错误的风险,非常容易阅读,但是IDE 既不是可跟踪性也不是自动完成。没关系,但让人抱怨(请不要在这里抱怨,我只是展示如何做到这一点):
string_consts = Stringspace('a', 'b',...,'asdfasdfasdf')
print(string_consts.a)
... where:
class Stringspace(object):
def __init__(self, *strlist):
for s in strlist:
setattr(self, s, s)
另一种方法是使用哨兵对象定义class,在post阶段设置值。这没关系,可以跟踪,将自己呈现为实际的 class,允许使用别名等。但它需要在 class:
末尾进行烦人的额外调用
same = object()
class StrList(object):
this_is_a_strval = same
this_is_another_strval = same
this_gets_aliased = "to something else"
# This would of course could become a function
for attr in dir(StrList):
if getattr(StrList, attr) is same:
setattr(StrList, attr, attr)
print(StrList.a)
如果这就是 slot 魔法的意义所在,那么我很失望,因为必须实际实例化一个对象:
class SlotEnum(object):
__slots__ = []
def __init__(self):
for k in self.__slots__:
setattr(self, k, k)
class Foo(SlotEnum):
__slots__ = ['a', 'b']
foo_enum_OBJECT = Foo()
print(foo_enum_OBJECT.a)
我找到了一个使用自定义元 class 的解决方案 at this external link,您的 class 包含字符串成员变量:
第 1 步,共 2 步:自定义元 class 可以这样定义:
class MetaForMyStrConstants(type):
def __new__(metacls, cls, bases, classdict):
object_attrs = set(dir(type(cls, (object,), {})))
simple_enum_cls = super().__new__(metacls, cls, bases, classdict)
simple_enum_cls._member_names_ = set(classdict.keys()) - object_attrs
non_members = set()
for attr in simple_enum_cls._member_names_:
if attr.startswith('_') and attr.endswith('_'):
non_members.add(attr)
else:
setattr(simple_enum_cls, attr, attr)
simple_enum_cls._member_names_.difference_update(non_members)
return simple_enum_cls
第 2 步,共 2 步: 定义字符串的 class 可以这样定义(使用虚拟值,例如空元组):
class MyStrConstants(metaclass=MetaForMyStrConstants):
ONE_LONG_STR = ()
ANOTHER_LONG_STR = ()
THE_REAL_LONGEST_STR = ()
正在测试:
print (MyStrConstants.ONE_LONG_STR)
print (MyStrConstants.ANOTHER_LONG_STR)
print (MyStrConstants.THE_REAL_LONGEST_STR)
输出:
ONE_LONG_STR
ANOTHER_LONG_STR
THE_REAL_LONGEST_STR
- 枚举已过期:
E.a.name
获得 a
是愚蠢的。
from enum import Enum, auto
class StrEnum(str, Enum):
"base class for Enum members to be strings matching the member's name"
def __repr__(self):
return '<%s.%s>' % (self.__class__.__name__, self.name)
def __str__(self):
return self.name
class E(StrEnum):
a = auto()
this_is_a_string = auto()
no_typo_here = auto()
>>> print(repr(E.a))
<E.a>
>>> print(E.a)
a
>>> print('the answer is: %s!' % E.a)
the answer is: a!
我想替换我的代码中的字符串文字,因为我想尽量减少拼写错误的风险,尤其是在字典键集中:
a['typoh'] = 'this is bad'
- 我不想输入两次(可能会漏掉值)
- 我希望它成为 "trackable" 各种 IDE s(即点击查看它的定义和转义完成)。
- 枚举已经出来了:'E.a.name' 得到 'a' 是愚蠢的。
有人告诉我这可以用 slots 来完成,但我不知道如何不使用小技巧。我可以想到以下几种方法:
这是一个不可接受的答案:
class TwiceIsNotNice(object):
this_is_a_string = 'this_is_a_string'
... (five thousand string constants in)
this_has_a_hard_to_spot_typographical_error =
'this_has_a_had_to_spot_typographical_error'
... (five thousand more string constants)
一种清晰但烦人的方法是使用 "Stringspace" class/object ,其中属性是通过传入的字符串列表设置的。这解决了最小化拼写错误的风险,非常容易阅读,但是IDE 既不是可跟踪性也不是自动完成。没关系,但让人抱怨(请不要在这里抱怨,我只是展示如何做到这一点):
string_consts = Stringspace('a', 'b',...,'asdfasdfasdf')
print(string_consts.a)
... where:
class Stringspace(object):
def __init__(self, *strlist):
for s in strlist:
setattr(self, s, s)
另一种方法是使用哨兵对象定义class,在post阶段设置值。这没关系,可以跟踪,将自己呈现为实际的 class,允许使用别名等。但它需要在 class:
末尾进行烦人的额外调用same = object()
class StrList(object):
this_is_a_strval = same
this_is_another_strval = same
this_gets_aliased = "to something else"
# This would of course could become a function
for attr in dir(StrList):
if getattr(StrList, attr) is same:
setattr(StrList, attr, attr)
print(StrList.a)
如果这就是 slot 魔法的意义所在,那么我很失望,因为必须实际实例化一个对象:
class SlotEnum(object):
__slots__ = []
def __init__(self):
for k in self.__slots__:
setattr(self, k, k)
class Foo(SlotEnum):
__slots__ = ['a', 'b']
foo_enum_OBJECT = Foo()
print(foo_enum_OBJECT.a)
我找到了一个使用自定义元 class 的解决方案 at this external link,您的 class 包含字符串成员变量:
第 1 步,共 2 步:自定义元 class 可以这样定义:
class MetaForMyStrConstants(type):
def __new__(metacls, cls, bases, classdict):
object_attrs = set(dir(type(cls, (object,), {})))
simple_enum_cls = super().__new__(metacls, cls, bases, classdict)
simple_enum_cls._member_names_ = set(classdict.keys()) - object_attrs
non_members = set()
for attr in simple_enum_cls._member_names_:
if attr.startswith('_') and attr.endswith('_'):
non_members.add(attr)
else:
setattr(simple_enum_cls, attr, attr)
simple_enum_cls._member_names_.difference_update(non_members)
return simple_enum_cls
第 2 步,共 2 步: 定义字符串的 class 可以这样定义(使用虚拟值,例如空元组):
class MyStrConstants(metaclass=MetaForMyStrConstants):
ONE_LONG_STR = ()
ANOTHER_LONG_STR = ()
THE_REAL_LONGEST_STR = ()
正在测试:
print (MyStrConstants.ONE_LONG_STR)
print (MyStrConstants.ANOTHER_LONG_STR)
print (MyStrConstants.THE_REAL_LONGEST_STR)
输出:
ONE_LONG_STR
ANOTHER_LONG_STR
THE_REAL_LONGEST_STR
- 枚举已过期:
E.a.name
获得a
是愚蠢的。
from enum import Enum, auto
class StrEnum(str, Enum):
"base class for Enum members to be strings matching the member's name"
def __repr__(self):
return '<%s.%s>' % (self.__class__.__name__, self.name)
def __str__(self):
return self.name
class E(StrEnum):
a = auto()
this_is_a_string = auto()
no_typo_here = auto()
>>> print(repr(E.a))
<E.a>
>>> print(E.a)
a
>>> print('the answer is: %s!' % E.a)
the answer is: a!