【问题标题】:pythonic way to declare multiple class instance properties as numbers?pythonic方式将多个类实例属性声明为数字?
【发布时间】:2016-03-03 06:08:12
【问题描述】:

我有一个具有多个属性的类,每个属性都必须是一个数字。在一遍又一遍地重复相同的代码之后,我认为有一种更 Pythonic 的方式可以将多个类实例属性声明为数字。

现在我将每个属性值设置为 None,如果值设置为非数字类型,则会引发类型错误。我更喜欢在属性初始化时将属性类型设置为数字。

谢谢!

例子:

import numbers

class classWithNumbers(object):

    def __init__(self):
        self._numProp1 = None
        self._numProp2 = None

    @property
    def numProp1(self):
        return self._numProp1
    @numProp1.setter
    def numProp1(self,value):
        if not isinstance(value, numbers.Number): #repeated test for number
            raise TypeError("Must be number")

        self._numProp1 = value

    @property
    def numProp2(self):
        return self._numProp2
    @numProp2.setter
    def numProp(self,value):
        if not isinstance(value, numbers.Number):
            raise TypeError("Must be number")

        self._numProp2 = value

另外,我实际上已经将它封装到一个在每个属性设置器处重复的方法中:

def isNumber(value):
if not isinstance(value, numbers.Number):
    raise TypeError("Must be number")

【问题讨论】:

    标签: python types properties initialization


    【解决方案1】:

    如果这个类的每个属性应该是一个数字,你可以实现自定义__setattr__方法:

    class ClassWithNumbers(object):
    
        def __init__(self):
            self.num_prop1 = 0
            self.num_prop2 = 0
    
        def __setattr__(self, name, value):
            if not isinstance(value, numbers.Number):
                raise TypeError("Must be number")
            super(ClassWithNumbers, self).__setattr__(name, value)
    

    来自文档:__setattr__ (is) 在尝试进行属性分配时调用。这被称为而不是正常机制(即将值存储在实例字典中)。 name 是属性名称,value 是要分配给它的值。

    更一般的方法是不允许更改已分配属性的类型:

    class ClassWithUnchangeableTypes(object):
        def __init__(self):
            self.num_prop1 = 0
            self.num_prop2 = 0
    
        def __setattr__(self, name, value):
            if hasattr(self, name):  # this means that we assigned value in the past
                previous_value_type = type(getattr(self, name))
                if not isinstance(value, previous_value_type):
                    raise TypeError("Must be {}".format(previous_value_type))
            super(ClassWithUnchangeableTypes, self).__setattr__(name, value)
    

    说到pythonic,来自pep8:

    类名通常应使用 CapWords 约定。

    使用函数命名规则:单词小写,必要时用下划线分隔以提高可读性。

    【讨论】:

    • 这很有希望,我还不确定每个属性都是数字,但我可以抽象出非数字属性来实现它。另外,感谢命名约定参考!
    【解决方案2】:

    最 Pythonic 的方式可能是调用 int 构造函数并让它抛出异常:

    class ClassWithNumbers(object):
        def __init__(self, v1, v2):
            self.numprop1 = int(v1)
            self.numprop2 = int(v2)
    

    如果numprops 是您界面的一部分,那么创建@property 访问器将是合适的。你也可以实现自己的描述符:

    class Number(object):
        def __init__(self, val=0):
            self.__set__(self, val)
    
        def __get__(self, obj, cls=None):
            return self.val
    
        def __set__(self, obj, val):
            try:
                self.val = int(val)
            except ValueError as e:
                raise TypeError(str(e))
    
    class ClassWithNumbers(object):
        numprop1 = Number(42)
        numprop2 = Number(-1)
    

    用法:

    c = ClassWithNumbers()
    print c.numprop1
    c.numprop1 += 1
    print c.numprop1
    c.numprop1 = 'hello'
    

    【讨论】:

      【解决方案3】:

      一个相当现代(python 3.5+)和pythonic的方式是使用type hints

      @property
      def numProp1(self):
          return self._numProp1
      @numProp1.setter
      def numProp1(self,value: int):
          self._numProp1 = value
      

      一种更兼容的方法是尝试转换为 int,如果失败,它将为您抛出异常。它也可能有不受欢迎的行为,比如接受浮点数:

      @property
      def numProp1(self):
          return self._numProp1
      @numProp1.setter
      def numProp1(self,value):
          self._numProp1 = int(value)
      

      但总体而言,您的实现没有任何问题。 如果您不想显式声明 getter 和 setter,则可以在使用时检查它们的类型,而不是在分配时检查它们。

      【讨论】:

      • 感谢您的“提示”!我在 python 2.7.9 上。我曾考虑过转换,但更喜欢我的类型错误。我会多玩一点。谢谢!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-10-06
      • 2016-07-28
      • 1970-01-01
      • 2015-01-16
      • 2016-03-03
      • 1970-01-01
      • 2022-06-11
      相关资源
      最近更新 更多