Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pycharm Type-Hinting of Class Fields / Instance Variables

Whenever we need a new object in Java, we declare the type and the name choose to give it a initial value or not. In Python we can't do this, because we don't declare types.

How can I get around this because if the types are not declared; I am not getting any code completion hints. Like the fields of a particular object or any methods we can call on the object...

 class Album:
    def __init__(self, name, Photo, next):
        self.name = name
        self.Photo = None
        self.next = next

    def __str__(self):
        return "Album name is: " + self.name


class Photo:
    def __init__(self, name, caption, Tag, next):
        self.name = name
        self.caption = caption
        self.Tag = Tag
        self.next = next

    def __str__(self):
        return "Photo name is: " + self.name + " with caption: " + self.caption


class Tag:
    def __init__(self, type, info, next):
        self.name = type
        self.info = info
        self.next = next

    def __str__(self):
        return "Photo name is: " + self.name


def addPhoto(toEdit, photoName, caption):

   if isinstance(toEdit, Album):    
        if toEdit.Photo is None:
            toEdit.Photo = Photo(photoName, caption, None, None)    
        else:

            tempPhoto = toEdit.Photo
            prev = None
            isFound = False 
            while tempPhoto != None:

                if tempPhoto.name.lower() == photoName.lower():
                    isFound = True
                    break

                prev = tempPhoto
                tempPhoto = tempPhoto.next

            if isFound == False:
                prev.next = Photo(photoName, caption, None, None)

            else:
                print("Photo " + photoName + " already exists in " + toEdit.name)


def deletePhoto(toEdit, photoName): 
    if isinstance(toEdit, Album):
        if photoName in toEdit.Photo.name:
            if toEdit.Photo.next is not None:
                toEdit.Photo = toEdit.Photo.next
                return True

            else:
                toEdit.Photo = None
                return True
        else:
            Photo = toEdit.Photo.next
            Photo_prev = None

            while Photo is not None:
                if Photo.name in photoName:
                    prev.next = Photo.next

                prev = Photo
                Photo = Photo.next

        print("Removed photo: " + photoName + " from " + toEdit.name)

pPtr = album1.Photo  
while (pPtr != None):
    print(pPtr)
    pPtr = pPtr.next

So whenever I try to do pPtr = album1.Photo and then try to access any fields of that pPtr object I get no suggestions in PyCharm. I need to know whether I am doing this wrong or if PyCharm is at fault.

The implementation is one giant linkedlists. Albums nodes contain Photo nodes which contain Tag nodes

like image 750
indersingh Avatar asked Jul 10 '14 19:07

indersingh


People also ask

Are fields instance variables?

Fields - Instance Variables. Fields hold the data for an object. Fields record what an object needs to know to do work in the program. Fields are also called instance variables or object variables or properties.

How do you write a hint variable in Python?

Here's how you can add type hints to our function: Add a colon and a data type after each function parameter. Add an arrow ( -> ) and a data type after the function to specify the return data type.

What is or are the instance variables in this class?

Instance Variable: It is basically a class variable without a static modifier and is usually shared by all class instances. Across different objects, these variables can have different values.


1 Answers

First off, as one of the commenters on your question pointed out, using upper_case variable names confuses them with Classes/Types. If you look at your question, you'll see it even confused the Stackoverflow code-formatter.

Additionally, in your Album constructor, you are masking the global variable "Photo" with a local parameter. That might confuse PyCharm, especially when you do the following. So for my answer + test below, I renamed your parameter to a lower-case photo so that it doesn't interfere.

**Edit: ** I did find a better way. See "The Right Way".

First Attempt

class Album:
    def __init__(self, name, photo, next):
        self.name = name
        self.photo = self.get_photo(photo)
        self.next = next

    def get_photo(self, photo):
        """
        @rtype: Photo
        """
        return photo

    def __str__(self):
        return "Album name is: " + self.name

The way it works is it uses the PyCharm type-inference. See here for details on how it works.

And below a screenshot of it working:

Image of answer working

Note: I do not recommmend doing this, as it is a hack. I came across your question as I'm attempting to find out if there is a better way of doing this in PyCharm.

The Right Way

The right way of doing this is to give PyCharm the type of the variables in the constructor. Essentially, moving the type-binding from the method as above, and into the constructor as part of the docstring entry "type".

class Album:
    def __init__(self, name, photo, next):
        """
        @type name: str
        @type photo: Photo
        @type next: str
        """
        self.name = name
        self.photo = photo
        self.next = next

    def __str__(self):
        return "Album name is: " + self.name


class Photo:
    def __init__(self, name, caption, Tag, next):
        self.name = name
        self.caption = caption
        self.Tag = Tag
        self.next = next

photo1 = Photo("name.txt", "caption", "tag", "next")

album1 = Album("TestAlbum", photo1, "next")

album1.photo.#code completion working here
like image 61
Zoran Pavlovic Avatar answered Oct 18 '22 00:10

Zoran Pavlovic