# why does menu_func() in this example reference a self when it is declared outside of a class

I'm learning bpy myself, and I don't have much knowledge of python。

I read the templates in text editor to learn scripting myself, but I found some thing weird in the Operator Mesh Add template:

import bpy
import bmesh

"""
This function takes inputs and returns vertex and face arrays.
no actual mesh data creation is done here.
"""

verts = [(+1.0, +1.0, -1.0),
(+1.0, -1.0, -1.0),
(-1.0, -1.0, -1.0),
(-1.0, +1.0, -1.0),
(+1.0, +1.0, +1.0),
(+1.0, -1.0, +1.0),
(-1.0, -1.0, +1.0),
(-1.0, +1.0, +1.0),
]

faces = [(0, 1, 2, 3),
(4, 7, 6, 5),
(0, 4, 5, 1),
(1, 5, 6, 2),
(2, 6, 7, 3),
(4, 0, 3, 7),
]

# apply size
for i, v in enumerate(verts):
verts[i] = v[0] * width, v[1] * depth, v[2] * height

return verts, faces

from bpy.props import FloatProperty, BoolProperty, FloatVectorProperty

bl_options = {'REGISTER', 'UNDO'}

width = FloatProperty(
name="Width",
description="Box Width",
min=0.01, max=100.0,
default=1.0,
)
height = FloatProperty(
name="Height",
description="Box Height",
min=0.01, max=100.0,
default=1.0,
)
depth = FloatProperty(
name="Depth",
description="Box Depth",
min=0.01, max=100.0,
default=1.0,
)

# generic transform props
view_align = BoolProperty(
name="Align to View",
default=False,
)
location = FloatVectorProperty(
name="Location",
subtype='TRANSLATION',
)
rotation = FloatVectorProperty(
name="Rotation",
subtype='EULER',
)

def execute(self, context):

self.height,
self.depth,
)

mesh = bpy.data.meshes.new("Box")

bm = bmesh.new()

for v_co in verts_loc:
bm.verts.new(v_co)

bm.verts.ensure_lookup_table()
for f_idx in faces:
bm.faces.new([bm.verts[i] for i in f_idx])

bm.to_mesh(mesh)
mesh.update()

# add the mesh as an object into the scene with this utility module
from bpy_extras import object_utils

return {'FINISHED'}

def register():

def unregister():

if __name__ == "__main__":
register()

# test call


self is used outside class indef menu_func(self, context):.

I was taught that self can only be used inside a class, so I'm confused.

Anyone can help me?

The answer lies in what happens in the register function, below the menu_func:

def register():


As you can see here, the menu_func is appended to the INFO_MT_mesh_add type as a new method. INFO_MT_mesh_add is the Add Mesh Menu in the blender UI.

This function is added to the Add Mesh Menu, and when you call it from the blender UI, it will be executed like any method. That means that it will get the class instance as the function's first parameter, "self".

The word "self" has no real meaning by itself, and is merely the first parameter this function receives. It is a convention in python (and some other languages) to call it "self", but you could call it "james" and it would work just fine.

When the function is a method in a class, it automatically gets the instance of the class as the first parameter when called from the instance (or the class itself if its a @classmethod, in which case we usually call the first parameter cls instead of self).

class someClass:
def myMethod( self ):
print( "I get the class instance as my first param 'self'" )
print( self )

clsInstance = someClass()
clsInstance.myMethod() # myMethod will get clsInstance as the first parameter


We could write it this way though, and it would work just the same:

def to_be_method( self ):
print( "I get the class instance as my first param 'self'" )
print( self )

class someClass:
# Reference to_be_method as our class' own myMethod
myMethod = to_be_method

clsInstance = someClass()
clsInstance.myMethod() # myMethod will get clsInstance as the first parameter


So as you can see in the example above, we define a function outside the class and used the "self" parameter, and then referenced this function inside the class.

Appending the menu_func into the INFO_MT_mesh_add class does something similar, which is why it's fine and works well.

I hope this explains the situation rather than confuse you even more! :)

The self argument in menu_func(self, context) could also have been written as:

def menu_func(caller, context):


The fact that it is written as self is a choice and a convention. The name isn't as important as the position of the arguments and the number of arguments in that function. Using self, context helps you and others see that it is being called from another place that does have a self and context.

### Why a menu_func at all?

Using a function like menu_func() allows us to describe a portion of the layout from our own add-on. If you couldn't specify it externally you would be forced to always edit your menu additions to INFO_MT_mesh_add manually, and each time you upgrade to a new version of Blender.

Let's say the draw function of INFO_MT_mesh_add looks like this:

def draw(self, context):
layout = self.layout

# in the registration function


For example if you use .append, you'll get your item at the end of the draw function, you might imagine that the code that python executed is equivalent to
def draw(self, context):

That means inside the draw function, the function menu_func is called with the self and context available to the drawing function at the time of calling.