Проблема с вашим регулярным выражением в том, что все необязательно. Побочным эффектом этого является то, что вы получаете совпадения нулевой ширины между каждым символом вне ваших других совпадений.
(?:\b(?:this|is|a|string)\s*)+(?<!\s)
Чтобы ответить на ваш вопрос в комментариях, последняя часть представляет собой отрицательный взгляд сзади, чтобы убедиться, что захват не заканчивается пробелом.
Я придерживался бы подхода функции фабрики. Это - очень стандартный Python и легкий читать и понять. Вы могли сделать это более универсальным для обработки большего количества опций несколькими способами такой как путем передачи в функции различителя и карте результатов к классам.
Если первый пример работает, это больше удачей, чем дизайном. Что, если Вы хотели иметь __init__
определенный в Вашем подклассе?
Вам не должны быть нужны метаклассы для этого. Смотрите на __new__
метод. Это позволит Вам брать под свой контроль создание объекта, а не просто инициализацию, и так возвращать объект Вашего выбора.
class Project(object):
"Base class and factory."
def __new__(cls, url):
if is_url_local(url):
return super(Project, cls).__new__(ProjectLocal, url)
else:
return super(Project, cls).__new__(ProjectRemote, url)
def __init__(self, url):
self.url = url
Следующие ссылки могут быть полезными: http://www.suttoncourtenay.org.uk/duncan/accu/pythonpatterns.html#factory http://code.activestate.com/recipes/86900/
Кроме того, поскольку Вы используете модернизированные классы, с помощью __ новый __ как функция фабрики (а не в базовом классе, отдельный класс лучше), то, что обычно делается (насколько я знаю).
Функция фабрики обычно более проста (поскольку другие люди уже отправили),
Кроме того, это не хорошая идея установить __, класс __ приписывает способ, которым Вы сделали.
Я надеюсь, что Вы находите ответ и ссылки полезными.
Всего наилучшего.
У меня обычно есть отдельный класс фабрики, чтобы сделать это. Таким образом, Вы не должны использовать метаклассы или присвоения на self.__class__
Я также стараюсь не помещать знание, о котором классы доступны для создания в фабрику. Скорее у меня есть все доступные классы, регистрируют себя жгут из прутьев фабрика во время импорта модуля. Давание там классифицирует и некоторая информация о том, когда выбрать этот класс к фабрике (это могло быть именем, regex или вызываемым (например, метод класса регистрирующегося класса)).
Работы очень хорошо для меня и также реализуют такие вещи как инкапсуляция и сокрытие информации.
Я думаю, что второй подход с помощью функции фабрики является намного более чистым, чем то, чтобы заставлять реализацию базового класса зависеть от его подклассов.
Да, как упомянул @scooterXL, фабричная функция - лучший подход в этом случае, но я хотел бы отметить случай для фабрик как classmethods.
Рассмотрим следующую иерархию классов:
class Base(object):
def __init__(self, config):
""" Initialize Base object with config as dict."""
self.config = config
@classmethod
def from_file(cls, filename):
config = read_and_parse_file_with_config(filename)
return cls(filename)
class ExtendedBase(Base):
def behaviour(self):
pass # do something specific to ExtendedBase
Теперь вы можете создавать объекты Base из config dict и из config файла:
>>> Base({"k": "v"})
>>> Base.from_file("/etc/base/base.conf")
Но также, вы можете сделать то же самое с ExtendedBase бесплатно:
>>> ExtendedBase({"k": "v"})
>>> ExtendedBase.from_file("/etc/extended/extended.conf")
Таким образом, этот classmethod factory можно также рассматривать как вспомогательный конструктор.