简体   繁体   中英

Classes in Python and defining the Type of Attributes

I'm new to Python and have a question about Classes and their attributes in Python 2.6.

Lets say I have a Class Node like this:

class Node:
    x = int
    y = int
    neighbours = []
    discovered = bool
    def __init__(self,x,y):
        self.x = x
        self.y = y

    def setNeigbours(self,neighbours):
        self.neighbours = neighbours

    def addNeighbours(self,n):
        if type(n) == list:
            self.neighbours.extend(n)
        else:
            self.neighbours.append(n)

    def isDiscovered(self):
        return self.discovered

    def setDiscovered(self,discovered):
        self.discovered = discovered

And a Class Graph like this:

class Graph:
    nodeList = Node
    edgeList = Edge

    def __init__(self,nodeList,edgeList):
        self.edgeList = edgeList
        self.nodeList = nodeList

    def getNodes(self):
        return self.nodeList

    def setNodes(self,nodeList):
        self.nodeList = nodeList

    def addNode(self,n):
        if type(n) == list:
            self.nodeList.extend(n)
        else:
            self.nodeList.append(n)

If I now create a new Graph and add some Nodes:

n1 = Node(0,0)
n2 = Node(1,1)
g = Graph([],[])
g.addNode(n1)
g.addNode(n2)

I would expect the following to print <Type 'Node'> :

for n in g.nodeList:
    print type(n)

But when I run it, I get:

<type 'instance'>
<type 'instance'>

Is there a way, to tell Python, that the nodeList , is a list, which only contains Node -Elements?

Indeed there is, provided you are using the latest version of Python (which at the time of writing is 3.6.0).

from typing import List

class Graph:
    nodeList: List[Node]

Python itself won't actually do anything with the information, but there are type-checking tools for Python which will perform a static analysis and tell you if you attempt to put something other than a Node in the list.

With older versions of Python 3 you can do something similar with a fomatted comment and the typechecking tools will then be able to do the same checks:

from typing import List

class Graph:
    nodeList  # type: List[Node]

All of this of course only provides optional static typechecking before you run the program. Once your code is running Python won't care at all about the types of objects so long as they have the right methods and attributes: if it quacks like a duck Python will treat it as a duck.

If you want to know more about optional static typechecking in Python see http://mypy-lang.org/

The fact that printing an instance of your Node type gives you <type 'instance'> indicates that you're using some version of Python 2. Please consider switching to a newer version if at all possible, but at the very least if you want to continue with Python 2 make sure that all of your objects explicitly derive from object :

class Node(object):
   ...

If you do that the print statement will show you the class. Failing to do this gives you old-style classes from the very early days of Python and you'll find things like properties don't work correctly with them.

None of this is how you write Python; it looks like Java instead.

You do not need to "declare" attributes at class level; the only reason to do that is to use values that are shared across all instances, which you are not doing because you immediately overwrite them with instance attributes. Remove those definitions.

It is also very unidiomatic to write getter and setter methods, especially if they just return the attribute. Your calling code should access the attributes directly.

As to your question, since you are using Python 2 [*] your classes must inherit from object. If you do that, you will see the correct types:

class Graph(object):
   ...

g = Graph()
type(g) # module.Graph

(*) note, you really really must not use 2.6; it is out of date and unsupported. If you are stuck on 2.x at least use 2.7; but really you should use 3.x, which apart from anything else fixes your original issue.

There's no way to enforce type in Python because Python is dynamically typed.

A possible solution is to check the instance type during the runtime.

First, inherit your class from object (ie 'new style' object):

class Node(object):
   # your code here

class Graph(object):
   # your code here

And then you can do a type checking during runtime:

>>> g = Graph()
>>> type(g)
<class '__main__.Graph'>
>>> isinstance(g, Graph)
True

Python is dynamically typed language. You do not need to declare variables before using them, or declare their type.

You can do stuff like this:

foo = 1 # this is an integer
foo = "string" # this is a string

Variable foo will have the type of the value stored in it.

In Python you can store different types of objects in the same list, if you want to enforce only one type to be stored you can subclass the builtin list class.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM