如何在Python中合并函数

0 投票
5 回答
570 浏览
提问于 2025-04-18 04:05

首先是代码:

class Api():
    def __init__(self, baseurl='http://localhost:8080/api'):
        self.base_url = baseurl

    def _makerequest(self, arguments):
        data = urllib.urlencode(arguments)
        req = urllib2.Request(self.base_url, data)            
        response = urllib2.urlopen(req)
        return response

    def getId(self, **kwargs):
        arguments = kwargs
        arguments['Type'] = 'getId'
        return self._makerequest(arguments)

    def getKey(self, **kwargs):
        arguments = kwargs
        arguments['Type'] = 'getKey'
        return self._makerequest(arguments)   

你可以看到,每个函数最终都会调用 _makerequest()。我这样写是为了有不同的函数(这样代码补全时会有提示),但又尽量减少代码的重复。

我想知道是否可以只用一个函数,但用不同的名字来调用它。例如,我可以调用 getId() 和 getKey(),但它们实际上会触发类里面的同一个函数。

有没有什么建议可以让这个过程更简单呢?

5 个回答

0

在Python中,函数和方法跟其他任何对象一样,名字是可以随意取的,甚至可以没有名字——比如返回值是一个函数,或者叫做匿名函数的lambda。给_makerequests一个类型参数,把重复的代码移出获取方法。

0

你可以使用装饰器。下面是一个简单的例子:

In [21]: def make_request(func):
    def _get_request(*args):
        print func(*args)
    return _get_request

In [26]: class Api(object):
    @make_request
    def hello(self, s):
        return 'Hello, '+s
    @make_request
    def goodbye(self, s):
        return 'Goodbye, '+s

In [27]: api = Api()

In [28]: api.hello('world')
Hello, world

In [29]: api.goodbye('world')
Goodbye, world
1

我觉得你反对的主要是你在每个API方法里都有一些重复的基础代码。

arguments = kwargs
arguments['Type'] = # Something

你能不能简单地这样做:

def _makerequest(self, rtype, **kwargs):
    kwargs['Type'] = rtype
    data = urllib.urlencode(kwargs)
    req = urllib2.Request(api.base_url, data)            
    response = urllib2.urlopen(req)
    return response

这样你就可以做到:

def getId(self, **kwargs):
    return self._makerequest('getId', **kwargs)
1

如果你真的想的话,可以直接使用 makerequest,不需要这些包装函数。如果你想让代码看起来更好看,可以这样做:

def get(self, type, **kwargs):
    arguments = kwargs
    arguments['Type'] = 'Get'+type
    return self.makerequest(arguments)

这样你就可以调用 get('Id', args) 或者 get('Key', args) 了。

0

这就是Python作为一种动态语言的优势所在——让这样的功能变得很简单。

class DynamicMethods(object):
   def __init__(self):
      pass

   class HiddenImplementation(object):
      ''' we create a separate implementation class that:
         1. stores the 'type' of the call (or whatever else you need to
           store on a per-call basis) 
         2. define a __call__() method that lets us perform whatever our 
         dynamic method call needs to do. In this example, we just print 
         the kwargs we're passed along with the call 'type'.
      '''  
      def __init__(self, typeName):
         self.typeName = typeName

      def __call__(self, **kwargs):
         args = kwargs
         args['type'] = self.typeName
         for k, v in args.items():
            print "{0}: {1}".format(k, v)



   def __getattr__(self, name):
     ''' any time code looks up an attribute that the class doesn't have 
        explicitly, this will be called. If the attribute being looked up
        starts with 'get', we create a HiddenImplementation object and 
        return that.
     '''
      if name.startswith('get'):
         return self.HiddenImplementation(name)


if __name__ == "__main__":
   d = DynamicMethods()
   d.getId(a=1, b=2, c=3)

...打印出

bgporter@varese ~/temp:python dynamicFn.py
a: 1
c: 3
b: 2
type: getId

撰写回答