Python类DRY

2024-06-08 11:31:52 发布

您现在位置:Python中文网/ 问答频道 /正文

我编写了下面的python类。现在我在每个函数中重复if settings.MIXPANEL_ID:,我想知道是否有更好的方法来编写这个类?你知道吗

class MixpanelClass:
    def __init__(self):
        if settings.MIXPANEL_ID:
            mp = Mixpanel(settings.MIXPANEL_ID)

    def mp_track_event(user_id, event, property=None):
        if settings.MIXPANEL_ID:
            mp.track(user_id, event, property)

    def mp_people_set(user_id, property):
        if settings.MIXPANEL_ID:
            mp.people_set(user_id, property)

    def mp_people_increment(user_id, property):
        if settings.MIXPANEL_ID:
            mp.people_increment(user_id, property)

    def mp_people_track_charge(user_id, revenue, property):
        if settings.MIXPANEL_ID:
            mp.people_track_charge(user_id, revenue, property)

    def mp_get_distinct_id(request):
        if settings.MIXPANEL_ID:
            mp_cookie_name = 'mp_' + settings.MIXPANEL_ID + '_mixpanel'
            mp_cookie = request.COOKIES.get(mp_cookie_name, None)
            if mp_cookie:
                unquoted = unquote(mp_cookie)
                dictionary = literal_eval(unquoted)
                return dictionary.get('distinct_id')

Tags: noneeventidgetifsettingscookiedef
3条回答

可以使用类装饰器(如果需要,可以装饰单个方法):

class enable_if:
    def __init__(self, condition):
        self.condition = condition

    def __call__(self, obj):
        if isinstance(obj, type):
            return self.decorate_class(obj)
        return self.decorate_callable(obj)

    def decorate_class(self, cls):
        for name in dir(cls):
            attr = getattr(cls, name)
            if callable(attr) and (name == '__init__' or not name.startswith('__') and not name.endswith('__')):
                setattr(cls, name, self.decorate_callable(attr))
        return cls

    def decorate_callable(self, func):
        def wrapper(obj, *args, **kwargs):
            if self.condition:
                return func(obj, *args, **kwargs)
        return wrapper

因此:

@enable_if(settings.MIXPANEL_ID)
class MixpanelClass:
    def __init__(self):
        mp = Mixpanel(settings.MIXPANEL_ID)

    def mp_track_event(user_id, event, property=None):
        mp.track(user_id, event, property)

    def mp_people_set(user_id, property):
        mp.people_set(user_id, property)

    def mp_people_increment(user_id, property):
        mp.people_increment(user_id, property)

    def mp_people_track_charge(user_id, revenue, property):
        mp.people_track_charge(user_id, revenue, property)

    def mp_get_distinct_id(request):
        mp_cookie_name = 'mp_' + settings.MIXPANEL_ID + '_mixpanel'
        mp_cookie = request.COOKIES.get(mp_cookie_name, None)
        if mp_cookie:
            unquoted = unquote(mp_cookie)
            dictionary = literal_eval(unquoted)
            return dictionary.get('distinct_id')

如果settings.MIXPANEL_IDFalse,则MixpanelClass类的每个用户方法和__init__方法都将被禁用。你知道吗

我要提一个建议,但是,我认为这仍然需要更多的信息从原来的海报。你知道吗


解决方案1:签入泛型方法

您可以实现一个泛型函数,在该函数中指定要调用的方法。必须将函数/方法作为参数传递给该函数

例如

def act_if_MIXPANEL_ID(self, method, *args, **kwargs):
    """Calls the method METHOD with the given args and kwargs"""
    if settings.MIXPANEL_ID:
        method(*args, **kwargs)

然后可以使用以下代码调用此方法:

class MixpanelClass(object):

    # here goes the rest of your code

    def mp_track_event(self, user_id, event, property=None):
        self.act_if_MIXPANEL_ID(self.mp.track, user_id, event, property)


    def act_if_MIXPANEL_ID(self, method, *args, **kwargs):
        """Calls the method METHOD with the given args and kwargs"""
        if settings.MIXPANEL_ID:
            method(*args, **kwargs)

PS:我冒昧地把静态转换成标准方法。你知道吗


解决方案2:装饰师

或者,您可以定义一个装饰器并用它注释您的方法。在调用该方法之前,将调用decorator。 它将调用do check(在本例中,打印其他内容)

请参阅此处以快速介绍装饰器:Intro

# This is the decorator
def check_settings(func):
    def wrapper(*args, **kwargs):
        if settings.MIXPANEL_ID:
            func(*args, **kwargs)
        else:
            print("Check for settings.MIXPANEL_ID failed.")
    return wrapper

class MixpanelClass:
    def __init__(self):
        if settings.MIXPANEL_ID:
            mp = Mixpanel(settings.MIXPANEL_ID)

    @check_settings
    def mp_track_event(user_id, event, property=None):
        mp.track(user_id, event, property)

    @check_settings
    def mp_people_set(user_id, property):
        mp.people_set(user_id, property)

    @check_settings
    def mp_people_increment(user_id, property):
        mp.people_increment(user_id, property)

如果settings.MIXPANEL_ID没有设置,那么拥有MixpanelClass的实例似乎没有任何意义。这意味着类的定义

class MixpanelClass:
    def __init__(self, mp_id):
        self.mp_id = mp_id
        self.mp = Mixpanel(mp_id)

    def mp_track_event(self, user_id, event, property=None):
        self.mp.track(user_id, event, property)

    def mp_people_set(self, user_id, property):
        self.mp.people_set(user_id, property)

    def mp_people_increment(self, user_id, property):
        self.mp.people_increment(user_id, property)

    def mp_people_track_charge(self, user_id, revenue, property):
        self.mp.people_track_charge(user_id, revenue, property)

    def mp_get_distinct_id(self, request):
        mp_cookie_name = 'mp_' + self.mp_id + '_mixpanel'
        mp_cookie = request.COOKIES.get(mp_cookie_name, None)
        if mp_cookie:
            unquoted = unquote(mp_cookie)
            dictionary = literal_eval(unquoted)
            return dictionary.get('distinct_id')

现在,如果您实际拥有一个id,那么只需实例化MixpanelClass

if settings.MIXPANEL_ID:
    m = MixpanelClass(settings.MIXPANEL_ID)

相关问题 更多 >