Установка строки переменной члена, значением которой является ее имя - PullRequest
0 голосов
/ 26 марта 2019

Я хочу заменить строковые литералы в моем коде, так как я хочу минимизировать риск опечаток, особенно в наборах ключей dict:

a['typoh'] = 'this is bad'
  • Я не хочу вводить вещи дважды(риск пропущенной опечатки в значении)
  • Я хочу, чтобы оно было "отслеживаемым" различными IDE (т. е. нажмите через, чтобы увидеть, где оно определено, и избежать завершения).
  • Перечисленияout: «Eaname», чтобы получить «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, где атрибуты устанавливаются черезпередан список строк. Это решает минимизированный риск опечаток, ОЧЕНЬ легко читается, но не имеет ни отслеживаемости 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)

Другой способ - определить класс с помощью объекта-стража, задав значениев пост фазе.Это нормально, отслеживается, представляет собой реальный класс, допускает псевдонимы и т. Д. Но для этого требуется дополнительный раздражающий вызов в конце класса:

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)

Если это то, что щель магия предположительно, тогда я разочарован, так как нужно было бы на самом деле создать объект:

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)

Ответы [ 2 ]

1 голос
/ 26 марта 2019

Я нашел одно решение по этой внешней ссылке с использованием пользовательского мета-класса, для вашего класса, содержащего строковые переменные-члены:

Шаг 1 из 2: Пользовательский метакласс может быть определен следующим образом:

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 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
0 голосов
/ 28 июня 2019
  • Перечисления отсутствуют: 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!
...