アプリ版:「スタンプのみでお礼する」機能のリリースについて

Pythonでターミナルに文字を出力する命令を出せるprintが予約語でないのは何故ですか。予約語は予め役割を与えられた語を指すと思うのですが。

A 回答 (7件)

文字通りの回答は、すでにあるとおりですが、


おそらく、
print = "xxx"
~~~~
print("OK")
のようなコードを書いて、「何故 print = "xxx" の時点でエラーにしないのか?」と言うことかと思います。

print = "xxx" と書いた変数スコープの範囲内で、標準のprint関数を一切使わないのであれば、何の問題もありません。print という名前は abc などと同じく変数名として扱われます。
print ="xxx"
sys.stdout.write(print)
は全く正当なプログラムです。望ましい書き方かどうかは別の話。

「同じ名前を別の意味に使ってはいけない」というか「同じ名前なら同じ物として扱われる」(変数のスコープは考慮の上で)というだけです。

例えば address という変数名は「住所」なのか「メールアドレス」なのかどっちの意味で使っているか(あるいはそれ以外の意味)を全く意識しないでプログラムを書くと、「住所欄にメールアドレスが表示される!?」的なエラーが起こったり、変数に型のある言語だと、型の不一致のエラーが出たりするかと思いますが、それと同じレベルの話です。

上記のコードを
printx ="xxx"
sys.stdout.write(printx)
と書いたとすると、これは仮に「標準関数名は全て予約語」でも今は正しいプログラムです。が、今後のPythonのバージョンアップで printx という標準関数が増えた場合、printxも予約語になり、今まで正しかったエラーになってしまいます。こういう事を防ぐために、予約語は必要最低限にされています。

言語によっては、「今は何の意味も無い(書くとエラー)が、将来の言語仕様のバージョンアップで使うかも知れないので、今のうちから予約語にしておくので、これらの名前は使うな」という言語もあります。
JavaScriptだとこれ。
https://developer.mozilla.org/ja/docs/Web/JavaSc …

また、言語によっては予約語が一切無い言語もあります。構文で文法的キーワードなのか、変数名/関数名なのか判断します。有名どころではFortranがそうです。FortanやPI/Iといった昔の言語には予約語がないものがいくつかあります。
if(a) x=1 ・・・条件がaであるif文。真なら変数xに1が代入される
if(a) =1 ・・・ifという名前の配列変数の添え字aの箇所に1を代入
    • good
    • 0

面白い質問だわ。

マジで。
ただ、答えにくい質問で、

> 何故ですか。

って訊かれたら

「その言語の設計者がそう決めたから」

としか答えようがない質問の類、なのね。
つまり、実の事を言うと、

「予約語として何を含めるべきか」

と言う明解な指針、っつーか「理論」って別に無いんだよ。
とある言語Aの設計者が「何かを予約語に定めました」としても、別の言語Bの設計者が「それを予約語にしない」って事はあり得るし、あり得ていいわけ。
そして言っちゃえば、「予約語は必ず言語設計に必要なモノ」ってモンでもないんだ。
ハッキリ言えば、「ユーザーに対しての親切設計」って意味合いの方が強いんだな。

例えば、条件分岐構文としてif、って単語を利用しているプログラミング言語は多い。
ところが、例えばLispって言語だと、そういう「重要構文の一部」でさえ、ユーザーが勝手に「書き換えて良い」と言う自由を提供している。

