用于类和子类的Python IsInstance()

时间:2018-05-17 00:24:43

标签: python class multiple-inheritance python-decorators

此代码来自python cook book第3版,来自类章节8.13。该程序尝试定义各种类型的数据结构,但希望对允许分配给某些属性的值强制执行约束。 我正在使用Pycharm IDE在python 2.7中执行该程序。

# Base class. Uses a descriptor to set a value
class Descriptor(object):
    def __init__(self, name=None, **opts):
        self.name = name
        for key, value in opts.items():
            setattr(self, key, value)

    def __set__(self, instance, value):
        instance.__dict__[self.name] = value

# Descriptor for enforcing types
class Typed(Descriptor):
    expected_type = type(None)
    def __set__(self, instance, value):
        if not isinstance(value, self.expected_type):
            raise TypeError('expected ' + str(self.expected_type))
        super(Typed,self).__set__(instance, value)

class Integer(Typed):
    expected_type = int

class String(Typed):
    expected_type = str

class MaxSized(Descriptor):
    def __init__(self, name=None, **opts):
        if 'size' not in opts:
            raise TypeError('missing size option')
        super(MaxSized,self).__init__(name, **opts)

    def __set__(self, instance, value):
        if len(value) >= self.size:
            raise ValueError('size must be < ' + str(self.size))
        super(MaxSized,self).__set__(instance, value)


class SizedString(String, MaxSized):
    pass

# Class decorator to apply constraints
def check_attributes(**kwargs):
    def decorate(cls):
        for key, value in kwargs.items():
            if isinstance(value, Descriptor):
                value.name = key
                setattr(cls, key, value)
            else:
                setattr(cls, key, value(key))
        return cls
    return decorate

# Example
@check_attributes(name=String,shares=Integer,place=SizedString('tester',size=8))
class Stock(object):
    def __init__(self, stkname, stkqty,stkhq):
        self.name = stkname
        self.shares = stkqty
        self.place = stkhq

使用以下初始化执行代码时

s = Stock('ACME', 50,'hky')
print s.name # print ACME
print s.shares # prints 50
print s.place # prints hky
  

条件:

在为@check_attributes place = SizedString(&#39; tester&#39;,size = 8)调试以下代码时,下面的 if 条件为True,其中至于 name = String and shares = Integer ,else条件为True。

       if isinstance(value, Descriptor):
            value.name = key
            setattr(cls, key, value)
        else:
            setattr(cls, key, value(key))
  

问题:

  1. 如果SizedString是Descriptor的一个实例(基于继承层次结构 - String,Typed,MaxSized,Descriptor),那么String和Integer也应该满足If条件吧?因为最后它也是(typed,Descriptor)的子类?

    1. setattr(cls,key,value(key))中的值(键)是什么意思,不能理解什么是值(键)意味着什么?
  2. 对于漫长的背景感到抱歉,但希望尽可能清楚。

1 个答案:

答案 0 :(得分:2)

  1.   

    如果SizedString是Descriptor的一个实例(基于继承层次结构 - String,Typed,MaxSized,Descriptor),那么String和Integer也应该满足If条件吗?因为最后它也是(typed,Descriptor)的子类?

    我们必须仔细查看传递给check_attributes函数的内容。仔细查看nameshare关键字参数的值是什么:

    @check_attributes(name=String,shares=Integer,place=SizedString('tester',size=8))
    

    注意StringInteger类名后缺少括号?这意味着StringInteger 类对象本身正在传递到check_attributes,而不是任何一个类的实例。由于String类对象和Integer类对象不是Descriptor的子类,isinstance(value, Descriptor)失败。

  2.   

    setattr(cls,key,value(key))中的值(键)是什么意思,不能理解什么是值(键)意味着什么?

    想一想。由于value具有传递给check_attributes的任何关键字参数的值,并且该值不是Descriptor类的实例,因此value必须引用类宾语。 (如果您不明白为什么会这样,请参阅我对您第一个问题的回答)。因此,调用value(key)正在创建某个类的实例,并将key值作为构造函数参数传递。