2017-10-04 202 views
0

我正在开发一些初始化函数/方法,如果默认值用于kwargs,它应该会发出警告 。我不能 找出如何做到这一点,谷歌也没有帮助我。 任何解决方案?如何使用默认关键字参数在函数调用中检查

为了说明

class MyClass(): 
    def __init__(a=0,b=1): 
     ''' Should warn you if using default.''' 
     self._a = a 
     self._b = b 

应该采取行动如下

MyClass(a=1) 
>>> 'warning: default b=1 is used. 

一个为什么要警告:Defualts有没有说明使用的典型值。但是最终用户应该设置它们而不是懒惰(!)。最终用户使用kwargs操纵yamls:如果他/她弄糟了,让最终用户意识到。基本上我需要args的(软)要求以及kwargs的所有好处。

+1

你能解释为什么你需要警告有关违约?如果它们是默认值,我认为该函数应该正常运行而不会发出警告。 – noel

+1

如果有人呼叫'MyClass(0,1)',是否应该有警告? –

+0

那么..用户意识总是一件好事,如果用户知道如果没有特别定义,使用特定的默认值看起来非常有趣。 这也可以用于第二个值如果没有指定,基于第一个参数值改变的情况.. –

回答

1

使用kwargs__init__的警告,然后一个专用initialize函数变量的赋值:

class MyClass(): 
    def __init__(self, **kwargs): 
     defaults = dict(a=0, b=1) 
     for key,val in defaults.items(): 
      if key not in kwargs: 
       print("warning: default {}={} is used.".format(key, val)) 
      kwargs[key]=val 

     self.initialize(**kwargs) 

    def initialize(self, a=0, b=1): 
     self._a = a 
     self._b = b 

MyClass() 
print('-'*50) 
MyClass(a=5) 
print('-'*50) 
MyClass(a=4,b=3) 

输出是:

warning: default b=1 is used. 
warning: default a=0 is used. 
-------------------------------------------------- 
warning: default b=1 is used. 
-------------------------------------------------- 
+0

谢谢!这听起来像一个很好的一般方法。有点冗长的默认值的双重定义,但这是你在语言中可能无法做到的事情。 – balletpiraat

3

你可以做什么:

class MyClass(object): 
    def __init__(self, **kwargs): 
     if not 'b' in kwargs: 
      print "warning" 
     self._a = kwargs.get('a', 0) 
     self._b = kwargs.get('b', 1) 

该代码使用提取存储在该键的值的字典的“获取”功能(即第一个参数),如果该键不存在,第二个参数是“默认”值的后备。

不知道这是否有一些帮助?

Python 2.7 "get" function for a dictionary


更新

因为从库恩的答案是非常有趣的,我想进一步推:

class MyClass(object): 

    def __init__(self, **kwargs): 
     defaults = dict(a=0, b=1) 
     for key, value in defaults.iteritems(): 
      if not key in kwargs: 
       print "Warning: default {0}={1} is used.".format(key, value) 
      kwargs.setdefault(key, value) 
     self.__dict__.update(kwargs) 

m = MyClass() 
print "a: {0}; b: {1}".format(m.a, m.b) 
print "-"*30 

m = MyClass(a=10) 
print "a: {0}; b: {1}".format(m.a, m.b) 
print "-"*30 

m = MyClass(a=10, b=11) 
print "a: {0}; b: {1}".format(m.a, m.b) 
print "-"*30 

这种方式,您可以有两个主要的优点:

  • 您的属性列表将直接添加到类中作为参数,以便您可以访问它。
  • setdefault方法提取值,如果密钥存在,并且如果不是简单地添加具有指定的默认值的密钥。

据我所知,这个代码可以是在非受控环境非常危险,所以你最终可以为您的类更复杂的结构回退,使用方法:

  • __getattr__(self, attributename)为根据定义的名称提取属性值,以便您可以将所有值保存在本地变量(如self.classparameters或
  • __setattr__(self, attributename, attributevalue))中以设置值。

这是代码:

