在红宝石中通过双splat传递空哈希

时间:2017-03-26 03:28:59

标签: ruby function hash kwargs splat

这个想法类似于你在python中使用装饰器所做的,我不知道该方法采用了什么参数,所以我传递* args,** kwargs作为一般情况

当我想将空哈希作为kwargs传递给不带参数的方法时出现问题

step

有趣的是,只有kwargs变量似乎是问题,因为:

class BaseServiceMeta(type):
    """ Metaclass that properly annotates the return value of the get_instance() method of
        any subclasses of the BaseService class.
    """
    def __new__(metaclass, classname, bases, classdict):
        cls = super(metaclass, metaclass).__new__(metaclass, classname, bases, classdict)
        if classname != 'BaseService':  # subclass?

            # define function with the correct return value annotation
            def get_instance() -> classname:
                return super(cls, cls).get_instance()  # call superclass classmethod

            setattr(cls, 'get_instance', get_instance)  # override inherited method

        return cls

class BaseService(metaclass=BaseServiceMeta):  # metaclass added
    instances = {}

    @classmethod
    def get_instance(cls) -> 'BaseService':
        if cls.instances.get(cls) is None:
            cls.instances[cls] = cls()
        return cls.instances[cls]

class Service1(BaseService):
    pass

class Service2(BaseService):
    pass

# show that the methods have the correct return annotation
print(repr(BaseService.get_instance.__annotations__['return']))  # -> 'BaseService'
print(repr(   Service1.get_instance.__annotations__['return']))  # -> 'Service1'
print(repr(   Service2.get_instance.__annotations__['return']))  # -> 'Service2'

# call subclass methods to show they return the correct singleton instance of each type
print(Service1.get_instance())  # -> <__main__.Service1 object at 0x004A07D0>
print(Service2.get_instance())  # -> <__main__.Service2 object at 0x004A07F0>
print(Service1.get_instance())  # -> <__main__.Service1 object at 0x004A07D0>

如果您可以建议一种方法将方法对象实际作为参数传递给函数,那也是完美的。

1 个答案:

答案 0 :(得分:2)

您无法将任意数量的参数传递给ruby方法,而无需在方法定义中声明它。仅传递*args是有效的,因为* args为空,它基本上就像你没有向方法传递任何参数,这就是my_method所期望的。使用kwargs,您将空哈希作为参数传递。由于声明该方法不带参数,因此会引发错误。

一般来说,在ruby中执行此操作的方法是这样的:

def my_method(*args, **kwargs)
  'I have run correctly'
end

如果ruby方法可以接受无限数量的参数或关键字参数,则需要在方法的定义中明确。

然而,更频繁地,你会看到这样的习语:

def my_method(arg, opts={})
  # do something
end

# Invoke the method like this:
# args == ['argument', 'another argument']
# opts == {opt1: 'val1', opt2: 'val2'}
my_method('some argument', opt1: 'val1', opt2: 'val2')

至于你对my_method *args, **kwargs采取与my_method *args, **{}不同的行为的观察......我首先要说的是,如果你的动机首先是学习Ruby,那么我会再次强调我的观点。 kwargs不是Ruby中常用的,至少与Python中使用的方式不同。

之后我会说这很奇怪。

我注意到:

[**kwargs] # => [{}]
[**{}] # => []
# And even more interesting:
[**{}.itself] # => [{}]

所以我说**kwargs时,解释器会抱怨,因为你将空哈希传递给一个不会引用任何参数的方法。但至于为何与**{}不同,我不确定。我现在正在挖掘,但我当前的怀疑是老实说,这是翻译的侥幸。没有理由认为这些应该被评估为不同,只是因为将两者分配给变量...

另外,双重运算符的采用并不是非常普遍,主要是因为偏好上述opts={}成语。此外,这不是许多在实践中遇到的用例。程序员必须显式地将空哈希传递给这样一个方法,当它们可以(无论是kwargs还是opts)只是省略了参数。所以是的......我认为这可能是翻译的侥幸。