Найти - Пользователи
Полная версия: Dependency injection in python
Начало » Python для новичков » Dependency injection in python
1 2 3
Iskatel
Ля. А это все точно для новичков? Такое чувство, что глумиться изволите. Ничего не понимаю
rmk
4kpt_III

На самом деле ничем. Все концепции соблюдены.

Но есть некоторые детали реализации, и так:

Во втором примере вы заменили атрибут объекта на атрибут класса, соответственно и тип инъекции поменялся с инъекции в конструктор на инъекцию в атрибут (при том атрибут класса):

 class UserServiceV1(object):
    """Example class UserService."""
    def __init__(self, user_cls):
        """Initializer."""
        self.user_cls = user_cls
        super(UserService, self).__init__()
# vs
class UserServiceV2(object):
    """Example class UserService."""
    user_cls = None
    def __init__(self):
        """Initializer."""
        super(UserService, self).__init__()
# в таком случае:
class Admin(User):
    """Admin user."""
class Client(User):
    """Client user."""
class Driver(User):
    """Driver user."""
# код ниже не корректен:
admin_service_v2_provider = UserServiceV2
admin_service_v2_provider.user_cls = Admin
client_service_v2_provider = UserServiceV2
client_service_v2_provider.user_cls = Client
driver_service_v2_provider = UserServiceV2
driver_service_v2_provider.user_cls = Driver
# в этом проблема:
assert admin_service_v2_provider.user_cls is Driver and client_service_v2_provider.user_cls is Driver
# в случае использовании инъекции в конструктор (__init__ у нас в пайтоне) такой проблемы нет, 
# но нужно писать чуть больше кода:
def admin_service_provider():
    """Provider admin users service."""
    return UserServiceV1(Admin)
def client_service_provider():
    """Provider client users service."""
    return UserServiceV1(Client)
def driver_service_provider():
    """Provider driver users service."""
    return UserServiceV1(Driver)
# Как вы видели, у меня это решается вот так:
from dependency_injector import providers
admin_service_provider = providers.Factory(UserServiceV1, user_cls=Admin)
client_service_provider = providers.Factory(UserServiceV1, user_cls=Client)
driver_service_provider = providers.Factory(UserServiceV1, user_cls=Driver)

Есть еще различные тонкости, которые на первый взгляд не видны, но, опять же, это тонкости реализации, которые каждый делает по разному.
4kpt_III
Я знал про эту проблему. Спасибо, что подтвердили мою догадку. Тогда можно проще. Еще проще. Если можно, то прокомментируйте

from functools import partial
class User(object):
    """Example class User."""
    def __init__(self, id, password):
        """Initializer."""
        self.id = id
        self.password = password
        super(User, self).__init__()
class UserServiceV1(object):
    """Example class UserService."""
    def __init__(self, user_cls):
        """Initializer."""
        self.user_cls = user_cls
        super(UserServiceV1, self).__init__()
# vs
class UserServiceV2(object):
    """Example class UserService."""
    def __init__(self, user_cls):
        """Initializer."""
        self.user_cls = user_cls
        super(UserServiceV2, self).__init__()
# в таком случае:
class Admin(User):
    """Admin user."""
class Client(User):
    """Client user."""
class Driver(User):
    """Driver user."""
# код ниже не корректен, но если применить кэрирование:
admin_service_v2_provider = partial(UserServiceV2, user_cls=Admin)
client_service_v2_provider = partial(UserServiceV2, user_cls=Client)
driver_service_v2_provider = partial(UserServiceV2, user_cls=Driver)
# и код уменьшается и проблему как ветром сдувает:
assert admin_service_v2_provider().user_cls is Admin
assert driver_service_v2_provider().user_cls is Driver

Заранее благодарен за ответ.
FishHook
Не забывайте тему, у меня появится чуть-чуть времени, я разберусь с вашей либой и тогда качественно опротестую
rmk
4kpt_III

Очень круто (без сарказма)!

Я опять достану пару примеров из рукава

 """`Factory` providers init injections example."""
import collections
import dependency_injector.providers as providers
CreditCard = collections.namedtuple('CreditCard', [])
Photo = collections.namedtuple('Photo', [])
User = collections.namedtuple('User', ['uid', 'main_photo', 'credit_card'])
# User, Photo and CreditCard factories:
credit_cards_factory = providers.Factory(CreditCard)
photos_factory = providers.Factory(Photo)
users_factory = providers.Factory(User,
                                  main_photo=photos_factory,
                                  credit_card=credit_cards_factory)
