{"id":380540,"date":"2024-06-29T03:09:22","date_gmt":"2024-06-29T03:09:22","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=380540"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=380540","title":{"rendered":"<span>\u041f\u043e\u0434\u0445\u043e\u0434\u044b \u043a \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043f\u0430\u0442\u0442\u0435\u0440\u043d\u0430 \u0424\u0430\u0431\u0440\u0438\u043a\u0430 \u0432 Python<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<blockquote>\n<p>\u041a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0438 \u0432\u00a0\u043a\u043e\u0434\u0435 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u044b \u043d\u0430\u00a0\u0430\u043d\u0433\u043b\u0438\u0439\u0441\u043a\u043e\u043c \u044f\u0437\u044b\u043a\u0435, \u0430\u00a0\u0432\u0441\u0435 \u0431\u043b\u043e\u043a\u0438 \u043a\u043e\u0434\u0430 \u0441\u043f\u0440\u044f\u0442\u0430\u043d\u044b \u043f\u043e\u0434\u00a0\u0441\u043f\u043e\u0439\u043b\u0435\u0440\u044b, \u0447\u0442\u043e\u0431\u044b \u043d\u0435\u00a0\u043c\u0435\u0448\u0430\u0442\u044c \u0447\u0442\u0435\u043d\u0438\u044e.<\/p>\n<\/blockquote>\n<h2>\u0410\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u044f<\/h2>\n<p>\u0412\u00a0\u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u043d\u0435\u00a0\u0431\u0443\u0434\u0443 \u043e\u0431\u044a\u044f\u0441\u043d\u044f\u0442\u044c \u043f\u043e\u043b\u044c\u0437\u0443 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u043f\u0430\u0442\u0442\u0435\u0440\u043d\u043e\u0432 \u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0438 \u0444\u0430\u0431\u0440\u0438\u043a\u0438 \u0432\u00a0\u0447\u0430\u0441\u0442\u043d\u043e\u0441\u0442\u0438. \u0417\u0434\u0435\u0441\u044c \u0431\u0443\u0434\u0443\u0442 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u043d\u044b \u043f\u043e\u0434\u0445\u043e\u0434\u044b \u043a\u00a0\u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438, \u043d\u0430\u0447\u0438\u043d\u0430\u044f \u043e\u0442\u00a0\u043f\u0440\u043e\u0441\u0442\u044b\u0445, \u0431\u0430\u043d\u0430\u043b\u044c\u043d\u044b\u0445 \u0438 \u0437\u0430\u043a\u0430\u043d\u0447\u0438\u0432\u0430\u044f \u0431\u043e\u043b\u0435\u0435 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b\u043c\u0438, \u0430\u00a0\u0442\u0430\u043a\u0436\u0435 \u0441\u0434\u0435\u043b\u0430\u043d \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432\u044b\u0432\u043e\u0434.<\/p>\n<h2>\u041f\u043e\u0434\u0445\u043e\u0434\u044b \u043a \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438<\/h2>\n<h3>if-else \/ match-case<\/h3>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0444\u0430\u0431\u0440\u0438\u043a\u0438 \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u043e\u0432 \u0443\u0441\u043b\u043e\u0432\u0438\u044f<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"python\">class ClassNotFoundError(ValueError):     ...   class SubjectOne(object):     ...   class SubjectTwo(object):     ...   class Factory(object):     @staticmethod     def get(class_name: str) -> object:         if type(class_name) != str:             raise ValueError(\"class_name must be a string!\")          if class_name == \"SubjectOne\":             return SubjectOne          if class_name == \"SubjectTwo\":             return SubjectTwo          raise ClassNotFoundError   # Usage class_ = Factory.get(\"SubjectOne\") <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0412\u043d\u0438\u043c\u0430\u043d\u0438\u0435! \u0422\u0430\u043a \u0434\u0435\u043b\u0430\u0442\u044c \u043d\u0435 \u043d\u0443\u0436\u043d\u043e!<\/p>\n<p>\u0421\u0443\u0442\u044c \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043f\u0440\u043e\u0441\u0442\u0430\u00a0\u2014 \u043d\u0430\u00a0\u0432\u0445\u043e\u0434 \u043c\u0435\u0442\u043e\u0434\u0430 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u043a\u043b\u0430\u0441\u0441\u0430 \u0438\u043b\u0438\u00a0\u043a\u0430\u043a\u043e\u0439\u2011\u0442\u043e \u043a\u043b\u044e\u0447, \u043f\u043e\u00a0\u043a\u043e\u0442\u043e\u0440\u043e\u043c\u0443 \u043c\u043e\u0436\u043d\u043e \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u0446\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043a\u043b\u0430\u0441\u0441, \u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c \u043e\u0431\u044a\u0435\u043a\u0442 \u043a\u043b\u0430\u0441\u0441\u0430.<\/p>\n<h3>\u0421\u043b\u043e\u0432\u0430\u0440\u044c<\/h3>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0444\u0430\u0431\u0440\u0438\u043a\u0438 \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u0441\u043b\u043e\u0432\u0430\u0440\u044f<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"python\">from typing import Hashable, Callable   class ClassNotFoundError(ValueError):     ...   class SubjectOne(object):     ...   class SubjectTwo(object):     ...   class Factory(object):     @staticmethod     def get(class_name: Hashable) -> object:         if not isinstance(class_name, Hashable):             raise ValueError(\"class_name must be a Hashable type!\")                  classes: dict[Hashable, Callable[..., object]] = {             \"SubjectOne\": SubjectOne,             \"SubjectTwo\": SubjectTwo         }          class_ = classes.get(class_name, None)         if class_ is not None:             return class_          raise ClassNotFoundError   # Usage class_ = Factory.get(\"SubjectOne\") <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u041f\u043e\u043d\u0438\u043c\u0430\u044f, \u0447\u0442\u043e \u0440\u0430\u0437 \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u043a\u0430\u043a\u043e\u0439-\u0442\u043e \u043a\u043b\u044e\u0447, \u043d\u0435\u0442\u0440\u0443\u0434\u043d\u043e \u0434\u043e\u0439\u0442\u0438 \u0434\u043e \u0438\u0434\u0435\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0441\u043b\u043e\u0432\u0430\u0440\u044f, \u0432\u043c\u0435\u0441\u0442\u043e \u043a\u0443\u0447\u0438 \u0443\u0441\u043b\u043e\u0432\u0438\u0439. \u0412\u0430\u0436\u043d\u043e \u043b\u0438\u0448\u044c \u043f\u043e\u043c\u043d\u0438\u0442\u044c, \u0447\u0442\u043e \u043a\u043b\u044e\u0447 \u0441\u043b\u043e\u0432\u0430\u0440\u044f \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c <code>Hashable<\/code> &#8212; \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0442\u044c \u043c\u0435\u0442\u043e\u0434 <code>__hash__()<\/code>.<\/p>\n<h3>eval<\/h3>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0444\u0430\u0431\u0440\u0438\u043a\u0438 \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u043c\u0435\u0442\u043e\u0434\u0430 eval<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"python\">class ClassNotFoundError(ValueError):     ...   class SubjectOne(object):     ...   class SubjectTwo(object):     ...   class Factory(object):     @staticmethod     def get(class_name: str) -> object:         if type(class_name) != str:             raise ValueError(\"class_name must be a string!\")          try:             instance_ = eval(f\"{class_name}()\")             return instance_         except Exception as e:             from warnings import warn             warn(str(e))              raise ClassNotFoundError   # Usage instance_ = Factory.get(\"SubjectTwo\") <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0412\u043d\u0438\u043c\u0430\u043d\u0438\u0435! \u0422\u0430\u043a \u0434\u0435\u043b\u0430\u0442\u044c \u043d\u0435\u00a0\u043d\u0443\u0436\u043d\u043e!<\/p>\n<p>\u042d\u0442\u043e\u0442 \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043e\u0434\u043d\u0438\u043c \u0438\u0437\u00a0\u0441\u0430\u043c\u044b\u0445 \u043f\u0440\u043e\u0441\u0442\u044b\u0445 \u0438 \u0438\u043d\u0442\u0443\u0438\u0442\u0438\u0432\u043d\u043e \u043f\u043e\u043d\u044f\u0442\u043d\u044b\u0445\u00a0\u2014 \u043c\u044b \u043f\u0440\u043e\u0441\u0442\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u043c \u043a\u043e\u0434 \u0441\u00a0\u0438\u043d\u0441\u0442\u0430\u043d\u0446\u0438\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u043a\u043b\u0430\u0441\u0441\u0430 \u043f\u043e\u00a0\u0435\u0433\u043e \u0441\u0442\u0440\u043e\u043a\u043e\u0432\u043e\u043c\u0443 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044e.<br \/>\u0412\u0430\u0436\u043d\u043e \u043f\u043e\u043d\u0438\u043c\u0430\u0442\u044c, \u0447\u0442\u043e <strong>\u044d\u0442\u043e\u0442 \u0441\u043f\u043e\u0441\u043e\u0431 \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442 \u043f\u043e\u0447\u0442\u0438 \u043b\u044e\u0431\u043e\u0439 \u043a\u043e\u0434<\/strong>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u044b \u043f\u0435\u0440\u0435\u0434\u0430\u0434\u0438\u043c.<\/p>\n<p><em>\u041f\u0440\u0438\u043c\u0435\u0447\u0430\u043d\u0438\u0435: <\/em>\u0412 <code>eval<\/code> \u043c\u043e\u0436\u043d\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u043a\u043e\u0434\u0430, \u043e\u0434\u043d\u0430\u043a\u043e \u043c\u044b \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0431\u043e\u043b\u0435\u0435 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430 \u0432\u00a0\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0433\u043b\u0430\u0432\u0435!<\/p>\n<h3>\u0413\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u044b\u0439 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442<\/h3>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0444\u0430\u0431\u0440\u0438\u043a\u0438 \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"python\">class ClassNotFoundError(ValueError):     ...   class SubjectOne(object):     ...   class SubjectTwo(object):     ...   class Factory(object):     @staticmethod     def get(class_name: str) -> object:         if type(class_name) != str:             raise ValueError(\"class_name must be a string!\")          class_ = globals().get(class_name, None)         if class_ is not None:             return class_          raise ClassNotFoundError   # Usage class_ = Factory.get(\"SubjectTwo\") <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0412\u043d\u0438\u043c\u0430\u043d\u0438\u0435! \u0422\u0430\u043a \u0434\u0435\u043b\u0430\u0442\u044c \u043d\u0435 \u043d\u0443\u0436\u043d\u043e!<\/p>\n<p>\u0412\u044b\u0437\u043e\u0432 <code>globals<\/code> \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043c\u0435\u0442\u043e\u0434\u0430 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0441\u043b\u043e\u0432\u0430\u0440\u044c, \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0449\u0438\u0439 \u0432\u0441\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u044b \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u043c\u043e\u0434\u0443\u043b\u044f. \u0420\u0430\u0437 \u044d\u0442\u043e \u0441\u043b\u043e\u0432\u0430\u0440\u044c, \u0442\u043e \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043f\u0440\u0438\u043c\u0435\u043d\u0438\u0442\u044c \u0437\u0434\u0435\u0441\u044c \u0442\u043e\u0442 \u0436\u0435 \u043f\u043e\u0434\u0445\u043e\u0434, \u0447\u0442\u043e \u0431\u044b\u043b \u043e\u043f\u0438\u0441\u0430\u043d \u0440\u0430\u043d\u044c\u0448\u0435.<\/p>\n<h3>\u041f\u043e\u0434\u043a\u043b\u0430\u0441\u0441\u044b<\/h3>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0444\u0430\u0431\u0440\u0438\u043a\u0438 \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u043f\u043e\u0434\u043a\u043b\u0430\u0441\u0441\u043e\u0432<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"python\">from typing import Callable   class ClassNotFoundError(ValueError):     ...   class FactorySubject(object):     ...   class SubjectOne(FactorySubject):     ...   class SubjectTwo(FactorySubject):     ...   class Factory(object):     @staticmethod     def get(class_name: str) -> object:         if type(class_name) != str:             raise ValueError(\"class_name must be a string!\")          raw_subclasses_ = FactorySubject.__subclasses__()         classes: dict[str, Callable[..., object]] = {c.__name__:c for c in raw_subclasses_}         class_ = classes.get(class_name, None)         if class_ is not None:             return class_          raise ClassNotFoundError   # Usage class_ = Factory.get(\"SubjectTwo\") <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u042d\u0442\u043e\u0442 \u043c\u0435\u0442\u043e\u0434 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u044f\u0437\u044b\u043a\u0430 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0432\u0441\u0435 \u043f\u043e\u0434\u043a\u043b\u0430\u0441\u0441\u044b \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0451\u043d\u043d\u043e\u0433\u043e \u043a\u043b\u0430\u0441\u0441\u0430, \u0447\u0442\u043e\u0431\u044b \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0441\u043b\u043e\u0432\u0430\u0440\u044c \u0441\u043e \u0432\u0441\u0435\u043c\u0438 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u043c\u0438 <code>FactorySubject<\/code><em>&#8216;s<\/em>.<\/p>\n<h3>\u0424\u0430\u0439\u043b\u044b \u043c\u043e\u0434\u0443\u043b\u044f*<\/h3>\n<blockquote>\n<p><em>\u0418\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u0438 \u0432\u043c\u0435\u0441\u0442\u0435 \u0441 \u043f\u0440\u0438\u043c\u0435\u0440\u043e\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0432 <\/em><a href=\"https:\/\/github.com\/eijawa\/python-factory-pattern\" rel=\"noopener noreferrer nofollow\"><em>\u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438<\/em><\/a><em>.<\/em><\/p>\n<\/blockquote>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0444\u0430\u0431\u0440\u0438\u043a\u0438 \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u0430\u0432\u0442\u043e\u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u0441\u043b\u043e\u0432\u0430\u0440\u044f \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u0444\u0430\u0439\u043b\u043e\u0432 \u043c\u043e\u0434\u0443\u043b\u044f<\/summary>\n<div class=\"spoiler__content\">\n<p><em>\u0410\u0431\u0441\u0442\u0440\u0430\u043a\u0442\u043d\u044b\u0439 \u043a\u043b\u0430\u0441\u0441 \u0444\u0430\u0431\u0440\u0438\u043a\u0438<\/em><\/p>\n<pre><code class=\"python\">import importlib import logging import os from abc import ABC, abstractmethod from functools import cache from pathlib import Path from types import ModuleType from typing import Callable, Hashable, TypeVar, Generic  debug_logger = logging.getLogger(\"debug\")  T = TypeVar(\"T\")  CallableClass = Callable[..., T]   class AbstractFactory(Generic[T], ABC):     \"\"\"     AbstractFactory     ===============      Class properties     ----------------      modules_dir: Path         A path to dir with desired modules,         which we want to get from our Factory.      parent_package: str         Full parent package path.         Example: src.high_package.low_package      filter_files: list[str]         List of file names to filter from results.       Required implemented methods     ----------------------------     @classmethod     def get_class_name(cls, module: ModuleType) -> str:         Prefer to use with dir(module)       Available additional methods to overload     ----------------------------------------     @classmethod     def get_class_key(cls, class_: object) -> Hashable:         This value used to define key in our dictionary         Default: class_.__class__.__name__     \"\"\"      modules_dir: Path      parent_package: str      filter_files: list[str]      @classmethod     def get(cls, name: str) -> T:         \"\"\"         Get class instance by class_name|key          Arguments         name: str             A class name or a key, if defined by get_class_key-method          Return         Instance of class          Exceptions         ModuleNotFoundError             Raises if module with given name was not found...         \"\"\"          debug_logger.debug(f\"Initialisation for: {name}\")          # Get class-object by it's name         class_: CallableClass | None = cls.__get_classes_dict().get(name, None)          if not class_:             e = ModuleNotFoundError(f\"Module with given name - {name} - not found!\")             debug_logger.exception(e)             raise e          return class_      @classmethod     def exists(cls, name: str) -> bool:         \"\"\"         Check if class with class_name|key exists in Factory.         It's handy method if you do not want to catch exception of get-method.         \"\"\"          class_: CallableClass | None = cls.__get_classes_dict().get(name, None)          return class_ is not None      @classmethod     @cache     def __get_classes_dict(cls) -> dict[Hashable, CallableClass]:         \"\"\"Get cached dictionary of all available classes by Factory\"\"\"          classes_dict: dict[Hashable, CallableClass] = {}          # Get all modules path in modules_dir folder         for module_path in os.listdir(cls.modules_dir):             # Filter unused, standard and all other modules,             # which contains in our filter_files             if module_path.endswith(\".py\") and module_path not in cls.filter_files:                 module: ModuleType = importlib.import_module(                     \".%s\" % module_path.removesuffix(\".py\"),                     package=cls.parent_package,                 )                  # Get class_name by filtering all dir(module) data                 class_name = cls.get_class_name(module)                  class_ = getattr(module, class_name)                 classes_dict[cls.get_class_key(class_)] = class_          return classes_dict      @classmethod     @abstractmethod     def get_class_name(cls, module: ModuleType) -> str:         \"\"\"         *In implementation of this method, I offer to use dir(module)*         This method must return only name of the desired callable class.          The reason behind this approach:         All data got from dir(module) will have link to all of class Parents,         methods, variables and etc., which contains in module,         because of that, we need to carefully filter result.         \"\"\"          ...      @classmethod     def get_class_key(cls, class_: object) -> Hashable:         \"\"\"This value used to define key in our dictionary\"\"\"          return class_.__class__.__name__ <\/code><\/pre>\n<p><em>\u041f\u0440\u0438\u043c\u0435\u0440 \u043a\u043b\u0430\u0441\u0441\u0430-\u043d\u0430\u0441\u043b\u0435\u0434\u043d\u0438\u043a\u0430<\/em><\/p>\n<pre><code class=\"python\">class ParsersFactory(AbstractFactory[BaseParser]):     modules_dir = Path(__file__).parent \/ \"modules\"     parent_package = \"src.parsers.modules\"      filter_files = [\"__init__.py\", \"base.py\"]      @classmethod     def get_class_name(cls, module: ModuleType):         return next(             filter(                 lambda x: x.endswith(\"Parser\") and x != \"BaseParser\",                 dir(module),             )         )          @classmethod     def get_class_key(cls, class_: object) -> str:         return getattr(class_, \"domain\") <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u041e\u0441\u043d\u043e\u0432\u043d\u0430\u044f \u0438\u0434\u0435\u044f \u044d\u0442\u043e\u0433\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u0430 \u0441\u0442\u0440\u043e\u0438\u0442\u0441\u044f \u043d\u0430 \u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438 \u0441\u043b\u043e\u0432\u0430\u0440\u044f \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0445 \u043a\u043b\u0430\u0441\u0441\u043e\u0432 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u0444\u0430\u0439\u043b\u043e\u0432 \u0438\u0437 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0451\u043d\u043d\u043e\u0433\u043e \u043c\u043e\u0434\u0443\u043b\u044f\\\u043f\u0430\u043f\u043a\u0438.<\/p>\n<p><em><sub>*\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u044d\u0442\u043e \u043d\u0435 \u0441\u0430\u043c\u043e\u0435 \u043e\u043f\u0442\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435, \u043d\u043e \u043e\u043d\u043e \u0438\u043c\u0435\u043b\u043e \u043c\u0435\u0441\u0442\u043e \u0431\u044b\u0442\u044c \u0438 \u043e\u0442\u043b\u0438\u0447\u043d\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0434\u043e \u0441\u0438\u0445 \u043f\u043e\u0440.<\/sub><\/em><\/p>\n<h2>\u0412\u044b\u0432\u043e\u0434<\/h2>\n<p>\u041c\u044b \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u043b\u0438 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u043e\u0432 \u043a \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043f\u0430\u0442\u0442\u0435\u0440\u043d\u0430 \u0424\u0430\u0431\u0440\u0438\u043a\u0430 \u0432 \u044f\u0437\u044b\u043a\u0435 Python. \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e, \u0435\u0441\u0442\u044c \u0438 \u0434\u0440\u0443\u0433\u0438\u0435 \u043f\u043e\u0434\u0445\u043e\u0434\u044b, \u043d\u043e \u0443\u0436\u0435 \u0441\u0435\u0439\u0447\u0430\u0441 \u043c\u043e\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0432\u044b\u0432\u043e\u0434, \u0447\u0442\u043e \u0431\u043e\u043b\u044c\u0448\u0430\u044f \u0447\u0430\u0441\u0442\u044c \u043f\u043e\u0434\u0445\u043e\u0434\u043e\u0432 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u0441\u043b\u043e\u0432\u0430\u0440\u044c. \u0420\u0430\u0437\u043d\u0438\u0446\u0430 \u043c\u0435\u0436\u0434\u0443 \u043d\u0438\u043c\u0438 \u043b\u0438\u0448\u044c \u0432 \u043c\u0435\u0442\u043e\u0434\u0435 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0441\u043b\u043e\u0432\u0430\u0440\u044f.<\/p>\n<h4>\u0418\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0438<\/h4>\n<ol>\n<li>\n<p>\u0417\u0434\u0435\u0441\u044c \u044f \u0443\u0437\u043d\u0430\u043b \u043e\u00a0\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0438 \u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430\u00a0\u2014 <a href=\"https:\/\/www.tutorialspoint.com\/python_design_patterns\/python_design_patterns_factory.htm\" rel=\"noopener noreferrer nofollow\"><u>Python Design Patterns &#8212; Factory<\/u><\/a><\/p>\n<\/li>\n<li>\n<p>\u0410\u00a0\u0437\u0434\u0435\u0441\u044c \u043e\u00a0\u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0438 \u043f\u043e\u0434\u043a\u043b\u0430\u0441\u0441\u043e\u0432 \u043a\u043b\u0430\u0441\u0441\u0430\u00a0\u2014 <a href=\"https:\/\/python-3-patterns%E2%80%91idioms%E2%80%91test.readthedocs.io\/en\/latest\/Factory.html\" rel=\"noopener noreferrer nofollow\"><u>Factory: Encapsulating Object Creation<\/u><\/a><\/p>\n<\/li>\n<\/ol>\n<p>UPD: \u0414\u043e\u0431\u0430\u0432\u0438\u043b \u043f\u0440\u0435\u0434\u0443\u043f\u0440\u0435\u0436\u0434\u0435\u043d\u0438\u0435 \u043e \u0442\u043e\u043c, \u0447\u0442\u043e \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u0435\u0442\u043e\u0434\u044b, \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u044b\u0435 \u0432 \u0441\u0442\u0430\u0442\u044c\u0435, \u043b\u0443\u0447\u0448\u0435 \u043d\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u044b\u0432\u0430\u0442\u044c.<\/p>\n<\/p>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/725340\/\"> https:\/\/habr.com\/ru\/articles\/725340\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<blockquote>\n<p>\u041a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0438 \u0432\u00a0\u043a\u043e\u0434\u0435 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u044b \u043d\u0430\u00a0\u0430\u043d\u0433\u043b\u0438\u0439\u0441\u043a\u043e\u043c \u044f\u0437\u044b\u043a\u0435, \u0430\u00a0\u0432\u0441\u0435 \u0431\u043b\u043e\u043a\u0438 \u043a\u043e\u0434\u0430 \u0441\u043f\u0440\u044f\u0442\u0430\u043d\u044b \u043f\u043e\u0434\u00a0\u0441\u043f\u043e\u0439\u043b\u0435\u0440\u044b, \u0447\u0442\u043e\u0431\u044b \u043d\u0435\u00a0\u043c\u0435\u0448\u0430\u0442\u044c \u0447\u0442\u0435\u043d\u0438\u044e.<\/p>\n<\/blockquote>\n<h2>\u0410\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u044f<\/h2>\n<p>\u0412\u00a0\u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u043d\u0435\u00a0\u0431\u0443\u0434\u0443 \u043e\u0431\u044a\u044f\u0441\u043d\u044f\u0442\u044c \u043f\u043e\u043b\u044c\u0437\u0443 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u043f\u0430\u0442\u0442\u0435\u0440\u043d\u043e\u0432 \u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0438 \u0444\u0430\u0431\u0440\u0438\u043a\u0438 \u0432\u00a0\u0447\u0430\u0441\u0442\u043d\u043e\u0441\u0442\u0438. \u0417\u0434\u0435\u0441\u044c \u0431\u0443\u0434\u0443\u0442 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u043d\u044b \u043f\u043e\u0434\u0445\u043e\u0434\u044b \u043a\u00a0\u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438, \u043d\u0430\u0447\u0438\u043d\u0430\u044f \u043e\u0442\u00a0\u043f\u0440\u043e\u0441\u0442\u044b\u0445, \u0431\u0430\u043d\u0430\u043b\u044c\u043d\u044b\u0445 \u0438 \u0437\u0430\u043a\u0430\u043d\u0447\u0438\u0432\u0430\u044f \u0431\u043e\u043b\u0435\u0435 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b\u043c\u0438, \u0430\u00a0\u0442\u0430\u043a\u0436\u0435 \u0441\u0434\u0435\u043b\u0430\u043d \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432\u044b\u0432\u043e\u0434.<\/p>\n<h2>\u041f\u043e\u0434\u0445\u043e\u0434\u044b \u043a \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438<\/h2>\n<h3>if-else \/ match-case<\/h3>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0444\u0430\u0431\u0440\u0438\u043a\u0438 \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u043e\u0432 \u0443\u0441\u043b\u043e\u0432\u0438\u044f<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"python\">class ClassNotFoundError(ValueError):     ...   class SubjectOne(object):     ...   class SubjectTwo(object):     ...   class Factory(object):     @staticmethod     def get(class_name: str) -> object:         if type(class_name) != str:             raise ValueError(\"class_name must be a string!\")          if class_name == \"SubjectOne\":             return SubjectOne          if class_name == \"SubjectTwo\":             return SubjectTwo          raise ClassNotFoundError   # Usage class_ = Factory.get(\"SubjectOne\") <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0412\u043d\u0438\u043c\u0430\u043d\u0438\u0435! \u0422\u0430\u043a \u0434\u0435\u043b\u0430\u0442\u044c \u043d\u0435 \u043d\u0443\u0436\u043d\u043e!<\/p>\n<p>\u0421\u0443\u0442\u044c \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043f\u0440\u043e\u0441\u0442\u0430\u00a0\u2014 \u043d\u0430\u00a0\u0432\u0445\u043e\u0434 \u043c\u0435\u0442\u043e\u0434\u0430 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u043a\u043b\u0430\u0441\u0441\u0430 \u0438\u043b\u0438\u00a0\u043a\u0430\u043a\u043e\u0439\u2011\u0442\u043e \u043a\u043b\u044e\u0447, \u043f\u043e\u00a0\u043a\u043e\u0442\u043e\u0440\u043e\u043c\u0443 \u043c\u043e\u0436\u043d\u043e \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u0446\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043a\u043b\u0430\u0441\u0441, \u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c \u043e\u0431\u044a\u0435\u043a\u0442 \u043a\u043b\u0430\u0441\u0441\u0430.<\/p>\n<h3>\u0421\u043b\u043e\u0432\u0430\u0440\u044c<\/h3>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0444\u0430\u0431\u0440\u0438\u043a\u0438 \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u0441\u043b\u043e\u0432\u0430\u0440\u044f<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"python\">from typing import Hashable, Callable   class ClassNotFoundError(ValueError):     ...   class SubjectOne(object):     ...   class SubjectTwo(object):     ...   class Factory(object):     @staticmethod     def get(class_name: Hashable) -> object:         if not isinstance(class_name, Hashable):             raise ValueError(\"class_name must be a Hashable type!\")                  classes: dict[Hashable, Callable[..., object]] = {             \"SubjectOne\": SubjectOne,             \"SubjectTwo\": SubjectTwo         }          class_ = classes.get(class_name, None)         if class_ is not None:             return class_          raise ClassNotFoundError   # Usage class_ = Factory.get(\"SubjectOne\") <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u041f\u043e\u043d\u0438\u043c\u0430\u044f, \u0447\u0442\u043e \u0440\u0430\u0437 \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u043a\u0430\u043a\u043e\u0439-\u0442\u043e \u043a\u043b\u044e\u0447, \u043d\u0435\u0442\u0440\u0443\u0434\u043d\u043e \u0434\u043e\u0439\u0442\u0438 \u0434\u043e \u0438\u0434\u0435\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0441\u043b\u043e\u0432\u0430\u0440\u044f, \u0432\u043c\u0435\u0441\u0442\u043e \u043a\u0443\u0447\u0438 \u0443\u0441\u043b\u043e\u0432\u0438\u0439. \u0412\u0430\u0436\u043d\u043e \u043b\u0438\u0448\u044c \u043f\u043e\u043c\u043d\u0438\u0442\u044c, \u0447\u0442\u043e \u043a\u043b\u044e\u0447 \u0441\u043b\u043e\u0432\u0430\u0440\u044f \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c <code>Hashable<\/code> &#8212; \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0442\u044c \u043c\u0435\u0442\u043e\u0434 <code>__hash__()<\/code>.<\/p>\n<h3>eval<\/h3>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0444\u0430\u0431\u0440\u0438\u043a\u0438 \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u043c\u0435\u0442\u043e\u0434\u0430 eval<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"python\">class ClassNotFoundError(ValueError):     ...   class SubjectOne(object):     ...   class SubjectTwo(object):     ...   class Factory(object):     @staticmethod     def get(class_name: str) -> object:         if type(class_name) != str:             raise ValueError(\"class_name must be a string!\")          try:             instance_ = eval(f\"{class_name}()\")             return instance_         except Exception as e:             from warnings import warn             warn(str(e))              raise ClassNotFoundError   # Usage instance_ = Factory.get(\"SubjectTwo\") <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0412\u043d\u0438\u043c\u0430\u043d\u0438\u0435! \u0422\u0430\u043a \u0434\u0435\u043b\u0430\u0442\u044c \u043d\u0435\u00a0\u043d\u0443\u0436\u043d\u043e!<\/p>\n<p>\u042d\u0442\u043e\u0442 \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043e\u0434\u043d\u0438\u043c \u0438\u0437\u00a0\u0441\u0430\u043c\u044b\u0445 \u043f\u0440\u043e\u0441\u0442\u044b\u0445 \u0438 \u0438\u043d\u0442\u0443\u0438\u0442\u0438\u0432\u043d\u043e \u043f\u043e\u043d\u044f\u0442\u043d\u044b\u0445\u00a0\u2014 \u043c\u044b \u043f\u0440\u043e\u0441\u0442\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u043c \u043a\u043e\u0434 \u0441\u00a0\u0438\u043d\u0441\u0442\u0430\u043d\u0446\u0438\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u043a\u043b\u0430\u0441\u0441\u0430 \u043f\u043e\u00a0\u0435\u0433\u043e \u0441\u0442\u0440\u043e\u043a\u043e\u0432\u043e\u043c\u0443 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044e.<br \/>\u0412\u0430\u0436\u043d\u043e \u043f\u043e\u043d\u0438\u043c\u0430\u0442\u044c, \u0447\u0442\u043e <strong>\u044d\u0442\u043e\u0442 \u0441\u043f\u043e\u0441\u043e\u0431 \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442 \u043f\u043e\u0447\u0442\u0438 \u043b\u044e\u0431\u043e\u0439 \u043a\u043e\u0434<\/strong>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u044b \u043f\u0435\u0440\u0435\u0434\u0430\u0434\u0438\u043c.<\/p>\n<p><em>\u041f\u0440\u0438\u043c\u0435\u0447\u0430\u043d\u0438\u0435: <\/em>\u0412 <code>eval<\/code> \u043c\u043e\u0436\u043d\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u043a\u043e\u0434\u0430, \u043e\u0434\u043d\u0430\u043a\u043e \u043c\u044b \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0431\u043e\u043b\u0435\u0435 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430 \u0432\u00a0\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0433\u043b\u0430\u0432\u0435!<\/p>\n<h3>\u0413\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u044b\u0439 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442<\/h3>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0444\u0430\u0431\u0440\u0438\u043a\u0438 \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"python\">class ClassNotFoundError(ValueError):     ...   class SubjectOne(object):     ...   class SubjectTwo(object):     ...   class Factory(object):     @staticmethod     def get(class_name: str) -> object:         if type(class_name) != str:             raise ValueError(\"class_name must be a string!\")          class_ = globals().get(class_name, None)         if class_ is not None:             return class_          raise ClassNotFoundError   # Usage class_ = Factory.get(\"SubjectTwo\") <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0412\u043d\u0438\u043c\u0430\u043d\u0438\u0435! \u0422\u0430\u043a \u0434\u0435\u043b\u0430\u0442\u044c \u043d\u0435 \u043d\u0443\u0436\u043d\u043e!<\/p>\n<p>\u0412\u044b\u0437\u043e\u0432 <code>globals<\/code> \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043c\u0435\u0442\u043e\u0434\u0430 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0441\u043b\u043e\u0432\u0430\u0440\u044c, \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0449\u0438\u0439 \u0432\u0441\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u044b \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u043c\u043e\u0434\u0443\u043b\u044f. \u0420\u0430\u0437 \u044d\u0442\u043e \u0441\u043b\u043e\u0432\u0430\u0440\u044c, \u0442\u043e \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043f\u0440\u0438\u043c\u0435\u043d\u0438\u0442\u044c \u0437\u0434\u0435\u0441\u044c \u0442\u043e\u0442 \u0436\u0435 \u043f\u043e\u0434\u0445\u043e\u0434, \u0447\u0442\u043e \u0431\u044b\u043b \u043e\u043f\u0438\u0441\u0430\u043d \u0440\u0430\u043d\u044c\u0448\u0435.<\/p>\n<h3>\u041f\u043e\u0434\u043a\u043b\u0430\u0441\u0441\u044b<\/h3>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0444\u0430\u0431\u0440\u0438\u043a\u0438 \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u043f\u043e\u0434\u043a\u043b\u0430\u0441\u0441\u043e\u0432<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"python\">from typing import Callable   class ClassNotFoundError(ValueError):     ...   class FactorySubject(object):     ...   class SubjectOne(FactorySubject):     ...   class SubjectTwo(FactorySubject):     ...   class Factory(object):     @staticmethod     def get(class_name: str) -> object:         if type(class_name) != str:             raise ValueError(\"class_name must be a string!\")          raw_subclasses_ = FactorySubject.__subclasses__()         classes: dict[str, Callable[..., object]] = {c.__name__:c for c in raw_subclasses_}         class_ = classes.get(class_name, None)         if class_ is not None:             return class_          raise ClassNotFoundError   # Usage class_ = Factory.get(\"SubjectTwo\") <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u042d\u0442\u043e\u0442 \u043c\u0435\u0442\u043e\u0434 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u044f\u0437\u044b\u043a\u0430 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0432\u0441\u0435 \u043f\u043e\u0434\u043a\u043b\u0430\u0441\u0441\u044b \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0451\u043d\u043d\u043e\u0433\u043e \u043a\u043b\u0430\u0441\u0441\u0430, \u0447\u0442\u043e\u0431\u044b \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0441\u043b\u043e\u0432\u0430\u0440\u044c \u0441\u043e \u0432\u0441\u0435\u043c\u0438 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u043c\u0438 <code>FactorySubject<\/code><em>&#8216;s<\/em>.<\/p>\n<h3>\u0424\u0430\u0439\u043b\u044b \u043c\u043e\u0434\u0443\u043b\u044f*<\/h3>\n<blockquote>\n<p><em>\u0418\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u0438 \u0432\u043c\u0435\u0441\u0442\u0435 \u0441 \u043f\u0440\u0438\u043c\u0435\u0440\u043e\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0432 <\/em><a href=\"https:\/\/github.com\/eijawa\/python-factory-pattern\" rel=\"noopener noreferrer nofollow\"><em>\u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438<\/em><\/a><em>.<\/em><\/p>\n<\/blockquote>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0444\u0430\u0431\u0440\u0438\u043a\u0438 \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u0430\u0432\u0442\u043e\u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u0441\u043b\u043e\u0432\u0430\u0440\u044f \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u0444\u0430\u0439\u043b\u043e\u0432 \u043c\u043e\u0434\u0443\u043b\u044f<\/summary>\n<div class=\"spoiler__content\">\n<p><em>\u0410\u0431\u0441\u0442\u0440\u0430\u043a\u0442\u043d\u044b\u0439 \u043a\u043b\u0430\u0441\u0441 \u0444\u0430\u0431\u0440\u0438\u043a\u0438<\/em><\/p>\n<pre><code class=\"python\">import importlib import logging import os from abc import ABC, abstractmethod from functools import cache from pathlib import Path from types import ModuleType from typing import Callable, Hashable, TypeVar, Generic  debug_logger = logging.getLogger(\"debug\")  T = TypeVar(\"T\")  CallableClass = Callable[..., T]   class AbstractFactory(Generic[T], ABC):     \"\"\"     AbstractFactory     ===============      Class properties     ----------------      modules_dir: Path         A path to dir with desired modules,         which we want to get from our Factory.      parent_package: str         Full parent package path.         Example: src.high_package.low_package      filter_files: list[str]         List of file names to filter from results.       Required implemented methods     ----------------------------     @classmethod     def get_class_name(cls, module: ModuleType) -> str:         Prefer to use with dir(module)       Available additional methods to overload     ----------------------------------------     @classmethod     def get_class_key(cls, class_: object) -> Hashable:         This value used to define key in our dictionary         Default: class_.__class__.__name__     \"\"\"      modules_dir: Path      parent_package: str      filter_files: list[str]      @classmethod     def get(cls, name: str) -> T:         \"\"\"         Get class instance by class_name|key          Arguments         name: str             A class name or a key, if defined by get_class_key-method          Return         Instance of class          Exceptions         ModuleNotFoundError             Raises if module with given name was not found...         \"\"\"          debug_logger.debug(f\"Initialisation for: {name}\")          # Get class-object by it's name         class_: CallableClass | None = cls.__get_classes_dict().get(name, None)          if not class_:             e = ModuleNotFoundError(f\"Module with given name - {name} - not found!\")             debug_logger.exception(e)             raise e          return class_      @classmethod     def exists(cls, name: str) -> bool:         \"\"\"         Check if class with class_name|key exists in Factory.         It's handy method if you do not want to catch exception of get-method.         \"\"\"          class_: CallableClass | None = cls.__get_classes_dict().get(name, None)          return class_ is not None      @classmethod     @cache     def __get_classes_dict(cls) -> dict[Hashable, CallableClass]:         \"\"\"Get cached dictionary of all available classes by Factory\"\"\"          classes_dict: dict[Hashable, CallableClass] = {}          # Get all modules path in modules_dir folder         for module_path in os.listdir(cls.modules_dir):             # Filter unused, standard and all other modules,             # which contains in our filter_files             if module_path.endswith(\".py\") and module_path not in cls.filter_files:                 module: ModuleType = importlib.import_module(                     \".%s\" % module_path.removesuffix(\".py\"),                     package=cls.parent_package,                 )                  # Get class_name by filtering all dir(module) data                 class_name = cls.get_class_name(module)                  class_ = getattr(module, class_name)                 classes_dict[cls.get_class_key(class_)] = class_          return classes_dict      @classmethod     @abstractmethod     def get_class_name(cls, module: ModuleType) -> str:         \"\"\"         *In implementation of this method, I offer to use dir(module)*         This method must return only name of the desired callable class.          The reason behind this approach:         All data got from dir(module) will have link to all of class Parents,         methods, variables and etc., which contains in module,         because of that, we need to carefully filter result.         \"\"\"          ...      @classmethod     def get_class_key(cls, class_: object) -> Hashable:         \"\"\"This value used to define key in our dictionary\"\"\"          return class_.__class__.__name__ <\/code><\/pre>\n<p><em>\u041f\u0440\u0438\u043c\u0435\u0440 \u043a\u043b\u0430\u0441\u0441\u0430-\u043d\u0430\u0441\u043b\u0435\u0434\u043d\u0438\u043a\u0430<\/em><\/p>\n<pre><code class=\"python\">class ParsersFactory(AbstractFactory[BaseParser]):     modules_dir = Path(__file__).parent \/ \"modules\"     parent_package = \"src.parsers.modules\"      filter_files = [\"__init__.py\", \"base.py\"]      @classmethod     def get_class_name(cls, module: ModuleType):         return next(             filter(                 lambda x: x.endswith(\"Parser\") and x != \"BaseParser\",                 dir(module),             )         )          @classmethod     def get_class_key(cls, class_: object) -> str:         return getattr(class_, \"domain\") <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u041e\u0441\u043d\u043e\u0432\u043d\u0430\u044f \u0438\u0434\u0435\u044f \u044d\u0442\u043e\u0433\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u0430 \u0441\u0442\u0440\u043e\u0438\u0442\u0441\u044f \u043d\u0430 \u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438 \u0441\u043b\u043e\u0432\u0430\u0440\u044f \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0445 \u043a\u043b\u0430\u0441\u0441\u043e\u0432 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u0444\u0430\u0439\u043b\u043e\u0432 \u0438\u0437 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0451\u043d\u043d\u043e\u0433\u043e \u043c\u043e\u0434\u0443\u043b\u044f\\\u043f\u0430\u043f\u043a\u0438.<\/p>\n<p><em><sub>*\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u044d\u0442\u043e \u043d\u0435 \u0441\u0430\u043c\u043e\u0435 \u043e\u043f\u0442\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435, \u043d\u043e \u043e\u043d\u043e \u0438\u043c\u0435\u043b\u043e \u043c\u0435\u0441\u0442\u043e \u0431\u044b\u0442\u044c \u0438 \u043e\u0442\u043b\u0438\u0447\u043d\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0434\u043e \u0441\u0438\u0445 \u043f\u043e\u0440.<\/sub><\/em><\/p>\n<h2>\u0412\u044b\u0432\u043e\u0434<\/h2>\n<p>\u041c\u044b \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u043b\u0438 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u043e\u0432 \u043a \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043f\u0430\u0442\u0442\u0435\u0440\u043d\u0430<\/p>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-380540","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/380540","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=380540"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/380540\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=380540"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=380540"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=380540"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}