如何在Python中创建强类型对象引用?

0 投票
2 回答
2486 浏览
提问于 2025-04-18 01:34

我刚开始接触Python 2.7。

我想在一个类和另一个类之间建立一种强类型的引用。

假设我有两个类:

class Module:
    count = 0

    def __init__(self, m_name, m_type, m_on=False):
        self.name  = m_name
        self.type = m_type
        self.on = m_on
        self.id  = self.count
        self.count += 1

还有一个叫做Slot的类,我想在里面放一个Module作为元素:

class Slot:
    count = 0

    def __init__(self):
        self.id  = self.count
        self.count += 1
        self.element = None

现在我想添加一个方法,用来设置这个Slot里的element,然后在其他方法中使用它(包括它的字段和方法),但我想确保这个元素是Module类型。

如果我能让PyCharm知道elementModule类型,那就更好了,这样它可以自动补全我输入的内容。

这可能吗?除了在初始化方法中这样做,我还能用其他方法让Python识别吗:

self.element = Module()

(如果我这样做,它会把element识别为Module类型,并且会自动补全)。

2 个回答

0

我想你说的是静态类型引用,而不是强类型引用。其实,Python 的引用是强类型的。

如果你想要静态类型,那 Python 可能不太适合你。

我也觉得这个说法没有什么特别的地方:

self.element = Module()

这只是创建了一个 Module 类的对象。而且,变量 'element' 的类型仍然是 Module 类,除非你明确地把它重新赋值为其他类型。

这和我们在 C++ 或 Java 中做的事情不太一样,但我认为这种灵活性让 Python 更加强大。

希望这些能帮到你。

1

正如haraprasadj所说,Python 不是静态类型的,所以你可能需要适应这种情况,并相应地编写代码。Python 和 Java 不一样。我是从 Java 转过来的,刚开始的时候我也花了一些时间来适应这些东西,但一旦你习惯了,你会发现 Java 的语法显得过于“挑剔”和繁琐(嗯……至少我现在是这么觉得的)。

说到这一点,使用新风格类(从object继承的类),你可以使用@property 装饰器来创建透明的获取器设置器(可以参考这个问题这个问题这个文档)。

在你的情况下,为了确保Slot类的element属性总是None或者是Module的实例,你可以这样做:

class Module(object):
    count = 0

    def __init__(self, m_name, m_type, m_on=False):
        self.name  = m_name
        self.type = m_type
        self.on = m_on
        self.id  = self.count
        self.count += 1

class Slot(object):
    count = 0

    def __init__(self):
        self.id  = self.count
        self.count += 1
        self.element = None

    @property
    def element(self):
        return self._element

    @element.setter
    def element(self, e):
      if not(e is None or isinstance(e, Module)):
          raise TypeError("Element must be None or Module")
      self._element = e

if __name__ == "__main__":
    s = Slot()
    m = Module('name', 'type')
    print "s.element? %s" % s.element
    s.element = m
    print "s.element? %s" % s.element
    # Now, exception:
    s.element = "hellouuuu"

这段代码的输出是:

s.element? None
s.element? <__main__.Module object at 0x26c9b10>
Traceback (most recent call last):
  File "./stack13.py", line 35, in <module>
    s.element = "hellouuuu"
  File "./stack13.py", line 25, in element
    raise TypeError("Element must be None or Module")
TypeError: Element must be None or Module

那么,这里发生了什么呢?当你创建一个Slot的实例(变量s),并尝试通过s.module = "whatever"给它的module属性赋值时,实际上调用的是s@element.setter方法,参数e的值是"whatever"。如果这个方法没有抛出异常,实际的属性会存储在s._module中。你可以使用vars(s)来查看这个类的实际属性(关于vars的更多信息可以参考这里):

>> s = Slot()
>> m = Module('name', 'type')
>> s.element = m
>> print "%s" % vars(s)
{'count': 1, 'id': 0, '_element': <__main__.Module object at 0x19d0b10>}

看到了吗?那里没有element,只有_element

现在,当你尝试读取element属性时,使用s.element,实际上是调用了用@property装饰的方法。

在我发的例子中,在那个方法里加一个print语句:

@property
def element(self):
    print "I'm reading self._element. Wohooo"
    return self._element

现在,重新执行脚本。你会在输出中看到:

I'm reading self._element. Wohooo
s.element? None
I'm reading self._element. Wohooo
s.element? <__main__.Module object at 0x1fd0ad0>
{'count': 1, 'id': 0, '_element': <__main__.Module object at 0x1fd0ad0>}
Traceback (most recent call last):
  File "./stack13.py", line 37, in <module>
    s.element = "hellouuuu"
  File "./stack13.py", line 26, in element
    raise TypeError("Element must be None or Module")
TypeError: Element must be None or Module

撰写回答