[1]> (defparameter if 'hoge)
IF
[2]> if
HOGE
[3]>

これで、以降はこのインタプリタ上では、ifは「条件分岐」ではなくって、単にhogeを格納した変数、って事になっちまった。
もう僕らがifを「条件分岐」として使える事は、この時の「起動したインタプリタ上で」無くなっちまった。
ある意味「危険」だよな(笑)。そういう「危険」を許す言語もある。
これを避ける為に「構文で使われる単語は再定義させないようにしよう」と「親切で」予約語として設定してる「言語仕様」だとか「言語実装」が、あくまで「多い」と言う話なんだ。
それだけ。

でも実の事を言うと、予約語自体があろうがなかろうが、まずは「問題ない」ってのが原則なのね。
何故なら何らかを「再定義」したところで、それは貴方が書いたプログラム上の話、であって、実の事を言うと、何らかのインタプリタの「中身」とか、コンパイラの「中身」を書き換えたわけじゃない。結局、そのテの「言語処理系」を起動した時点で、その言語処理系は作成者が想定したように「初期化」される。この時点で、例えば上の例で言うと「ifは言語設計者が考えたように初期化」されるんで、結果何の問題も生じない、んだ(つまり、その後「プログラミング言語自体が」おかしくなる、って事はない)。
結果、予約語ってのは意味合いで言うと

「これらの単語を貴方が勝手に書き換えると、以降の貴方のプログラムはおかしな動作を始めますよ?」

って事で「親切心」で設定されたモノなんだ。
親切心がどこまでか、ってのはその言語の「設計者」自体にかかってるわけで、「こうすべきだ」って話じゃあないのね。

と言うわけで、貴方が考えるように、「標準ライブラリ内の関数に付いては再定義は許すべきじゃないんじゃないの?」ってのも考え方としては「アリ」なんだ。
Pythonはそこまでしねぇよ、ってだけの話でね。Pythonは「言語仕様がない」言語なんで、そのうちいきなり「貴方が考えてるように」printを予約語にするかもしんない。
でも現時点ではそうじゃない。だから例えば次のようなプログラムを書くのを許す。

>>> list = [1, 2, 3]
>>> list
[1, 2, 3]

これで関数listは単なる変数名になっちまった。
よって以降は、「この起動内」だと文字列をリストに変換する事が出来なくなる。

>>> list("hoge")
Traceback (most recent call last):
File "/usr/lib/python3.10/idlelib/run.py", line 578, in runcode
exec(code, self.locals)
File "<pyshell#2>", line 1, in <module>
TypeError: 'list' object is not callable
>>>

でもインタプリタを再起動すれば、問題はないわけ。

## 再起動後
>>> list("hoge")
['h', 'o', 'g', 'e']

Pythonの設計者は「これくらいは不具合でも何でもねぇだろ?」って思ってる、って事だな(笑)。だから予約語にしてないわけだ。

結果、例えば昨今の流行りで、「構文を書く単語を予約語にしよう」ってのも、「絶対そうせねばならない」わけじゃなくって、あくまで「凡例」とか「通例」なんだよ。
何かしらの「こうせねばアカン」っつー理論的な何かしら、があるわけじゃないんだ。
あくまで「とある言語での」その言語設計者が思い描く「やっちゃアカン事」に縛られてるわけだな。
繰り返すけど、なんかの理論的「根拠」があるわけじゃないんだ。
予約語はその言語設計者のアイディア次第で左右される、って事だ。
    • good
    • 0

予約語は言語仕様で定められているものです。


しかしprintは関数と言って標準ライブラリのひとつです。
構文解析の負荷を減らすためにそうなっていると思います。
    • good
    • 0

Cにもないですよ。

Javascriptにも無いです。Javaにも有りません。
今時標準出力を予約語にしてる言語はほぼなくなっています。

予約語というのは、予約語でないと表現出来ない言語の仕様に不可欠なものに付ける というのが今風です。ライブラリで実装出来るものには予約語は与えられません。不要な予約語が増えれば言語仕様が膨らみ、無駄に言語の実装が膨らむからです。

予約語は主に数式の表現とか制御構文とかに使われ、I/Oの呼び出しに使われることはありません。ライブラリを呼びだすだけです。
#大昔のFortranとかBasicとか、ライブラリがろくに使えなかった頃の言語にはI/O用の予約語が沢山有りました。
    • good
    • 1

解釈がちょっと違います。



コンピュータがプログラミング言語を解釈するとき「字句解析」というものが行われます。
これは、文法が正しいか、正しいならどんな構造をしているかを調べるものです。
https://docs.python.org/ja/3/reference/lexical_a …


この中で変数、関数、命令等の「名前」として解釈するべきものを「識別子」と言います。(あるいは「名前」とも言います)
識別子のうち、特別な意味として使うために他の用途では使えないように制限したものが「予約語」です。

例えば
if = 500
を許してしまうと、ifは変数になってしまうため「if文の始まりを表わる識別子」としては使えなくなります。

https://docs.python.org/ja/3/reference/lexical_a …


一方「定義済み」「組込み」と呼ばれる関数等があります。
これらは「字句解析」では他の識別子と同じ解釈で処理されます。
他の識別子との違いは、実行したときにそれが定義されているかどうかです。
Python3ではprintは「組込関数」になります。
https://docs.python.org/ja/3/whatsnew/2.6.html#p …
https://docs.python.org/ja/3/library/functions.h …

例えば

print("hello world")

というプログラムがあったとすると、実際には

def print(*objects, sep=' ', end='\n', file=None, flush=False):
  # 引数を解釈して出力するプログラム

print("hello world")

というプログラムが実行されている、という感じになります。
ユーザーには「自分用のprintが作れる」という利点があり、
開発者には「『print文』用の字句解析が不要になる」という利点があります。


なお、print関数は2.6で先行実装(従来のprint文と切り替え可能)、3.0から本格実装になりました。
それまでは printは「文」であり、予約語でした。
https://docs.python.org/2.7/reference/lexical_an …
    • good
    • 0

printは関数名です。

関数はprintのほかにたくさんあります。
(例 pow,abs,int,join等)
    • good
    • 0

printだけが特別なわけじゃなくて、rangeやlenなど事前に存在する関数も普通の変数と同じように、別の値に上書きができます。


同じスクリプト言語のJavaScriptも標準出力のconsole.log()もconsole=1と上書きができます。

しかし、Pythonならdefやpass、JavaScriptならfunctionやvarなど代入不可な単語はあります。

違いとしては、
・Pythonのdefやpass、JavaScriptのfunctionやvarという単語は文法に刻まれている
・print、range、len、consoleは文法に刻まれた単語ではなくあくまで標準機能として実装されているだけ

文法上意味のある単語(予約後)と、標準機能としてすでに存在している単語(予約語ではない)という違いがあります。
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人はこんなQ&Aも見ています


このQ&Aを見た人がよく見るQ&A