如何强制/确保类属性是特定类型?

发布于 2021-01-29 19:33:00

如何在Python中将类成员变量限制为特定类型?


较长版本:

我有一个具有多个成员变量的类,这些成员变量在该类的外部设置。由于它们的使用方式,它们必须为特定类型,即int或list。

如果这是C ++,则只需将它们设为私有,然后在“
set”函数中进行类型检查。鉴于这是不可能的,是否有任何方法可以限制变量的类型,以便在为其分配了错误类型的值时在运行时发生错误/异常?还是我需要在使用它们的每个函数中检查它们的类型?

关注者
0
被浏览
51
1 个回答
  • 面试哥
    面试哥 2021-01-29
    为面试而生,有面试问题,就找面试哥。

    您可以像其他答案一样使用属性-因此,如果您想约束单个属性,例如说“ bar”,并将其约束为整数,则可以编写如下代码:

    class Foo(object):
        def _get_bar(self):
            return self.__bar
        def _set_bar(self, value):
            if not isinstance(value, int):
                raise TypeError("bar must be set to an integer")
            self.__bar = value
        bar = property(_get_bar, _set_bar)
    

    这有效:

    >>> f = Foo()
    >>> f.bar = 3
    >>> f.bar
    3
    >>> f.bar = "three"
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "<stdin>", line 6, in _set_bar
    TypeError: bar must be set to an integer
    >>>
    

    (还有一种新的属性编写方法,使用内置的“属性”作为getter方法的装饰器-但我更喜欢旧方法,就像我上面提到的那样)。

    当然,如果您的类具有很多属性,并希望以这种方式保护所有属性,那么它就会变得冗长。不用担心-
    Python的自省功能允许创建一个类装饰器,该装饰器可以用最少的行自动实现。

    def getter_setter_gen(name, type_):
        def getter(self):
            return getattr(self, "__" + name)
        def setter(self, value):
            if not isinstance(value, type_):
                raise TypeError(f"{name} attribute must be set to an instance of {type_}")
            setattr(self, "__" + name, value)
        return property(getter, setter)
    
    def auto_attr_check(cls):
        new_dct = {}
        for key, value in cls.__dict__.items():
            if isinstance(value, type):
                value = getter_setter_gen(key, value)
            new_dct[key] = value
        # Creates a new class, using the modified dictionary as the class dict:
        return type(cls)(cls.__name__, cls.__bases__, new_dct)
    

    然后,您仅用auto_attr_check作类装饰器,并在类主体中声明要与属性也需要约束的类型相等的属性:

    ...     
    ... @auto_attr_check
    ... class Foo(object):
    ...     bar = int
    ...     baz = str
    ...     bam = float
    ... 
    >>> f = Foo()
    >>> f.bar = 5; f.baz = "hello"; f.bam = 5.0
    >>> f.bar = "hello"
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "<stdin>", line 6, in setter
    TypeError: bar attribute must be set to an instance of <type 'int'>
    >>> f.baz = 5
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "<stdin>", line 6, in setter
    TypeError: baz attribute must be set to an instance of <type 'str'>
    >>> f.bam = 3 + 2j
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "<stdin>", line 6, in setter
    TypeError: bam attribute must be set to an instance of <type 'float'>
    >>>
    


知识点
面圈网VIP题库

面圈网VIP题库全新上线,海量真题题库资源。 90大类考试,超10万份考试真题开放下载啦

去下载看看