• 締切済み

python:関数が複数globalを読むロジック

cametan_42の回答

回答No.5

う〜む、これはだな・・・・・・。 最初に言っておく。実は直感的な話を言うと # 出力 # Hello Jiro, Hello Jiro. になるのが「正しい」。 繰り返すが、「マトモなレキシカルスコープを持つ」プログラミング言語だと全部同様の結果になる。 // JavaScriptの例 default_name = "Ichiro"; function kyodai1(name = default_name) { return `Hello ${name},`; } function kyodai2(name = null) { if (name === null) { name = default_name; } return `Hello ${name}.`; } default_name = "Jiro"; console.log(`${kyodai1()} ${kyodai2()}`); これも出力はJiro Jiroだ。 いくらファイルの冒頭でdefault_name = "Ichiro";と定義されていても実行直前でdefault_nameが"Jiro"と書き換えられている以上、実行時に参照するdefault_nameは"Jiro"になる。 他のレキシカルスコープ採用の(しかもキーワード引数アリの)言語で試しても同じ結果になるだろう。 レキシカルスコープは別名「字句的スコープ」と言う。「書いた通りにスコープが決定する」と言う意味だ。 つまり、他のスコーピングのシステムに比べると「悩む必要がない」設計になっている。直感的に判断が可能だ。 一方、Pythonは「一応」レキシカルスコープ採用、って言って良い言語だが、実はその実装は極めて不完全なんだ。 んで、だ。 どこからこの問題を持ってきた? この問題は、普遍的なレキシカルスコープの挙動を問うてる問題じゃなくって、実の事を言うと「Pythonのバグ地味た挙動」を問うてる問題なんだ。 問題は、Pythonのスコープの問題ではなくって、「Pythonの関数定義に於いてのキーワード引数の挙動の不審さ」の問題なんだ。 従って、 > Tutolialで該当箇所がわからずにいます はこれ、だ。 4.8.1. デフォルトの引数値: https://docs.python.org/ja/3/tutorial/controlflow.html#default-argument-values つまり、kyodai1の定義時にdefault_nameが"Ichiro"だった為、一旦それを評価した以上「そこから変わらない」と言うバグ地味た挙動が他の「マトモなレキシカルスコープを持った言語」と違う挙動をする原因になってる(これは全然何も得がない、んだ)。 そして、「こういうスタイルでPythonでプログラムしたらダメ」なんだよ。 ダメなプログラムを出して、つまり、重箱の隅をつつくような出題をする、ってのがPythonの「資格試験」の特徴なんだけど、まさしくそのテの問題だと思う。 Pythonにキーワード引数に大域変数で定義したデフォルト値を与えちゃいけない、んだ。この例のように「思わぬ挙動を引き起こす」場合がある、ってこった。 (もっとも「Pythonの危険性を知る」にはいい問題かもしれんが・・・・・・苦笑) プログラミング言語に於いては、この、Pythonのように「実装者のポカ」が影響を与える場合がある。 従って、 > このロジックを3つのAIにコードを読ませて説明させた 極論、「ロジック」じゃねぇんだよ。「実装者がそういう実装をしちまった」以上に理由がない場合がしばしばある。 従って、「資格試験対策」を考えるなら、「ロジックを考える」んじゃなくって「暗記対策」しかあり得ないわけだ。 「重箱の隅をつつく」問題が出る以上、そこには「普遍的な(レキシカルスコープ採用言語に於いての)プログラミングに於いてのお約束」を問うてるわけじゃないんで、当然「暗記での対策」になっちまうわけだ。 Pythonは比較的、「どこを取っても論理的で整然としてる」言語じゃないんだ(もっとも言っちゃうと、かなりの確率でどの言語も「理論的にはどっか破綻してはいるが・・・「人が設計してる以上しょうがない」が)。

ketae
質問者

お礼

実際AIにコードを読ませたあと、実行させると Hello Jiro, Hello Jiro. と出したのがあったので、pythonではない言語の振る舞いではそうなるかなと昨日思っていました 同時にAIはglobal変数の多用は勧めないともいうので、これは問題集上の問題だなと思います ありがとうございます

