# Can't get the active_object in Operator

I try to get the active object by "bpy.context.scene.objects.active" in my operator, but I receive a error 'Context' object has no attribute 'objects', what's wrong?My scripts is as follow:

import bpy
from bpy.props import *

cube=bpy.data.objects["Cube"]

class HelloError(bpy.types.Operator):
bl_idname = "object.hello_error"
bl_label = "HelloError"
bl_options={'REGISTER','UNDO'}

my_property= BoolProperty(name="my_property", default=True)
def execute(self, context):
print("--------------------------------")
if self.my_property:
print("do something......")

#set the active object as a existed cube
bpy.context.scene.objects.active =cube
print("objects:",bpy.context.scene.objects)
print("cur_active:",bpy.context.scene.objects.active.name)
return {'FINISHED'}
def register():
bpy.utils.register_class(HelloError)
def unregister():
bpy.utils.unregister_class(HelloError)
if __name__ == "__main__":
register()


And the blender The file will be uploaded soon(It seems that the website"https://blend-exchange.giantcowfilms.com/"cannot be accessed now in my computer, i will upload the file once it is accessible)

You need to be aware that Blender, when changing such custom properties, internally runs an undo step, and then re-executes the script. The trouble with your script is that you define the content of the variable cube right in the __main__ area of your script. This means it is only run once when the script registers. When the undo->redo happens, this can get lost. In fact, when I just copy-paste your code into a new file, run the script, run the operator and toggle the property, the pasted script disappears (pasting it is also undone in the undo step).

To fix it, get the cube while executing. It could also make sense to get it in the invoke() function, but let's keep it simple for now. So try this modified script instead:

import bpy
from bpy.props import BoolProperty

class HelloError(bpy.types.Operator):
bl_idname = "object.hello_error"
bl_label = "HelloError"
bl_options={'REGISTER','UNDO'}

my_property= BoolProperty(name="my_property", default=True)
def execute(self, context):
print("--------------------------------")
if self.my_property:
print("do something......")

# get desired object within execute() function instead!!
# also, retrieve it from the current scene objects,
# this ensures it exists within the scene and can be set active
cube = context.scene.objects.get("Cube")

#set the active object as a existed cube
context.scene.objects.active =cube
print("objects:", context.scene.objects)
print("cur_active:", context.scene.objects.active.name)
return {'FINISHED'}

def register():
bpy.utils.register_class(HelloError)

def unregister():
bpy.utils.unregister_class(HelloError)

if __name__ == "__main__":
register()


I've done a few other style modifications to it, namely using the context variable that is passed into the execute() method instead of constantly grabbing it from bpy.context, and using context.blend_data instead of bpy.data (a call which I removed later on, see next paragraph).

Finally, batFINGER pointed out in a comment that it is recommended to pull the cube object from context.scene.objects instead of context.blend_data.objects, as this will make sure the cube is already linked to the scene, and later on can be set as active object. Using the get() method, the variable will be set to None if there is no object named Cube, instead of throwing an error immediately. You could later on use a sanity check like:

        if not cube:
return{'CANCELLED'}

• Recommend cube = context.scene.objects.get("Cube") to ensure it is linked to the scene. (or link it if it isn't) Dec 9, 2018 at 3:46
• @batFINGER thanks for pointing this out, I've updated the answer accordingly. Dec 9, 2018 at 8:40
• @aliasguru Just a question as I am not a programmer but wouldn't context.active_object = cube be more effective as it is compatible in blender 2.79 and 2.8 which does not appear to translate scene.objects.active?
– Ratt
Dec 9, 2018 at 10:44
• @Ratt Both context.active_object as well as the shorter form context.object are read-only properties, which cannot be set. So traversing through context.scene.objects.active in 2.79 and context.view_layer.objects.active in 2.80 is the feasible way at the moment. Dec 9, 2018 at 11:25