class MyClass(object): 

    def __init__(self, **kwargs): 
     defaults = dict(a=0, b=1) 
     for key, value in defaults.iteritems(): 
      if not key in kwargs: 
       print "Warning: default {0}={1} is used.".format(key, value) 
      kwargs.setdefault(key, value) 
     self.__dict__.update(kwargs) 

    def __getattr__(self, parameter): 
     return self.__dict__.get(parameter) 

    def __setattr__(self, parameter, value): 
     self.__dict__.update({parameter: value}) 

m = MyClass() 
m.b = 11 
print "a: {0}; b: {1}".format(m.a, m.b) 
print "-"*30 

m = MyClass(a=10) 
m.b = 101 
print "a: {0}; b: {1}".format(m.a, m.b) 
print "-"*30 

m = MyClass(a=10, b=11) 
m.b = 1001 
print "a: {0}; b: {1}".format(m.a, m.b) 
print "-"*30 

这是一件需要非常小心地手持,因为你可以(而且会)在多个场合一些严重的问题。

警告:这是如何使用__setattr____getattr__的解释,反而是接近与多种解决方案相同的问题一个简单的(和愚蠢)的方式,因此,如果你知道如何改进此位用更智能的方式使用那些魔术方法,不客气。


实施这一过程的另一种方式,这可能是更冗长,但可让您有发生什么控制的大量使用装饰@property:

class MyClass(object): 

    def __init__(self, **kwargs): 
     self.classparam = dict(a=0, b=1) 
     for key, value in self.classparam.iteritems(): 
      if not key in kwargs: 
       print "Warning: default {0}={1} is used.".format(key, value) 
      kwargs.setdefault(key, value) 
     self.classparam.update(kwargs) 

    @property 
    def a(self): 
     return self.classparam.get('a') 

    @a.setter 
    def a(self, value): 
     self.classparam.update(a=value) 

    @property 
    def b(self): 
     return self.classparam.get('b') 

    @b.setter 
    def b(self, value): 
     self.classparam.update(b=value) 

m = MyClass() 
m.b = 10 
print "a: {0}; b: {1}".format(m.a, m.b) 
print "-"*30 

m = MyClass(a=10) 
m.b = 100 
print "a: {0}; b: {1}".format(m.a, m.b) 
print "-"*30 

m = MyClass(a=10, b=11) 
m.b = 1000 
print "a: {0}; b: {1}".format(m.a, m.b) 
print "-"*30 
+0

我喜欢这个解决方案!这非常重要。对于少数几个kwargs会很好。 ThomasKühn的答案将用于更一般的情况。 – balletpiraat

+0

谢谢你提出另一个鼓舞人心的建议。我以前不知道setdefault方法!看到我的答案,我最终想出了什么。 – balletpiraat

+0

@balletpiraat,不客气!其实你启发我的一些改进,我的工作流程中的参数检查:) –

0

我终于想出了 - 与同事的帮助 - 就是使用一个类属性来存储默认值:

举例说明:

class MySpecialClass(): 

    default_kwargs = dict(a=0,b=0) 

    def __init__(self,kwargs): 

     _kwargs = do_something(kwargs,self.default_kwargs) 

     self.a = _kwargs['a'] 
     ... some more unpacking ... 

instance = MySpecialClass({'a':0}) 
>>> some effect 

其中do_something()填补丢失的钥匙/引发警告等

对我来说,这所有我想要的:

  • 明确有关默认值
  • 简单,不使用未明显语言特征
  • 明确拆包 - 如果还是缺少些什么,你得到一个错误。
  • 灵活/清洁通过do_something()
  • 更多?
+0

mmh ..你仍然可以使用'** kwargs',因为你使用它的方式并不明显,但总是需要一个参数传递给构造函数。使用'** kwargs'会发生什么情况是让构造函数(或任何其他函数或方法)将参数传递为'MyClass(a = 12,b ='asd')'这可能是一种更为pythonic的方式一个更全面的方式来处理一个对象。 –

相关问题