関連するQ&A

  • python: nonlocalとglobal文

    pythonで次のような関数の書き方がチュートリアル本に書かれていました ------------------------------------------- スコープと名前空間の例 def scope(): loc = "abc" def do_local(): loc = "local" def do_nonlocal(): nonlocal loc loc = "nonlocal" def do_global(): global loc loc = "global" ------------------------------------------- VS Codeでブレークポイントを置き走らせ、 nonlocal loc → loc = "nonlocal" global loc →loc = "global" の代入(バインディング?)が起こることはわかりました チュートリアル本では、nonlocalとglobalは次のように書かれています 説明文 nonlocal文 その変数が自分を取り囲むスコープにある global文 その変数がグローバルスコープにある 質問; 上の2行(説明文)の 1)nonlocal文 その変数が自分を取り囲むスコープにある 2)global文 その変数がグローバルスコープにある これらのスコープが何、どこ、どのように、指しているか教えてください また 3)これらと名前空間の関係をわかりやすく教えてください (本ではわからず) 【回答上のご注意】 回答は、解答(答え)を求めています わたしはプログラマーではないので、昭和的な「自分で考えろ」的なものは求めていません わからなければ答えない自由もあなたにはあります 不明点があれば説明いたします

  • pythonの問題を解くのを助けていただきたいです

    スペースが2つ以上ある場合スペースを一つだけにする、そして文の最初と最後にスペースがあった場合そのスペースを消すというコードをこのコードをベースに書き換えていただくことは可能でしょうか? def removeExtraSpaces(theString): outSt = "" foundExtraSpaces = False for ch in theString: if ch = " ": foundExtraSpaces = True elif foundExtraSpaces == True: outSt += ch return outSt print(removeExtraSpaces(" Hello Joe ")) #この場合”Hello Joe”と出力されるはずです。

  • pythonの関数内での関数の定義について

    Python Cookbook 3rd の2章6節の内容でわからないことがあります。 コード import re #サンプルテキスト text = 'UPPER PYTHON, lower python, Mixed Python' #正規表現で文字のケースに合わせて置換する def matchcase(word) .....def replace(m): ..........text = m.group() ..........if text.isupper(): ...............return word.upper() ..........elif text.islower() ...............return word.lower() ..........elif text[0].isupper(): ...............return word.capitalize() ..........else: ..............return word .....return replace #実行分 re.sub('python', matches('snake'), text, flags=re.IGNORECASE) #実行結果 >>>'UPPER SNAKE, lower snake, Mixed Snake' このサンプルコードのmatchcase内のreplace関数に引数を渡していないと思うのですが、どのような仕組みでこのコードは動いているのでしょうか? m.group()とあるので実行分のre.sub(...)でのマッチしたという情報がreplace(m)のmに渡されているだろうとは思うのですが、なぜ引数を指定せずにそのようなことが起こるのかが理解できません。 何卒よろしくお願いします。

  • VBAからPythonを動かしたいのですが…

    いつもお世話になっております。 icevainと申します。 python超初心者です。 【質問】 『VBAでPythonを動かす』という興味のあるサイトを見つけました。 https://qiita.com/O_LUPAN/items/1ceb5c950ff40f3558ab サイトのpythonコード #ここから import sys def sum(suji1, suji2): return suji1 + suji2 if __name__ == "__main__": argv = sys.argv suji1 = str(argv[1]) suji2 = str(argv[2]) total = sum(suji1, suji2) print(total) #ここまで サイトのpythonコードを無理やり変更して、 #ここから import sys def sum(suji1, suji2): rst="OK" return rst if __name__ == "__main__": argv = sys.argv suji1 = str(argv[1]) suji2 = str(argv[2]) total = sum(suji1, suji2) print(total) #ここまで OKがかえってくると思ったのですが、 0がかえってきてしまいます。 OKをかえすにはどうすればよいのかわかりません。 お分かりの方おりましたらご協力お願い致します。

  • python print文のエラーがでます

    #!/usr/bin/env python # -*- coding: utf-8 -*- from __future__ import print_function import datetime class TZ(datetime.tzinfo): def __init__(self, name, offset): self.name = name self.offset = offset def utcoffset(self, dt): return datetime.timedelta(hours=self.offset) def tzname(self, dt): return self.name def dst(self, dt): return datetime.timedelta(0) def main(): path = '/sys/bus/w1/devices/28-000*********/w1_slave' with open(path) as f: data = f.read() temp = float(data[data.index('t=')+2:])/1000 FMT = '{},{:.1f}' JST = TZ('JST', 9) now = datetime.datetime.now(JST) print(FMT.format(now.strftime("%Y/%m/%d %H:%M:%S"), temp)) if __name__ == '__main__': main()
 とうってじっこうすると print(FMT.format(now.strftime("%Y/%m/%d %H:%M:%S"), temp)) の部分に SyntaxError: invalid syntax とエラーがでます。 どういうことなのか教えていただけるとうれしいです!

  • python: def関数での記述arg=

    python: def関数での()記述内にarg=を書く意味と働き pythonで、defで関数定義をする際、引数を並べるやり方は理解したのですが、arg = と記述する意味ができずにいます 図のAでは実行すると100を出力します 5行目 f(arg = i)の ”arg =” の文法というか、これがはたしている役割がよくわかりません ためしにBのように arg= を撤去して、引数をiたった1つにすると9行目でエラーになります ( f(i)とするとエラーにならない) Cがエラー出ない理由もわかります 質問: 1) Bにおいて、5行目で arg = の果たしている役割を教えてください 2) Bにおいて9行目でf()では関数を呼び出せていないのは、arg = の不在と関係あると想像できますが、そのロジックを教えてください 【回答上のご注意】 回答は、解答(答え)を求めています わたしはプログラマーではないので、昭和的な「自分で考えろ」的なものは求めていません わからなければ答えない自由もあなたにはあります 不明点があれば説明いたします

  • Pythonでのプログラミングについて。

    Pythonでのプログラミングについて。 大学の授業でPythonが出たのですが、なんせ先生が適当すぎてさっぱり意味がわかりません・・; 以下の問題の答えか、もしくは解説してくれる方はいらっしゃいませんでしょうか。 Q1:オレンジの数(count)を受け取って、"Number of oranges:<count>"を返すorange関数(a)を書け。 ただし、countが10以上の場合は実際の値のかわりに"many"を使え。 def orange(count): (a) return str print orange(4) print orange(99) Q2:文字列を受け取って、最初と最後の各2文字から作成した文字列を返すboth_ends関数(b)を書け。 ただし、文字列の長さが1のときは空文字列を返せ。 def both_ends(coun): (b) return str print both_end("hello") print both_end("a") Q3:文字列を反転するプログラム(c)を書け。 orig="hello" (c) print result Q4:文字列を反転するreverse関数(d)を書け。 (d) orig="good" result=reverse(orig) print result Q5:キーボードから受け取った文字列が回文(palindrome)かどうか判定するプログラム(e)を書け。 (d) orig=raw_input("Type a phrease:") result=reverse(orig) (e) Type a phrease:alice reverse=ecila Type a phrease:anna **palindrome** 自分で本を読んだり色々調べてみたのですが、判りませんでした。。 今日の12時までなのですが、誰かお願いします(;_;)

  • Array.sortメソッドのデフォルト比較関数

    JavaScriptのArray.sortメソッドは、 引数を指定しなければデフォルトの比較関数でソートされますが、 この比較関数を取り出して利用できないでしょうか。 要件は、プロパティ[name]と[value]を持ったオブジェクトの配列のソートです。 nameプロパティは半角英数字の文字列で、これをキーにソートしたいと考えています。 ソートの基準は、Array.sortのデフォルトと同じです。 つまり、こんなコードを想定しています。 var ary = [o1, o2, o3]; // o1~o3はそれぞれ上記のオブジェクト ary.sort(function(a, b){ return compare(a.name, b.name); }); このコードにおけるcompare関数を、Array.sortのデフォルト比較関数にしたいのですが、 これは自前で作成するしかないのでしょうか。 数値だけでなく文字列全般の比較になるので、結構実装が面倒そうなのですが、 自作する場合に何か使えそうな標準関数等、無いでしょうか。 今のところ思いついているのは、下記みたいなものです。 var compare = function(a, b) {  var temp = [a, b];  temp = temp.sort();  return temp[0] === a ? -1 : 1; } 比較関数内で更にArray.sortを呼んで2項目をソートし、 順番が入れ替わったかどうかを判定するだけです。 何だか冗長で気持ち悪いコードですので、代案を探しています。

  • Pythonにて不明な部分

    あるPythonコードからの抽出です。 Synset = namedtuple('Synset', 'synset pos name src') def getSynset(synset): print synset x = "select * from synset where synset='" + synset + "';" print x cur = conn.execute(x) return Synset(*cur.fetchone()) このgetSynsetを呼んだ時に、どのような内容が返されるか分かりません。 特に *cur の"*"は機能は何でしょうか。Cならポインタが指す内容ですが、Pythonにポインタは無いと思います。

  • pythonで実体参照文字を直す方法

    pythonで以下のコードを使って実体参照、文字参照を直しているのですが「~」 など特定の文字がうまく直されませんどういうことでしょうか? python2.7です。 下のコードで4&#xFF5E;6&#x4EBA;を直すと46人になる。 文字参照とか実体参照とかhtmlentitydefsの使い方も詳しく分かってません。 その辺も総合して教えていただけるとありがたいです。 def sansyounaosi(text): # 正規表現のコンパイル reference_regex = re.compile(u'&(#x?[0-9a-f]+|[a-z]+);', re.IGNORECASE) num16_regex = re.compile(u'#x\d+', re.IGNORECASE) num10_regex = re.compile(u'#\d+', re.IGNORECASE) result = u'' g = 0 while True: # 実体参照 or 文字参照を見つける match = reference_regex.search(text, g) if match is None: result += text[g:] break result += text[g:match.start()] g = match.end() name = match.group(1) # 実体参照 if name in htmlentitydefs.name2codepoint.keys(): result += unichr(htmlentitydefs.name2codepoint[name]) # 文字参照 elif num16_regex.match(name): # 16進数 result += unichr(int(u'0'+name[1:], 16)) elif num10_regex.match(name): # 10進数 result += unichr(int(name[1:])) return result