py5coding / py5book

juypter book repo for py5
https://py5coding.org/
64 stars 10 forks source link

Composite Objects #6

Closed marziabil closed 2 years ago

marziabil commented 2 years ago

Hi,

I wish to make a file with composite objects. Hence, I have a main file which contains objects of different classes (face, eyes, eyebrows etc) - the end product being an emoji.

Here's the link to my code: https://github.com/marziabil/emojis/tree/py5-test

However, I get this error in VS Code every time I run the main file:

AttributeError: 'Face' object has no attribute '_instance'

Is there any solution to this since I want all the objects to be a part of the main class.

Thanks in advance!

hx2A commented 2 years ago

Hi @marziabil ! Thanks for giving py5 a try.

I looked at your code and I see you are programming py5 in class mode. With class mode, you are able to run multiple Sketches at the same time, each in its own window.

There are two things I notice about your code. First, when programming in class mode, if you create a class and define an __init__() method, you need to make a call to super().__init__(). For example, in https://github.com/marziabil/emojis/blob/py5-test/face.py, you should change the __init__() method to:

    def __init__(self, faceColour):
        super().__init__()  # <=== add this line
        # self.xValence = xValence #x coordinate of emotion - valence
        # self.yArousal = yArousal #y coordinate of emotion - arousal
        self.faceColour = faceColour

The need to do this may not be properly documented. If that's the case, let me know and we will fix that.

This is the error message you should see when a Sketch has this issue:

RuntimeError: py5 internal problem: did you create a class with an `__init__()` method without a call to `super().__init__()`?

I tried to make an error message that pointed people in the right direction.

This isn't the error message you are getting though. In the file https://github.com/marziabil/emojis/blob/py5-test/main.py, you are programming in module mode but then instantiating instances of Face, Eyes, Mouth, etc, each its own Sketch instance, and then calling their draw methods directly. I would expect this to give the error message you are receiving about a missing _instance attribute.

To help I would like to better understand what you are trying to do. Is it important to your project that you have each of the Face, Eyes, Mouth, etc, in its own Sketch instance? Do you need to run each component separately from the others? If not, you can simplify things by drawing each of the components in their own functions. For example, in eyes.py, you could write:

import py5

def xSthaped():
        py5.stroke(0)
        py5.stroke_weight(6) #upper half of x and thinner part
        py5.line(45,75,65,85)
        py5.stroke_weight(8) #upper half of x and thicker part
        py5.line(65,85,85,95)
        py5.stroke_weight(8) #lower half of x and thicker part
        py5.line(65,105, 85, 95)
        py5.stroke_weight(6) #lower half of x and thinner part
        py5.line(45, 115, 65, 105)

# create functions for other eye types...

def draw_eyes(eyeType):
    if eyeType == "xShaped":
        xShaped()  
    elif eyeType == "oval":
        valEyes()
    # etc...

Then in main.py you could have:

import py5

from eyes import draw_eyes

eyeType = "wideOpenEyes"

def draw():
    draw_eyes(eyeType)
    # draw other parts of face

py5.run_sketch()

This approach would let you divide up each part of the face into its own file. Everything would be programmed in module mode. Does this make sense? If not, let me know and I'll do more to help.

marziabil commented 2 years ago

Thank you for the detailed explanation! That worked 😊

I'll try importing simpful now and seeing how things work. And yes, the part about super().init() isn't mentioned anywhere else.

hx2A commented 2 years ago

Awesome, I am glad it is now working for you!

And yes, the part about super().init() isn't mentioned anywhere else.

OK, good to know. I'll add it to the descriptions of the py5 modes. In addition, @marcovicci and @tabreturn are working on creating beginner tutorials that include a page for object oriented programming (creating classes, aka using py5 in class mode). We'll be sure to mention that when programming in class mode, if your class implements __init__() you need to make a call to super().__init__() so that the parent __init__() method gets called.

Have fun coding in py5!