# Creating several User objects:
user1 = users_factory(1)
# Same as: user1 = User(1,
#                       main_photo=Photo(),
#                       credit_card=CreditCard())
user2 = users_factory(2)
# Same as: user2 = User(2,
#                       main_photo=Photo(),
#                       credit_card=CreditCard())
# Context keyword arguments have priority on keyword argument injections:
main_photo = Photo()
credit_card = CreditCard()
user3 = users_factory(3,
                      main_photo=main_photo,
                      credit_card=credit_card)
# Same as: user3 = User(3,
#                       main_photo=main_photo,
#                       credit_card=credit_card)

Полный пример с описанием тут - http://python-dependency-injector.ets-labs.org/en/stable/providers/factory.html#factory-providers-and-init-injections

Такую штуку будет проблемно собрать на партиалах, а именно:

 user1 = users_factory(1)
# Same as: user1 = User(1,
#                       main_photo=Photo(),
#                       credit_card=CreditCard())

 @partial
просто будет вбрасывать аргументы, но не сможет отличить, что нужно вызвать, а что нет.

У меня, например, есть такое понятие как провайдеры (callable объекты) и все остальное. Все остальное инжектиться “как есть”, а провайдеры передают результат своего вызова как значение инъекции.


Я еще раз повторюсь - это все дело вкуса. То, что делал я - это скорее синтаксический “сахар” для себя, чем какие-то инновации Кстати, говоря о инновациях, у меня все еще есть идея прикрутить к своей либе построение графов зависимостей. Это вполне реально сделать на основе той инфы, которая сейчас храниться в DI каталогах. Просто прикольно было бы посмотреть на граф зависимостей приложения. Думал на счет практического применения такого графа и понял, что нужно попробовать его на практике. Возможно, он поможет общаться с коллегами и объяснять как работает это или то. Возможно, поможет в начале рефакторинга понимать какой муравейник ты собираешься разворошить Нужно пробовать, пока это только концепт…
rmk
FishHook

Буду рад, если найдете время
4kpt_III
rmk

Опять же не вижу никаких проблем…

class User(object):
    def __init__(self, id, main_photo, credit_card):
        """Initializer."""
        self.id = id
        self.main_photo = main_photo
        self.credit_card = credit_card
        super(User, self).__init__()
class Photo(object):
    pass
class CreditCard(object):
    pass
connector = lambda id: User(id, main_photo=Photo(), credit_card=CreditCard())
# Creating several User objects:
user1 = connector(1)
# Same as: user1 = User(1,
#                       main_photo=Photo(),
#                       credit_card=CreditCard())
user2 = connector(2)
# Same as: user2 = User(2,
#                       main_photo=Photo(),
#                       credit_card=CreditCard())
# Making some asserts:
assert user1.id == 1
assert isinstance(user1.main_photo, Photo)
assert isinstance(user1.credit_card, CreditCard)
assert user2.id == 2
assert isinstance(user2.main_photo, Photo)
assert isinstance(user2.credit_card, CreditCard)
assert user1.main_photo is not user2.main_photo
assert user1.credit_card is not user2.credit_card

P.S. Еще вчера прочитал документацию к коду. Отдельное уважение вызвали uml диаграммы. Не всегда такое встретишь. Есть ньюансы по-поводу uml 1.1 и uml 2.0, но при этом при все отменная документация. Редко такую найдешь.

P.S.S. id зарегистрированное в python слово. PyCharm аж бесится
rmk
4kpt_III

Спасибо за позитивные отзывы Приятно было подискутировать

PS: посмотрю различия между uml 1.1 и uml 2.0
PSS: заменю id на что-нибудь типа uid


asm

Вопрос к вам - получилась ли тема полезной?
asm
rmk
получилась ли тема полезной?
Спасибо большое за участие. Тема на самом деле очень интересная. Но вот посмотреть все пока времени нет. Я обязательно отпишу, если у меня появятся вопросы. Спасибо!
rmk
Привет всем!

Случайно наткнулся на эту тему, в которой участвовал раньше, и решил обновить ссылки и примеры так как и то, и другое, было уже не актуально.

This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB