最好有多个方法或大量可选参数?

发布于 2024-11-30 20:22:06 字数 1429 浏览 3 评论 0原文

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

撩心不撩汉 2024-12-07 20:22:06

通常,在编写方法时,人们可能会认为方法/对象应该做一件事并且应该做得很好。如果您的方法获得越来越多的参数,而这些参数需要代码中越来越多的 if,则可能意味着您的代码正在做不止一件事。特别是如果这些参数触发完全不同的行为。相反,也许可以通过使用不同的类并让它们重载方法来产生相同的行为。

也许您可以使用类似的方法:

class BaseClass(object):
    def a_method(self, item_id):
        response = lookup_response(item_id)
        return response

class CachingClass(BaseClass):
    def a_method(self, item_id):
        if item_id in cache:
            return item_from_cache
        return super(CachingClass, self).a_method(item_id)

    def uncached_method(self, item_id)
        return super(CachingClass, self).a_method(item_id)

这样您就可以拆分如何查找响应和缓存的逻辑,同时还可以让 API 用户灵活地决定是否需要缓存功能。

Normally when writing method one could argue that a method / object should do one thing and it should do it well. If your method get more and more parameters which require more and more ifs in your code that probably means that your code is doing more then one thing. Especially if those parameters trigger totally different behavior. Instead maybe the same behavior could be produced by having different classes and having them overload methods.

Maybe you could use something like:

class BaseClass(object):
    def a_method(self, item_id):
        response = lookup_response(item_id)
        return response

class CachingClass(BaseClass):
    def a_method(self, item_id):
        if item_id in cache:
            return item_from_cache
        return super(CachingClass, self).a_method(item_id)

    def uncached_method(self, item_id)
        return super(CachingClass, self).a_method(item_id)

That way you can split the logic of how to lookup the response and the caching while also making it flexible for the user of the API to decide if they want the caching capabilities or not.

蓝眼泪 2024-12-07 20:22:06

B 类 中使用的方法没有任何问题。为了让您一目了然地知道您实际上需要包含 item_idcached_api_response,我会首先进行错误检查:

class B:

    def a_method(item_id = None, cached_api_response = None):
        """Requires either item_id or cached_api_response"""

        if not ((item_id == None) ^ (cached_api_response == None)):
            #error

        # or, if you want to allow both,
        if (item_id == None) and (cached_api_response == None):
            # error

        # you don't actually have to do this on one line
        # also don't use it if cached_item_api_response can evaluate to 'False'
        api_response = cached_item_api_response or # make api call using item_id

        ... #do stuff

There is nothing wrong with the method used in your class B. To make it more obvious at a glance that you actually need to include either item_id or cached_api_response, I would put the error checking first:

class B:

    def a_method(item_id = None, cached_api_response = None):
        """Requires either item_id or cached_api_response"""

        if not ((item_id == None) ^ (cached_api_response == None)):
            #error

        # or, if you want to allow both,
        if (item_id == None) and (cached_api_response == None):
            # error

        # you don't actually have to do this on one line
        # also don't use it if cached_item_api_response can evaluate to 'False'
        api_response = cached_item_api_response or # make api call using item_id

        ... #do stuff
故乡的云 2024-12-07 20:22:06

最终,这是必须针对每种情况做出的判断。我会问自己,这两者中哪一个更适合:

  1. 两种完全不同的算法或动作,具有完全不同的语义,即使它们可能传递相似的信息
  2. 一个概念性的想法,具有一致的语义,但具有基于输入的细微差别

如果第一个是最接近的,请使用单独的方法。如果第二个最接近,请使用可选参数。您甚至可以通过测试参数的类型来实现单个方法,以避免传递额外的参数。

Ultimately this is a judgement that must be made for each situation. I would ask myself, which of these two more closely fits:

  1. Two completely different algorithms or actions, with completely different semantics, even though they may be passed similar information
  2. A single conceptual idea, with consistent semantics, but with nuance based on input

If the first is closest, go with separate methods. If the second is closest, go with optional arguments. You might even implement a single method by testing the type of the argument(s) to avoid passing additional arguments.

杀お生予夺 2024-12-07 20:22:06

这是面向对象的反模式。

class API_Connection(object):
    def do_something_with_api_response(self, response):
        ...

    def do_something_else_with_api_response(self, response):
        ...

您在一个实例上有两个方法,并且您在它们之间显式传递状态?为什么这些方法而不是模块中的裸函数?

相反,请考虑使用封装来帮助您让类的实例拥有 api 响应。

例如:

class API_Connection(object):
    def __init__(self, api_url):
        self._url = api_url
        self.cached_response = None

    @property
    def response(self):
        """Actually use the _url and get the response when needed."""
        if self._cached_response is None:
            # actually calculate self._cached_response by making our
            # remote call, etc
            self._cached_response = self._get_api_response(self._url)
        return self._cached_response

    def _get_api_response(self, api_param1, ...):
        """Make the request and return the api's response"""

    def do_something_with_api_response(self):
        # just use self.response
        do_something(self.response)

    def do_something_else_with_api_response(self):
        # just use self.response
        do_something_else(self.response)

您有缓存,任何需要此响应的方法都可以按任意顺序运行,而无需发出多个 api 请求,因为第一个需要 self.response 的方法将计算它,而其他每个方法都将使用缓存的值。希望很容易想象通过多个 URL 或 RPC 调用来扩展它。如果您需要很多缓存其返回值的方法,例如上面的响应,那么您应该为您的方法考虑一个记忆化装饰器。

This is an OO anti-pattern.

class API_Connection(object):
    def do_something_with_api_response(self, response):
        ...

    def do_something_else_with_api_response(self, response):
        ...

You have two methods on an instance and you're passing state between them explicitly? Why are these methods and not bare functions in a module?

Instead, think about using encapsulation to help you by having the instance of the class own the api response.

For example:

class API_Connection(object):
    def __init__(self, api_url):
        self._url = api_url
        self.cached_response = None

    @property
    def response(self):
        """Actually use the _url and get the response when needed."""
        if self._cached_response is None:
            # actually calculate self._cached_response by making our
            # remote call, etc
            self._cached_response = self._get_api_response(self._url)
        return self._cached_response

    def _get_api_response(self, api_param1, ...):
        """Make the request and return the api's response"""

    def do_something_with_api_response(self):
        # just use self.response
        do_something(self.response)

    def do_something_else_with_api_response(self):
        # just use self.response
        do_something_else(self.response)

You have caching and any method which needs this response can run in any order without making multiple api requests because the first method that needs self.response will calculate it and every other will use the cached value. Hopefully it's easy to imagine extending this with multiple URLs or RPC calls. If you have a need for a lot of methods that cache their return values like response above then you should look into a memoization decorator for your methods.

孤星 2024-12-07 20:22:06

缓存的响应应该保存在实例中,而不是像一袋彩虹糖一样传递——如果你把它掉了怎么办?

item_id 每个实例都是唯一的,还是一个实例可以查询多个实例?如果它可以有多个,我会采用这样的方法:

class A(object):

    def __init__(self):
        self._cache = dict()

    def a_method( item_id ):
        """Gets api_reponse from cache (cache may have to get a current response).
        """
        api_response = self._get_cached_response( item_id )
        ... #do stuff

    def b_method( item_id ):
        """'nother method (just for show)
        """
        api_response = self._get_cached_response( item_id )
        ... #do other stuff

    def _get_cached_response( self, item_id ):
        if item_id in self._cache:
            return self._cache[ item_id ]
        response = self._cache[ item_id ] = api_call( item_id, ... )
        return response

    def refresh_response( item_id ):
        if item_id in self._cache:
            del self._cache[ item_id ]
        self._get_cached_response( item_id )

如果您可能需要获取有关 item_id 的最新信息,您可以有一个 refresh_response方法。

The cached response should be saved in the instance, not passed around like a bag of Skittles -- what if you dropped it?

Is item_id unique per instance, or can an instance make queries for more than one? If it can have more than one, I'd go with something like this:

class A(object):

    def __init__(self):
        self._cache = dict()

    def a_method( item_id ):
        """Gets api_reponse from cache (cache may have to get a current response).
        """
        api_response = self._get_cached_response( item_id )
        ... #do stuff

    def b_method( item_id ):
        """'nother method (just for show)
        """
        api_response = self._get_cached_response( item_id )
        ... #do other stuff

    def _get_cached_response( self, item_id ):
        if item_id in self._cache:
            return self._cache[ item_id ]
        response = self._cache[ item_id ] = api_call( item_id, ... )
        return response

    def refresh_response( item_id ):
        if item_id in self._cache:
            del self._cache[ item_id ]
        self._get_cached_response( item_id )

And if you may have to get the most current info about item_id, you can have a refresh_response method.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文