2010-12-06 6 views
7

Pythonを学ぶときの典型的なPointクラスの例を説明すると、私は何らかの理由でクラスのものと同じ型のクラスレベル(静的変数)を持つことができないことに気付きました。例えば。 Javaで同じ作品しばらくPythonで同じ型のクラス変数

class Point: 

    ORIGIN = Point() # doesn't work 

    def __init__(self, x=0, y=0): 
    self.x = x 
    self.y = y 

class Point { 

    public static void main(final String[] args) { } 

    private static final Point ORIGIN = new Point(0, 0); 

    private int x; 

    private int y; 

    public Point(int x, int y) { 
    this.x = x; 
    this.y = y; 
    } 

} 

質問です:Pythonで同じことを達成するためのいずれかの方法があります。今はモジュールレベルの変数に頼っていますが、私はその解決策が好きではありません。また、授業の体ではできない理由がありますか?

+2

"今、私はモジュールレベルの変数に頼っています。モジュールレベルのグローバルは、クラス定義内に隠された奇妙な静的な最終変数をより意味をなさないものにします。よりシンプルなソリューションで何が問題になっていますか? –

+0

@ S.Lott:ORIGINはどのモジュールにも属していない*という理由があります。例えばの場合。私はこのクラスを他のモジュールに移すことにしました.ORIGINが参照される方法は常に同じです。 – sasuke

+0

ORIGINはPointのインスタンスで、Pointと同じモジュールに属します。あなたが1つを動かすと、なぜあなたは他の人を動かさないでしょうか? –

答えて

4

クラスのインスタンスが作成されるまで、つまりクラスの本体が評価された後(通常のPythonコードのように実行される)まで、クラスのインスタンスを作成することはできません。

Javaの例でも同じです:ClassLoaderはPointクラスを作成し、staticフィールドのコードを実行します。これは、他のいくつかの結果をもたらすだろうもちろん

def class_with_static(name, bases, body): 
    static_block = body.pop("__static__", None) 
    klass = type(name, bases, body) 
    if static_block: 
     static_block(klass) 
    return klass 

class Point(object): 
    __metaclass__ = class_with_static 

    def __static__(cls): 
     cls.ORIGIN = cls() 

    def __init__(self, x=0, y=0): 
     self.x = x 
     self.y = y 

assert isinstance(Point.ORIGIN, Point) 
assert Point.ORIGIN.x == Point.ORIGIN.y == 0 
assert not hasattr(Point, "__static__") 

のように:Pointのすべてのサブクラスがあります、あなたがこのような何かを行うことができるように

Pythonでクラスローダのラフ同等は、メタクラスであります自分自身の属性ORIGINだから、他の人のようにしたいと思うかもしれません:)

+0

良い説明;ここでの問題は、Javaでは 'ORIGIN'クラスのレベル変数はクラス全体がロードされた後に*初期化されますが、Pythonの場合はPointを検索しようとしますが、実際には場合。私はなぜこれがPythonでは許されていないが、何も思い付くことができないという良い理由を考えようとしました。他の人が指摘しているように、ここで最もクリーンな解決策は、ORIGINプロパティを宣言後の*クラスにアタッチすることです。 :-( – sasuke

+0

あなたは 'class'を宣言として扱いますが、実際には式であり、その結果をモジュールレベルの名前" Point "に格納しているという混乱から来ています。 Pythonの式を使用しているため、 'Point'の値として使用される式で 'Point'を参照することはできません。 – lqc

+0

expressionと言うと、Python固有の意味ですね。 Pythonランタイムがコードを順番に横断し、モジュールレベルのクラス、関数、変数の宣言を式として扱い、それらをモジュールプロパティに代入するという意味ですか? – sasuke

8
class Point(object): 
    pass 

Point.ORIGIN = Point() 
5

事実の後にそれを割り当てます。私はそれのために良い名前がどうなるかわからないが、

class Point: 
    def __init__(self, x=0, y=0): 
    self.x = x 
    self.y = y 


Point.ORIGIN = Point() 
+0

これはモジュールレベルの変数です。これはまさに私が終わりにしたくないものです。 :-) – sasuke

+7

いいえ、そうではありません。 **割り当て**はモジュールレベルですが、**値**はPointクラスの属性として格納されます。 –

+0

私のところで間違っている。要は、これはクラス外のクラスレベル宣言をプッシュしています。 Pythonは通常のクラスとインスタンスレベルの宣言*をクラス宣言内に持つことができます。これは言語の欠点ですか?そうでない場合は、タイプが自分自身を参照することを許さない根本的な理由は何ですか? – sasuke

2

あなたは、クラスのデコレータでこれを行うことができます。上記のコードで利用されてはいないが、あなたはまた、デコレータを介して間接的にクラスの__init__()コンストラクタに引数を渡すことができ

def add_class_var(name, *args, **kwrds): 
    def decorator(cls): 
     setattr(cls, name, cls(*args, **kwrds)) 
     return cls 
    return decorator 

@add_class_var('ORIGIN') 
class Point: 
    def __init__(self, x=0, y=0): 
     self.x = x 
     self.y = y 

print Point.ORIGIN, Point.ORIGIN.x, Point.ORIGIN.y 
# <__main__.Point instance at 0x00B5B418> 0 0 

:ここでは、方法です。