2017-04-12 68 views
0

this回答它显示为属性传递给类__init__Python 2.7:使用setattr设置所有args/kwargs属性是否很好?

例如,kwargs/ARGS如何自动设置,我们可以这样做:

class Employee(object): 
    def __init__(self, *initial_data, **kwargs): 
     # EDIT 
     self._allowed_attrs = ['name', 'surname', 'salary', 'address', 'phone', 'mail'] 

     for dictionary in initial_data: 
      for key in dictionary: 
       if key in self._allowed_attrs: # EDIT 
        setattr(self, key, dictionary[key]) 
     for key in kwargs: 
      if key in self._allowed_attrs: # EDIT 
       setattr(self, key, kwargs[key]) 

在我来说,我已经提前知道论点我将通过,所以我正在考虑这个解决方案只有一个较少的重复和较短的代码。

这是否被认为是良好做法? 这是针对手动初始化每个属性的解决方案的赞成/反对?还有其他更好的方法吗?由于第一条评论/回答(正确)侧重于清理参数或列出参数,我认为在这个框架中可以很容易地解决这个问题。

+1

从[的Python禅](https://www.python.org/dev/peps/pep -0020 /):'显式优于隐式.'。你需要调用者将'* args'绑定到字典中。 – AChampion

+0

感谢您的评论,但我想我会反对'美丽胜于丑陋'和'可读性计数'。 25行'self.something = kwargs ['something']'对我来说看起来并不漂亮或不可读,但这显然是个人的品味 – FLab

+0

我不同意可读性,我会指出'稀疏比密集好','难以解释“等。总的来说,我不会赞成这种做法。 – AChampion

回答

0

之前讨论:Python decorator to automatically define __init__ variablesPython: Is it a good idea to dynamically create variables?

优点:

  • 减少代码重复

缺点:

1

它使我们无法弄清楚该类预期的参数类型。

如果某人(或您在几个月的时间内)想要在他们的代码中创建Employee,他们会查看构造函数的参数以查看他们应该传递什么(可能手动或者IDE自动显示他们)。你的代码除了隐藏它之外几乎没有什么用处。

0

完全可以使用语言自省功能来减少重复和键入你必须做的事情。

当然,这是更好,如果你正在服用注意正确处理的属性,甚至是消毒的内容 - 所以最好的办法是要么为__init__方法的装饰,或者它的碱基相当于类__init__,它将完成所需的任何操作:检查传递的参数对于特定类是否正常,然后使用setattr在实例内设置它们的值。

我认为不太神奇的方法是在您的类层次结构中有一个约定,以将所需参数声明为类属性。 通过这种方式,您可以使用这些类属性来记录预期参数及其类型,并将__init__签名保留为*args, **kwargs,并让您的基类init将其全部处理。

SQLAlchemy Base模型可以做到这一点 - 您可以将类属性指定为特殊的“检测属性”,并在__init__中调用时自动分配它们。

一个更简单的方法是:

_sentinel = object() 

class Base(object): 
    def __init__(self, *args, **kwargs): 
     for attr_name, class_attr in self.__class__.__dict__.items(): 
      if isinstance(class_attr, type) and kwargs.get(attr_name, _sentinel) != _sentinel: 
       attr_value = kwargs[attr_name] 
       if not isinstance(attr_value, class_attr): 
        raise TypeError("Parameter {} is expected to be of type {}".format(attr_name, class_attr)) 
       setattr(self, attr_name, attr_value) 


class Person(Base): 
    name = str 
    age = int 
    phonenumber = Phone 
    ... 

这就要求所有的参数以班级为命名的参数传递 - 但他们都将被自动分配给实例的属性,它会工作,是有稽和安全。如果你想变得更好,只需定义一些奇特的描述符类作为你的类属性值。

3

问题:......少重复和更短的代码

你的示例代码的需求,9号线和28个关键词

class Employee(object): 
    def __init__(self, name, surname, salary, address, phone, mail): 
     self.name = name 
     self.surname = surename 
     self.salary = salary 
     self.address = address 
     self.phone = phone 
     self.mail = mail 

这个默认的一个需求,6号线和19个关键词。 总结,您的示例需要更多不是“较短的代码”。 我看不到任何“重复...代码”在默认的一个,所有的作业完成一次

比较这两条线,做同样的事情。控制哪些ARGS可以通过:

self._allowed_attrs = ['name', 'surname', 'salary', 'address', 'phone', 'mail'] 

def __init__(self, name, surname, salary, address, phone, mail): 

第二个需要较少的努力,并做尽在其中。
不需要if key in self._allowed_attrs:,因为python会为你做。


在实际项目中,我会用这样的

class Employee(object): 
    def __init__(self, person, salary=None): 
     self.id = unique_id() 
     self.person = person 
     self.salary = salary 

所有person相关数据都在object person进行了总结。


结论
为您给出的例子class Employee我永远不会使用(*args, **kwargs)
(*args, **kwargs)如果无法预测哪些参数已通过,则参数仅有用。

相关问题