2012-03-17 11 views
8

属性アクセスの構文上の制限は(少なくともCPythonと2.7.2の実装では)Pythonで、あります:属性名をPythonキーワードにできないのはなぜですか?

>>> class C(object): pass 
>>> o = C() 
>>> o.x = 123 # Works 
>>> o.if = 123 
    o.if = 123 
    ^
SyntaxError: invalid syntax 

私の質問は二つです:

  1. は、根本的な理由がありますなぜPythonのキーワード属性名(o.if = 123のように)を使用することは禁じられていますか?
  2. 上記の属性名の制限は文書化されていますか?

それは感覚が私のプログラムの一つで、o.class = …を行うことになるだろう、と私はそれを行うことができていない少しがっかりしています(o.class_働くだろうが、それはのように単純では見えません)。

PS:明らかに、ifclassはPythonのキーワードです。質問はです。なぜならというキーワードを属性名として使用することは禁じられています(私はo.class = 123の式にあいまいさはありません)。と記載されているかどうかです。

+3

キーワードは常にキーワードでありコンテキストではない場合、パーサーが簡単であるためです。だから、コードは属性アクセスがあるところまで到達していないので、構文解析レベルの構文エラーです( 'if'は文法の一部であり、決してこの場所には現れません)。ほとんどの言語で同じですが、そのための文法は言語文法です。 –

+2

また、 'cls'は通常、クラスへの参照を保持する名前に使用されます。 –

+0

キーワードを変数/関数名と区別できるパーサーがあっても、コーナーケースでは他のものをシャドーすることはできません。あなたが数十の名前の使用を禁止するだけで真実を維持するのはずっと簡単です。 –

答えて

7

setattrgetattrを使用することができますがキーワードです文のレベルではなく、式の中にあるときの識別子 - ifの場合はX if C else Yのため二重になり、リストの補完とジェネレータの式ではforが使用されます)。

したがって、属性アクセスのポイントに到達しないコードは、誤ったインデントと同様にパーサによって拒否されます(SyntaxErrorで、AttributeErrorなどではありません)。属性名、変数名、関数名、または型名としてifを使用するかどうかは区別されません。パーサーは常に "キーワード"ラベルを割り当てて、それを識別子とは異なるトークンにするだけで、これは識別子になることはありません。

ほとんどの言語で同じですが、言語文法(+ lexer specification)がそのドキュメントです。 Language spec mentions it explicitly。また、あなたはあなたにべきを意味するものではありません、予約名を持つ属性を作成するsetattrまたは__dict__を使用することができるという理由だけで、また、Pythonの3に

は変更されません。自然な属性アクセスの代わりに自分/ APIユーザーにgetattrを使用させないでください。 getattrは、変数属性名へのアクセスが必要な場合に予約する必要があります。

+1

教師がコンパイラクラスで教えてくれるのはそうです。これは、コンパイラが古典的に構築される方法です。トークンは分割され、カテゴリに分類され、パーサによって意味があるかどうか分析されます。 +や:のような特別なシンボルはすべて、( "if"、 "or"、 "class"、 "def"など)独自の(ユニタリ)カテゴリとすべての予約語を持ちます。他のすべての単語は特別なカテゴリに属します:識別子。 "if"は識別子ではないので、単純な属性に名前を付けることはできません。私はコンパイラ/コードアナライザを他の方法で構築することは不可能ではないと言っているわけではありません。ちょうどこれが最近行われていることです... – lvella

+0

@Ivella:非常に関連性の高いコメントです。 – EOL

+0

@CatPlusPlus: 'getattr'と' __dict__'について合意しました。通常のobject.attribute構文では禁じられているにもかかわらず、属性名がキーワードになることが示されているので、これらを言及しています。 – EOL

1

ifはキーワードです。あなたはo.whileo.forと同様の問題を持っている:Pythonで

pax> python 
>>> class C(object): pass 
... 

>>> o = C() 

>>> o.not_a_keyword = 123 

>>> o.if = 123 
    File "<stdin>", line 1 
    o.if = 123 
    ^
SyntaxError: invalid syntax 

>>> o.while = 123 
    File "<stdin>", line 1 
    o.while = 123 
     ^
SyntaxError: invalid syntax 

>>> o.for = 123 
    File "<stdin>", line 1 
    o.for = 123 
     ^
SyntaxError: invalid syntax 

他のキーワードを用いて得ることができる:

あなたは ないは、一般的にPythonで変数名としてキーワードを使用する必要があります
>>> import keyword 
>>> keyword.kwlist 
['and', 'as', 'assert', 'break', 'class', 'continue', 'def', 
'del', 'elif', 'else', 'except', 'exec', 'finally', 'for', 
'from', 'global', 'if', 'import', 'in', 'is', 'lambda', 
'not', 'or', 'pass', 'print', 'raise', 'return', 'try', 
'while', 'with', 'yield'] 

インターフェイスの場合はiface、入力フィールドの場合はinfldなど、わかりやすい名前を選択することをおすすめします。

については、なぜキーワードが許可されていないのかを編集すると、字句要素がコンテキストフリーであれば、パーサが大幅に簡略化されます。字句トークンifをある場所ではキーワードとして扱い、他のものでは識別子を使用すると、識別子をより賢明に選択すると、実際には必要ない複雑さが生じます。

long int int = char[new - int]; 

(少し難しさと)複雑なものを字句要素が発生する場所に基づいて、パーサー(とどのようなそれらのいずれかの側に存在する)で評価することができますたとえば、C++の文が

。しかし、(少なくとも部分的に)シンプルさ(および可読性)のために、これは行われません。

+1

はい、確かです。質問のタイトルを更新して、キーワードが属性名として禁止される理由を明示するようにしました。実際、 'o.class = 123'では' class'は属性名でなければなりません。しかし、これは有効ではありません(C)Python; CPythonインタプリタにとって明らかにならない理由があるに違いありません。これらの理由は何ですか? – EOL

3

ifは、キーワードであるため、変数名や属性(明示的)として使用することはできません。ときに

キーワードは常に文脈キーワード、およびされていないとき、パーサが簡単ですので、あなたが、しかし、例えばif(厄介な方法でこれを回避するために

>>> class C(object): pass 
... 
>>> o = C() 
>>> setattr(o, 'if', 123) 
>>> getattr(o, 'if') 
123 
+0

はい、確かに。これは 'o .__ dict__'にアクセスするよりもうまく見えます。しかし、問題はこの制限の理由と制限が文書化されているかどうかです。 – EOL

+0

理由は、キーワードを上書きできないためです。それは文書化する必要はありません。 – Blender

+0

私は@Cat Plus Plusの主なコメントの答えが好きです。パーサーを簡単にすることが設計上の決定でした。 Pythonのイディオムは 'if_'や' exec_'などを行うことです。 – jdi

関連する問題