2012/05/12

for-inループについての補足

前の記事で最後に取り上げた「指定した数だけ球を量産する」というテーマについてです。

ここでは、作成されるオブジェクトの名前については最初は意識しないことにします。きっと何百個と作ったりしたら、名前ではなくせいぜい番号をつけるかどうかくらいのものだと思いますし…(^^;

さて、こんな感じにしてみました↓





import pymel.core as pm
import random

for i in range(5):
    pm.polySphere(r = random.random())
 


キモになっているのは、for-inの行の「range(5)」です。
5の部分に、作成したい球の個数を入力します。100でもいいですし、たぶんちょっと重たいですが1000とかでもOKです。

range()は、引数に入れた数字分の要素数を持ったリストを作成するコマンドです。
例えば


range(5)


これだけで実行すると、

# Result: [0, 1, 2, 3, 4] #

と返ってきます。要素が5個入ったリストですね。
※ちなみにリストかどうか調べるときは、type()を使います。
こんな感じ↓

type(range(5))

そうすると

# Result: <type 'list'> #

「こいつはリストですよ」と教えてくれます。リストにかぎらず何者かわからない時に使えます。

こんな感じで、必要な数だけ要素をもったリストをその場で作ってfor-inループに入れてやることで、指定した数の球を作らせています。
for i in range(5): の「変数 i 」はここでは使っていません。特にiでなくてもaでもxでも構いません。


しかし…

実行してみると、サイズはランダムとは言えすべてが原点に作られてしまうので、実用的ではありません。せっかくなので散らばってもらいましょう。
こうしてみました↓



import pymel.core as pm
import random

for i in range(100):
    pm.polySphere(r = random.random())
    pm.move ([random.uniform(-10,10), random.uniform(-10,10), random.uniform(-10,10)])



polySphere作成直後はそのオブジェクトを選択した状態になるため、そのままmoveコマンドで動かしてみました。
moveコマンドは、通常は、

move('なまえ',[TX,TY,TZ])

という風に、一つ目の引数に動かすオブジェクトの名前を必要とするのですが、名前を与えなかった場合は選択中のオブジェクトに対して実行されます。ですので、移動のための三値のリストだけで今回は大丈夫です。

また uniform() は、カッコ内の2つの引数の間でランダム値を生成してくれます。ここではTX,TY,TZとも-10~10の範囲にしていますので、実行するとざっくりと立方体な空間内に球が撒き散らされます。



もうちょっと粘ってみましょう。
ループとは別の話題になりますが、Outlinerを眺めてみると数字の桁が違っています。いくら名前を気にしないとはいえあまり気持ちのいいものではありませんね。
このあたりを調整してみたいと思います。



import pymel.core as pm
import random

basename = 'mySphere'

for i in range(100):
    pm.polySphere(n = (basename + str(i+1).rjust(4,'0')),r = random.random())
    pm.move ([random.uniform(0,10), random.uniform(0,10), random.uniform(0,10)])



例えばこんな感じ。
三行目の変数basenameで標準でない自分なりの名前にする準備。
for-inループ部分の一行目、polySphereのnフラグのところで色々しています。

問題のこの部分ですが↓

(basename + str(i+1).rjust(4,'0'))

まず出発点は、さきほどのbasenameと、for-inループ開始時に用意した 変数i をひっつけるところからはじめます。

basenam + i

しかしこのままではエラーになる気がします。iが文字ではないので文字に接続できないということが考えられます。iを文字に変えてしまいましょう。

str(i)

↑こうです。strは、melでも登場するstringの略ですね。str()コマンドは、引数に与えたものを文字列に変換してくれるものです。これで、iに代入される数字は文字列として扱われます。
これを組み込んで実行してみると、まだ問題があります。
range()でつくったリストをiへ入れ込んでいるので、開始が0なのです。これでは気分的にあれなので、悪あがきしてみます。

str(i + 1)

これで1から番号付け出来ます。
さてこの時点では、こんな感じの記述になっています↓

basename + str(i + 1)

あと気に入らないのはの問題です。
一度に千個とか作成することを考えると、四桁はほしいところです。つまり一個目なら0001、十個目は0010、百個目で0100、です。それっぽい言い方をすると、四桁のゼロパディングです。
ありがたいことに、pythonの文字列型には、このために用意されたと思われるコマンド(ここでは厳密にはメソッドですが…)が備わっています。それが、上記の例でも使っていたrjustです。

str(i+1).rjust(4,'0')

rjustを使うと、対象文字列を右詰めにして、指定した桁数分だけ指定した文字で埋めてくれます。
一つ目の引数が桁数で、ここでは。2つ目の引数が埋めるための文字で、ここでは0です。0以外で埋めることってあんまりないんじゃないかなと思います(笑
ここではもう数字ではなく文字列として扱っているため、0もクォートで囲んで文字列として記述しなければなりません。
ちなみに、rjustが右詰めにするためのもので、左詰め用にljustというのも用意されています。

そんなこんなで四桁のゼロパディングの準備も出来ましたので、以下のようにしてpolySphereの名前フラグに渡してあげます。

n = (basename + str(i+1).rjust(4,'0'))



実はこの部分、他にも書き方があります
文字列フォーマットという記述方法を使って、以下のように表現できます。

n = (basename + '%(#)04d'%{"#":i+1})

なんじゃこりゃあーという気分になりますが、これでさっきと同じような結果が得られます。より一層プログラムらしいというか、抽象度の高い書き方になっています。
応用的な内容で、より効率的に文字列を操ろうと思ったらこういう書き方もある、くらいに覚えておいていただければよいかと思います。





関連リンク

range (組み込み関数)

str (組み込み関数)

rjust(組み込み型文字列メソッド)

文字列フォーマット
 

0 件のコメント:

コメントを投稿