You can join Blender Studio for €11.50/month and get access to all of our training & film content instantly!
Login Join Blender StudioVideos
Aug. 16th, 2017
info License: CC-BYLearn about Collections in this video. Not only do we look more at lists, we also use dictionaries in order to automatically mass-rename objects in the scene, and tuples to assign to multiple names at the same time.
Slides are only visible to Blender Cloud susbcribers
Join to comment publicly.
38 comments
thank you, Sybren, for the suggestion (around 16:50) of using
continue
to avoid extra conditions and indenting. as an inexperienced python coder, this sounds like something that should be followed in all one's code. to this end, for anyone else struggling with the meaning ofcontinue
, what it really means in plain English is that the code will stop executing the current iteration of the loop and go back to the top of the loop process and move on to the next iteration, socontinue
means continue with the whole loop operation, rather than continue with this iteration. i found this very confusing at first.I love how with every video, your beard gets bushier
Hmm, at 7.11'' I am confused by 'suflen'. How was this defined, I see that it was hard coded to 2 chars earlier. Is it a python function like 'len'?
@3pointedit: its defined in the code, suflen = len(suffix) so it should contain the length of what is in suffix. eg if suffix contain '_R' the suflen will equal 2 Hope I'm getting you question correct :)
@Stefan59: Oh I see, does this mean that anything in a string after an underscore "_" is recognized as a suffix function? So "suffix" is a python tool? And is "some_name" also a python function as it doesn't get defined anywhere? I guess that it is a wildcard?
@3pointedit: Nope, i'm not great at explaining things so I hope you can understand. The suffix is a variable the script defines, it can be anything. In the tutorial suffix is computered to be either R_ or L_ as thats what we want to move, but really it can be any name or length. len(suffix) command just mean grab the length of suffix, adding suflen = len(suffix) defines suflen for the first time and gives it the value of the length of suffix, tutorial it is always 2 because R_ and L_ have the length of 2. You may need to do some python tutorials before try to understand python in blender, it will help. Steve
@3pointedit:
some_name
is defined, it's the name of the first parameter of therename
function.Whatever you pass as first parameter, it'll get the name
some_name
. For example, if you would callrename("steve", "L_")
, it would act as if you had saidsome_name="steve"
andsuffix="L_"
.@Stefan59: Thank you for your patience :-) I think that I will have to rewatch some more times. How does the script calculate that the suffix (which is only a variable with no fixed length) is 2 characters long? Does it read the underscore or are you defining the suffix in ob.name?
@3pointedit: There is less magic involved than that, the underscore is nothing special. This type of programming is called "imperative programming", which means that you tell the computer "do this, then do this, then do this". This means that
len(suffix)
is executed when the computer runs that bit of code. It doesn't matter thatsuffix
can have different lengths at different times. The result oflen(suffix)
now is the length ofsuffix
now. Try toying around with it in the interactive Python console.@3pointedit: (5 minutes into tutorial) the function is defined
def rename(some_name, suffix):
and gets it value when calledob.name = rename(name, '_R')
so
name
is passed tosome_name
and'_R'
is passed tosuffix
@Stefan59: Thank you, I guess I am getting lost on the order of operations/definitions?
Even after check python doc about tuples, I'm confuse about this line:
base_name, suffix = name[:-suflen], name[-suflen:]
I don't understand how the hell
base_name
find its value, and where is storedname[-suflen:]
. In fact I just understand the part withsuffix = name[:-suflen]
:)@vinc3r: Erf OK I got it, after relistening! (not native english speaker here).
I was thinking that
suffix = name[:-suflen]
but not!For whose wondering:
base_name, suffix = name[:-suflen], name[-suflen:]
is equal to
base_name = name[:-suflen]
andsuffix = name[-suflen:]
Am i right ?
@vinc3r: You're right,
a, b = c, d
is the same asa = c
andb = d
.The added benefit of the former is that it also works when
(c, d)
is returned from a function, so then you can doa, b = function_returning_c_and_d()
.I load some objs, then hope to add "test" for each cube name, in the scene, I code like that.
for ob in bpy.data.objects: ob.name = 'test' + ob.name
but it not work, eg cube001 change name 'testtesttesttestcube001" etc it added multiple "test" about each obj. I understand, something wrong, but could you teach me clear?
@fun2tax: This is quite subtle. It happens because you're modifying the
bpy.data.objects
collection while you're looping over it. Internally Blender uses the object name to put the object into that collection. Since you're changing the keys, you're changing the collection itself, which causes objects to be visited more than once.You can solve this by first creating a dictionary of new names, and then loop over that to give each object its new name:
This way you do not change
bpy.data.objects
in the first loop, and you do not changenew_names
in the second loop.So I check list, in python doc, then change , as same as you did. for name, ob in bpy.data.objects.items():
ob.name = 'test_' + ob.name
it worked but the 'name' should be ob.name, is not it? actually even though I simply use name = 'test_' + name, all cube change name .
@sybren: thanks to take your time. I will try again your discribed code.
@sybren: Thanks I could understand better. so to chane obj.name in same loop need to use items()?
<code>for name, obj in bpy.data.objects.items(): if obj.location.x < 0: obj.name = 'Left_' + obj.name else: obj.name = 'Right_' +obj.name</code>
@fun2tax: My point is that you do not want to use one loop. Loop 1: given the object, figure out its new name. Loop 2: given the new names, assign them to the objects. Combining those in a single loop is not possible, as you should not modify the collection you're looping over.
@sybren: Thanks, one thing I still can not understand is, why I can change key values when I use "items()"? <quote>for ob_name, ob in bpy.data.objects.items(): ob.name = "aaa_" + ob.name</quote>
this code seems work for me. but it not recommended?
or I can use values(), and keys() in spite of items()
but
directly change bpy.data.objects collection keys , in this loop, then it can not work?
Have blender 2.79 current build change about it? because, now it seems work , even though I use
when I test same thing in 2.79 rc2, it actually added many "aaa_" about same objects . but I may prefer your recommend way, which make new dictionary for new name, then use two loop without change collection in one loop. thanks.
@fun2tax: Doing something the correct way is always preferrable to "it seems to work in this particular version of Blender" ;-)
@sybren: I could understand why it may cause problem by your answer. I just need to make it as habit, dividing 2 loop. ;-)
my rename and flip script, even after copy pasting from the slides does not seem to work, it changes the name but one of the objects out of two has a .001 at the end of of it, meaning that it changed the name of .l object into .R first but since .R object already existed blender added a .001 next to it, then it moves on the .R into .L and that seems to work. But the objects dont flip at all! and somehow this is working in your demonstration!.
@Pranavjit Virdi: ohkay sorry, so the script that i was refferring to at 13:02 works only if the names of the objects are not the same, meaning that it would work if you have a cube_L and sphere_R but it would not work if you have Cube_L and Cube_R, huh interesting, since the flip name solutions before that in the video seemed to work without error on just that scenario.
@Pranavjit Virdi: In such cases having an intermediary name can help out. For example, first you rename
Cube_L
→Cube_L_becomes_R
andCube_R
→Cube_R_becomes_L
. Then rename them again,Cube_L_becomes_R
→Cube_R
andCube_R_becomes_L
→Cube_L
. Then you're sure that you don't get any naming collissions.@Sybren A. Stüvel: _L_becomes_R is way more characters than suflen 2 which is already predefined, so i made it _E and _W (for east and west) but now it changes them to _E and _W only and i have to run the script another time for the _E to change to _L(which is what it was in the first place). another thing, even if i change the other object to have a different name the flipping of location doesn't work.
@Pranavjit Virdi: alright the flipping does work now(i am often amazed at my stupidity, the objects i tested were spread along the y axis instead of the x axis.) the rest of the prob still stands.
@Pranavjit Virdi: k it works... here is the code if anyone wants to see it.
@Pranavjit Virdi: wow i just realized you addressed this issue in the video completely, i had paused the video before that point and didn't bother to see the whole thing through, hehe.
Thanks for those amazing videos! I have a question about bones. I'd like to get the info of all currently selected bones and use an array to store their names, so I can then change them. Is there a way to do that using Python? Thanks!
Can someone help me out with why this code isn't working? I have a loop creating 20 Suzannes:
Okay, markdown doesn't seem to like the { character in the code above (at least in the preview window) and is adding
*@Peter Smith* Well at least use
f 'Suzanne.R.{index+1:03}'
;-)bpy.ops.mesh.primitive_monkey_add()
creates a new monkey every time, so Blender will just keep making new ones. Since they are all in the same blend file, they have to have a unique name.*@Sybren A. Stüvel* Thanks for the reply, but I don't think I was clear in my original question about what my issue is. The script deletes every object in the scene before then creating 20 monkey objects. The monkeys are renamed at object level (
ob.name = str(f...
) and that part works fine.But when I then try to set the mesh data name to be the same as the object name (
ob.data.name = ob.name
) it doesn't work. It works the first time I run the script when I open Blender (i.e. in a new Blender session). But every time I run it after that the mesh data doesn't take the name of the object data. Instead, the mesh numbers are incremented, so by the time I've run the script a few times I end up with objects named e.g. Suzanne.R.001 but with mesh name Suzanne.R.240.I don't get why that should be the case when the script deletes all the objects before recreating them? Is Blender somehow not "flushing out" the mesh data names when objects are deleted?
*@Peter Smith* You're right, take a look at
bpy.data.meshes
. It does not remove those when you remove the objects. If you want to remove a mesh, usebpy.data.meshes.remove(the_mesh)
.BTW, the
str()
call is unnecessary, asf"..."
is already a string.*@Sybren A. Stüvel* Cool, thanks for the reply, and thanks for the Python tip!