Pythonで静的クラス変数は可能ですか?

2008-09-16 python class oop static class-variables

Pythonで静的なクラス変数またはメソッドを持つことは可能ですか?これを行うにはどのような構文が必要ですか?

Answers

メソッド内ではなくクラス定義内で宣言された変数は、クラス変数または静的変数です。

>>> class MyClass:
...     i = 3
...
>>> MyClass.i
3 

@ millerdevが指摘するように、これによりクラスレベルのi変数が作成されますが、これはインスタンスレベルのi変数とは異なるため、

>>> m = MyClass()
>>> m.i = 4
>>> MyClass.i, m.i
>>> (3, 4)

これはC ++やJavaとは異なりますが、インスタンスへの参照を使用して静的メンバーにアクセスできないC#とはそれほど異なりません。

クラスとクラスオブジェクトについて、Pythonチュートリアルが何を言っているかをご覧ください。

@Steve Johnsonは、 静的メソッドに関して既に回答しています。これは、Pythonライブラリリファレンスの「組み込み関数」にも記載されています。

class C:
    @staticmethod
    def f(arg1, arg2, ...): ...

@beidyはstaticmethodよりもclassmethodをお勧めします。メソッドは最初の引数としてクラス型を受け取るためですが、この方法のstaticmethodに対する利点についてはまだ少し曖昧です。あなたもそうなら、それはおそらく問題ではありません。

個人的には、静的メソッドが必要なときはいつでもクラスメソッドを使用していました。主にクラスを引数として取得するためです。

class myObj(object):
   def myMethod(cls)
     ...
   myMethod = classmethod(myMethod) 

またはデコレータを使用する

class myObj(object):
   @classmethod
   def myMethod(cls)

静的プロパティの場合..そのときは、いくつかのPython定義を検索します。変数は常に変更できます。変更可能と不変の2つのタイプがあります。また、クラス属性とインスタンス属性があります。javaとc ++の意味で、静的属性に似ているものはありません。

クラスと何の関係もないのに、なぜ静的メソッドをPythonの意味で使用するのですか?私があなたなら、classmethodを使用するか、クラスから独立したメソッドを定義します。

Pythonの静的メソッドはclassmethodと呼ばれます 。次のコードを見てください

class MyClass:

    def myInstanceMethod(self):
        print 'output from an instance method'

    @classmethod
    def myStaticMethod(cls):
        print 'output from a static method'

>>> MyClass.myInstanceMethod()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unbound method myInstanceMethod() must be called [...]

>>> MyClass.myStaticMethod()
output from a static method

メソッドmyInstanceMethodを呼び出すと、エラーが発生することに注意してください。これは、このクラスのインスタンスでメソッドを呼び出す必要があるためです。メソッドmyStaticMethodは、 デコレータ @classmethodを使用してクラスメソッドとして設定されます。

キックとクスクスのために、次のようにクラスのインスタンスを渡すことにより、クラスでmyInstanceMethodを呼び出すことができます。

>>> MyClass.myInstanceMethod(MyClass())
output from an instance method

@Blair Conradは、クラス定義内で宣言された静的変数はメソッド内ではなくクラスまたは「静的」変数であると述べています。

>>> class Test(object):
...     i = 3
...
>>> Test.i
3

ここにいくつかの落とし穴があります。上記の例から続けます:

>>> t = Test()
>>> t.i     # "static" variable accessed via instance
3
>>> t.i = 5 # but if we assign to the instance ...
>>> Test.i  # we have not changed the "static" variable
3
>>> t.i     # we have overwritten Test.i on t by creating a new attribute t.i
5
>>> Test.i = 6 # to change the "static" variable we do it by assigning to the class
>>> t.i
5
>>> Test.i
6
>>> u = Test()
>>> u.i
6           # changes to t do not affect new instances of Test

# Namespaces are one honking great idea -- let's do more of those!
>>> Test.__dict__
{'i': 6, ...}
>>> t.__dict__
{'i': 5}
>>> u.__dict__
{}

属性it直接設定されたときに、インスタンス変数tiが「静的」クラス変数と同期しなくなったことに注意してください。これは、 i内再結合したt区別される名前空間、 Testネームスペース。 「静的」変数の値を変更する場合は、元々定義されていたスコープ(またはオブジェクト)内で変更する必要があります。 PythonにはC ++やJavaのように静的変数がないので、「静的」を引用符で囲みました。

静的変数やメソッドについては何も述べていませんが、 Pythonチュートリアルには、 クラスとクラスオブジェクトに関するいくつかの関連情報があります

@Steve Johnsonは、Pythonライブラリリファレンスの「組み込み関数」にも記載されている静的メソッドについても回答しました。

class Test(object):
    @staticmethod
    def f(arg1, arg2, ...):
        ...

@beidは、静的メソッドに類似したクラスメソッドにも言及しました。クラスメソッドの最初の引数はクラスオブジェクトです。例:

class Test(object):
    i = 3 # class (or static) variable
    @classmethod
    def g(cls, arg):
        # here we can use 'cls' instead of the class name (Test)
        if arg > cls.i:
            cls.i = arg # would be the same as Test.i = arg1

上記の例の画像表現

混乱を避けるために、静的変数と不変オブジェクトを対比させたいと思います。

整数、浮動小数点数、文字列、touplesなどの一部のプリミティブオブジェクトタイプは、Pythonでは不変です。つまり、特定の名前で参照されるオブジェクトは、前述のオブジェクトタイプのいずれかである場合は変更できません。名前は別のオブジェクトに再割り当てできますが、オブジェクト自体は変更できません。

変数を静的にすることで、変数名が現在指しているオブジェクト以外のオブジェクトを指すことを禁止することで、これをさらに一歩進めます。 (注:これは一般的なソフトウェアの概念であり、Pythonに固有のものではありません。Pythonで静的を実装する方法については、他の投稿を参照してください)。

クラス変数をその場でクラスに追加することもできます

>>> class X:
...     pass
... 
>>> X.bar = 0
>>> x = X()
>>> x.bar
0
>>> x.foo
Traceback (most recent call last):
  File "<interactive input>", line 1, in <module>
AttributeError: X instance has no attribute 'foo'
>>> X.foo = 1
>>> x.foo
1

そしてクラスインスタンスはクラス変数を変更できます

class X:
  l = []
  def __init__(self):
    self.l.append(1)

print X().l
print X().l

>python test.py
[1]
[1, 1]

メタクラスを使用してクラスを静的にすることもできます。

class StaticClassError(Exception):
    pass


class StaticClass:
    __metaclass__ = abc.ABCMeta

    def __new__(cls, *args, **kw):
        raise StaticClassError("%s is a static class and cannot be initiated."
                                % cls)

class MyClass(StaticClass):
    a = 1
    b = 3

    @staticmethod
    def add(x, y):
        return x+y

次に、誤ってMyClassを初期化しようとすると、StaticClassErrorが発生します。

次の例に示すように、静的プロパティとインスタンスプロパティについて特筆すべき点は次のとおりです。

class my_cls:
  my_prop = 0

#static property
print my_cls.my_prop  #--> 0

#assign value to static property
my_cls.my_prop = 1 
print my_cls.my_prop  #--> 1

#access static property thru' instance
my_inst = my_cls()
print my_inst.my_prop #--> 1

#instance property is different from static property 
#after being assigned a value
my_inst.my_prop = 2
print my_cls.my_prop  #--> 1
print my_inst.my_prop #--> 2

つまり、インスタンスプロパティに値を割り当てる前に、インスタンスを通じてプロパティにアクセスしようとすると、静的な値が使用されます。 Pythonクラスで宣言された各プロパティには、常にメモリ内に静的スロットがあります

私が見つけた最良の方法は、別のクラスを使用することです。オブジェクトを作成して、それを他のオブジェクトで使用できます。

class staticFlag:
    def __init__(self):
        self.__success = False
    def isSuccess(self):
        return self.__success
    def succeed(self):
        self.__success = True

class tryIt:
    def __init__(self, staticFlag):
        self.isSuccess = staticFlag.isSuccess
        self.succeed = staticFlag.succeed

tryArr = []
flag = staticFlag()
for i in range(10):
    tryArr.append(tryIt(flag))
    if i == 5:
        tryArr[i].succeed()
    print tryArr[i].isSuccess()

上記の例では、 staticFlagという名前のクラスを作成しました。

このクラスは、静的__success (プライベート静的__success )を提示する必要があります。

tryItクラスは、使用する必要がある通常のクラスを表しています。

ここで、1つのフラグ( staticFlag )のオブジェクトを作成しました。このフラグは、すべての通常のオブジェクトへの参照として送信されます。

これらのオブジェクトはすべて、リストtryArrに追加されます。


このスクリプトの結果:

False
False
False
False
False
True
True
True
True
True

メンバーメソッドの外部でメンバー変数を定義する場合、変数は、変数の表現方法に応じて静的または非静的のいずれかになります。

  • CLASSNAME.varは静的変数です
  • INSTANCENAME.varは静的変数ではありません。
  • クラス内のself.varは静的変数ではありません。
  • クラスメンバー関数内のvarが定義されていません。

例えば:

#!/usr/bin/python

class A:
    var=1

    def printvar(self):
        print "self.var is %d" % self.var
        print "A.var is %d" % A.var


    a = A()
    a.var = 2
    a.printvar()

    A.var = 3
    a.printvar()

結果は

self.var is 2
A.var is 1
self.var is 2
A.var is 3

この回答に関しては、静的定数の場合、記述子を使用できます。次に例を示します。

class ConstantAttribute(object):
    '''You can initialize my value but not change it.'''
    def __init__(self, value):
        self.value = value

    def __get__(self, obj, type=None):
        return self.value

    def __set__(self, obj, val):
        pass


class Demo(object):
    x = ConstantAttribute(10)


class SubDemo(Demo):
    x = 10


demo = Demo()
subdemo = SubDemo()
# should not change
demo.x = 100
# should change
subdemo.x = 100
print "small demo", demo.x
print "small subdemo", subdemo.x
print "big demo", Demo.x
print "big subdemo", SubDemo.x

その結果 ...

small demo 10
small subdemo 100
big demo 10
big subdemo 10

設定値(上記のpass )を静かに無視することが目的でない場合は、常に例外を発生させることができます。 C ++、Javaスタイルの静的クラス変数を探している場合:

class StaticAttribute(object):
    def __init__(self, value):
        self.value = value

    def __get__(self, obj, type=None):
        return self.value

    def __set__(self, obj, val):
        self.value = val

記述子の詳細については、 この回答と公式ドキュメントHOWTOをご覧ください。

静的メソッドとクラスメソッド

他の回答で述べたように、静的メソッドとクラスメソッドは、組み込みのデコレータを使用して簡単に実行できます。

class Test(object):

    # regular instance method:
    def MyMethod(self):
        pass

    # class method:
    @classmethod
    def MyClassMethod(klass):
        pass

    # static method:
    @staticmethod
    def MyStaticMethod():
        pass

通常どおり、 MyMethod()最初の引数はクラスインスタンスオブジェクトにバインドされます。対照的に、 MyClassMethod()最初の引数は、クラスオブジェクト自体 (この例ではTest )にバインドされていますMyStaticMethod()場合、バインドされる引数はなく、引数を持つことはオプションです。

「静的変数」

ただし、「静的変数」(とにかく、 変更可能な静的変数、つまり用語が矛盾しない場合)の実装は、それほど単純ではありません。 Millerdev が彼の回答指摘したように 、問題はPythonのクラス属性が本当に「静的変数」ではないことです。考慮してください:

class Test(object):
    i = 3  # This is a class attribute

x = Test()
x.i = 12   # Attempt to change the value of the class attribute using x instance
assert x.i == Test.i  # ERROR
assert Test.i == 3    # Test.i was not affected
assert x.i == 12      # x.i is a different object than Test.i

これは、行xi = 12が、 Test class i属性の値を変更する代わりに、 xに新しいインスタンス属性iを追加したためです。

予想される部分的な静的変数の動作、つまり、複数のインスタンス間での属性の同期(ただし、クラス自体との同期ではありません 。以下の「問題」を参照)は、クラス属性をプロパティに変換することで実現できます。

class Test(object):

    _i = 3

    @property
    def i(self):
        return type(self)._i

    @i.setter
    def i(self,val):
        type(self)._i = val

## ALTERNATIVE IMPLEMENTATION - FUNCTIONALLY EQUIVALENT TO ABOVE ##
## (except with separate methods for getting and setting i) ##

class Test(object):

    _i = 3

    def get_i(self):
        return type(self)._i

    def set_i(self,val):
        type(self)._i = val

    i = property(get_i, set_i)

今あなたはできる:

x1 = Test()
x2 = Test()
x1.i = 50
assert x2.i == x1.i  # no error
assert x2.i == 50    # the property is synced

これで、静的変数はすべてのクラスインスタンス間で同期したままになります

(注:つまり、クラスインスタンスが_i独自のバージョンを定義することを決定しない限り!しかし、誰かがそれを行うことを決定した場合、彼らは彼らが得るものに値するのではないですか???)

技術的に言えば、 iはまだ「静的変数」ではないことに注意してください。これはpropertyであり、特殊なタイプの記述子です。ただし、 property動作は、すべてのクラスインスタンス間で同期される(可変)静的変数と同等になりました。

不変の「静的変数」

不変の静的変数の動作の場合は、 propertyセッターを省略しproperty

class Test(object):

    _i = 3

    @property
    def i(self):
        return type(self)._i

## ALTERNATIVE IMPLEMENTATION - FUNCTIONALLY EQUIVALENT TO ABOVE ##
## (except with separate methods for getting i) ##

class Test(object):

    _i = 3

    def get_i(self):
        return type(self)._i

    i = property(get_i)

インスタンスi属性を設定しようとすると、 AttributeErrorが返されます。

x = Test()
assert x.i == 3  # success
x.i = 12         # ERROR

知っておくべき1つの問題

上記のメソッドはクラスのインスタンスでのみ機能することに注意してください。 クラス自体を使用する場合は機能しません 。だから例えば:

x = Test()
assert x.i == Test.i  # ERROR

# x.i and Test.i are two different objects:
type(Test.i)  # class 'property'
type(x.i)     # class 'int'

assert Test.i == xiという行assert Test.i == xiTesti属性とxが2つの異なるオブジェクトであるため、エラーを生成します。

多くの人々はこれを意外と感じるでしょう。しかし、そうであってはなりません。 Testクラスの定義(2番目のバージョン)に戻って調べたら、次の行に注意してください。

    i = property(get_i) 

明らかに、 Testのメンバーipropertyオブジェクトでなければなりません。これは、 property関数から返されるオブジェクトのタイプです。

上記の混乱を見つけた場合は、他の言語(Javaやc ++など)の観点から考えている可能性があります。 Python属性が返される順序、記述子プロトコル、メソッド解決順序(MRO)について、 propertyオブジェクトを調べてください。

私は上記の「問題」の解決策を以下に示します。ただし、私は- assert Test.i = xi -少なくともassert Test.i = xiがエラーを引き起こす理由を完全に理解するまで、次のようなことをしないでください。

REAL、 Test.i == xi静的変数Test.i == xi

以下の(Python 3)ソリューションは、情報提供のみを目的として提示しています。私はそれを「良い解決策」として保証していません。他の言語の静的変数の振る舞いをPythonでエミュレートすることが実際に必要かどうか疑問に思っています。ただし、それが実際に役立つかどうかに関係なく、以下はPythonがどのように機能するかをさらに理解するのに役立ちます。

更新:この試みは本当にひどいです。このようなことを主張する場合(ヒント:しないでください。Pythonは非常にエレガントな言語であり、他の言語のように動作させるために靴を角張る必要はありません)、代わりにEthan Furmanの回答のコードを使用してください。

メタクラスを使用して他の言語の静的変数の動作をエミュレートする

メタクラスはクラスのクラスです。 Pythonのすべてのクラスのデフォルトのメタクラス(つまり、Python 2.3以降の「新しいスタイル」クラス)はtypeです。例えば:

type(int)  # class 'type'
type(str)  # class 'type'
class Test(): pass
type(Test) # class 'type'

ただし、次のように独自のメタクラスを定義できます。

class MyMeta(type): pass

そして、それを次のようにあなた自身のクラスに適用してください(Python 3のみ):

class MyClass(metaclass = MyMeta):
    pass

type(MyClass)  # class MyMeta

以下は、他の言語の「静的変数」の動作をエミュレートしようとする、私が作成したメタクラスです。基本的には、デフォルトのgetter、setter、およびdeleterを、要求されている属性が「静的変数」であるかどうかを確認するバージョンに置き換えることで機能します。

「静的変数」のカタログは、 StaticVarMeta.statics属性に格納されます。すべての属性要求は、最初に代替の解決順序を使用して解決しようとします。これを「静的解決順序」または「SRO」と呼んでいます。これは、特定のクラス(またはその親クラス)の「静的変数」のセットで要求された属性を探すことによって行われます。属性が「SRO」に表示されない場合、クラスはデフォルトの属性の取得/設定/削除動作(つまり、「MRO」)にフォールバックします。

from functools import wraps

class StaticVarsMeta(type):
    '''A metaclass for creating classes that emulate the "static variable" behavior
    of other languages. I do not advise actually using this for anything!!!

    Behavior is intended to be similar to classes that use __slots__. However, "normal"
    attributes and __statics___ can coexist (unlike with __slots__). 

    Example usage: 

        class MyBaseClass(metaclass = StaticVarsMeta):
            __statics__ = {'a','b','c'}
            i = 0  # regular attribute
            a = 1  # static var defined (optional)

        class MyParentClass(MyBaseClass):
            __statics__ = {'d','e','f'}
            j = 2              # regular attribute
            d, e, f = 3, 4, 5  # Static vars
            a, b, c = 6, 7, 8  # Static vars (inherited from MyBaseClass, defined/re-defined here)

        class MyChildClass(MyParentClass):
            __statics__ = {'a','b','c'}
            j = 2  # regular attribute (redefines j from MyParentClass)
            d, e, f = 9, 10, 11   # Static vars (inherited from MyParentClass, redefined here)
            a, b, c = 12, 13, 14  # Static vars (overriding previous definition in MyParentClass here)'''
    statics = {}
    def __new__(mcls, name, bases, namespace):
        # Get the class object
        cls = super().__new__(mcls, name, bases, namespace)
        # Establish the "statics resolution order"
        cls.__sro__ = tuple(c for c in cls.__mro__ if isinstance(c,mcls))

        # Replace class getter, setter, and deleter for instance attributes
        cls.__getattribute__ = StaticVarsMeta.__inst_getattribute__(cls, cls.__getattribute__)
        cls.__setattr__ = StaticVarsMeta.__inst_setattr__(cls, cls.__setattr__)
        cls.__delattr__ = StaticVarsMeta.__inst_delattr__(cls, cls.__delattr__)
        # Store the list of static variables for the class object
        # This list is permanent and cannot be changed, similar to __slots__
        try:
            mcls.statics[cls] = getattr(cls,'__statics__')
        except AttributeError:
            mcls.statics[cls] = namespace['__statics__'] = set() # No static vars provided
        # Check and make sure the statics var names are strings
        if any(not isinstance(static,str) for static in mcls.statics[cls]):
            typ = dict(zip((not isinstance(static,str) for static in mcls.statics[cls]), map(type,mcls.statics[cls])))[True].__name__
            raise TypeError('__statics__ items must be strings, not {0}'.format(typ))
        # Move any previously existing, not overridden statics to the static var parent class(es)
        if len(cls.__sro__) > 1:
            for attr,value in namespace.items():
                if attr not in StaticVarsMeta.statics[cls] and attr != ['__statics__']:
                    for c in cls.__sro__[1:]:
                        if attr in StaticVarsMeta.statics[c]:
                            setattr(c,attr,value)
                            delattr(cls,attr)
        return cls
    def __inst_getattribute__(self, orig_getattribute):
        '''Replaces the class __getattribute__'''
        @wraps(orig_getattribute)
        def wrapper(self, attr):
            if StaticVarsMeta.is_static(type(self),attr):
                return StaticVarsMeta.__getstatic__(type(self),attr)
            else:
                return orig_getattribute(self, attr)
        return wrapper
    def __inst_setattr__(self, orig_setattribute):
        '''Replaces the class __setattr__'''
        @wraps(orig_setattribute)
        def wrapper(self, attr, value):
            if StaticVarsMeta.is_static(type(self),attr):
                StaticVarsMeta.__setstatic__(type(self),attr, value)
            else:
                orig_setattribute(self, attr, value)
        return wrapper
    def __inst_delattr__(self, orig_delattribute):
        '''Replaces the class __delattr__'''
        @wraps(orig_delattribute)
        def wrapper(self, attr):
            if StaticVarsMeta.is_static(type(self),attr):
                StaticVarsMeta.__delstatic__(type(self),attr)
            else:
                orig_delattribute(self, attr)
        return wrapper
    def __getstatic__(cls,attr):
        '''Static variable getter'''
        for c in cls.__sro__:
            if attr in StaticVarsMeta.statics[c]:
                try:
                    return getattr(c,attr)
                except AttributeError:
                    pass
        raise AttributeError(cls.__name__ + " object has no attribute '{0}'".format(attr))
    def __setstatic__(cls,attr,value):
        '''Static variable setter'''
        for c in cls.__sro__:
            if attr in StaticVarsMeta.statics[c]:
                setattr(c,attr,value)
                break
    def __delstatic__(cls,attr):
        '''Static variable deleter'''
        for c in cls.__sro__:
            if attr in StaticVarsMeta.statics[c]:
                try:
                    delattr(c,attr)
                    break
                except AttributeError:
                    pass
        raise AttributeError(cls.__name__ + " object has no attribute '{0}'".format(attr))
    def __delattr__(cls,attr):
        '''Prevent __sro__ attribute from deletion'''
        if attr == '__sro__':
            raise AttributeError('readonly attribute')
        super().__delattr__(attr)
    def is_static(cls,attr):
        '''Returns True if an attribute is a static variable of any class in the __sro__'''
        if any(attr in StaticVarsMeta.statics[c] for c in cls.__sro__):
            return True
        return False

staticクラス変数を持つことは可能ですが、おそらく努力する価値はありません。

Python 3で書かれた概念実証は次のとおりです。正確な詳細のいずれかが間違っている場合は、 static variable意味するものとほぼ一致するようにコードを調整できstatic variable


class Static:
    def __init__(self, value, doc=None):
        self.deleted = False
        self.value = value
        self.__doc__ = doc
    def __get__(self, inst, cls=None):
        if self.deleted:
            raise AttributeError('Attribute not set')
        return self.value
    def __set__(self, inst, value):
        self.deleted = False
        self.value = value
    def __delete__(self, inst):
        self.deleted = True

class StaticType(type):
    def __delattr__(cls, name):
        obj = cls.__dict__.get(name)
        if isinstance(obj, Static):
            obj.__delete__(name)
        else:
            super(StaticType, cls).__delattr__(name)
    def __getattribute__(cls, *args):
        obj = super(StaticType, cls).__getattribute__(*args)
        if isinstance(obj, Static):
            obj = obj.__get__(cls, cls.__class__)
        return obj
    def __setattr__(cls, name, val):
        # check if object already exists
        obj = cls.__dict__.get(name)
        if isinstance(obj, Static):
            obj.__set__(name, val)
        else:
            super(StaticType, cls).__setattr__(name, val)

そして使用中:

class MyStatic(metaclass=StaticType):
    """
    Testing static vars
    """
    a = Static(9)
    b = Static(12)
    c = 3

class YourStatic(MyStatic):
    d = Static('woo hoo')
    e = Static('doo wop')

そしていくつかのテスト:

ms1 = MyStatic()
ms2 = MyStatic()
ms3 = MyStatic()
assert ms1.a == ms2.a == ms3.a == MyStatic.a
assert ms1.b == ms2.b == ms3.b == MyStatic.b
assert ms1.c == ms2.c == ms3.c == MyStatic.c
ms1.a = 77
assert ms1.a == ms2.a == ms3.a == MyStatic.a
ms2.b = 99
assert ms1.b == ms2.b == ms3.b == MyStatic.b
MyStatic.a = 101
assert ms1.a == ms2.a == ms3.a == MyStatic.a
MyStatic.b = 139
assert ms1.b == ms2.b == ms3.b == MyStatic.b
del MyStatic.b
for inst in (ms1, ms2, ms3):
    try:
        getattr(inst, 'b')
    except AttributeError:
        pass
    else:
        print('AttributeError not raised on %r' % attr)
ms1.c = 13
ms2.c = 17
ms3.c = 19
assert ms1.c == 13
assert ms2.c == 17
assert ms3.c == 19
MyStatic.c = 43
assert ms1.c == 13
assert ms2.c == 17
assert ms3.c == 19

ys1 = YourStatic()
ys2 = YourStatic()
ys3 = YourStatic()
MyStatic.b = 'burgler'
assert ys1.a == ys2.a == ys3.a == YourStatic.a == MyStatic.a
assert ys1.b == ys2.b == ys3.b == YourStatic.b == MyStatic.b
assert ys1.d == ys2.d == ys3.d == YourStatic.d
assert ys1.e == ys2.e == ys3.e == YourStatic.e
ys1.a = 'blah'
assert ys1.a == ys2.a == ys3.a == YourStatic.a == MyStatic.a
ys2.b = 'kelp'
assert ys1.b == ys2.b == ys3.b == YourStatic.b == MyStatic.b
ys1.d = 'fee'
assert ys1.d == ys2.d == ys3.d == YourStatic.d
ys2.e = 'fie'
assert ys1.e == ys2.e == ys3.e == YourStatic.e
MyStatic.a = 'aargh'
assert ys1.a == ys2.a == ys3.a == YourStatic.a == MyStatic.a

クラスファクトリpython3.6の静的変数

python3.6以降でクラスファクトリを使用している場合は、 nonlocalキーワードを使用して、作成されているクラスのスコープ/コンテキストに次のように追加します。

>>> def SomeFactory(some_var=None):
...     class SomeClass(object):
...         nonlocal some_var
...         def print():
...             print(some_var)
...     return SomeClass
... 
>>> SomeFactory(some_var="hello world").print()
hello world

はいぜったいに、 Python自体には明示的に静的データメンバーはありませんが、そうすることで可能になります

class A:
    counter =0
    def callme (self):
        A.counter +=1
    def getcount (self):
        return self.counter  
>>> x=A()
>>> y=A()
>>> print(x.getcount())
>>> print(y.getcount())
>>> x.callme() 
>>> print(x.getcount())
>>> print(y.getcount())

出力

0
0
1
1

説明

here object (x) alone increment the counter variable
from 0 to 1 by not object y. But result it as "static counter"

Pythonの属性ルックアップに関する非常に興味深い点の1つは、「 仮想変数」の作成に使用できることです。

class A(object):

  label="Amazing"

  def __init__(self,d): 
      self.data=d

  def say(self): 
      print("%s %s!"%(self.label,self.data))

class B(A):
  label="Bold"  # overrides A.label

A(5).say()      # Amazing 5!
B(3).say()      # Bold 3!

通常、作成後にこれらへの割り当てはありません。 label特定のインスタンスに関連付けられていないという意味では静的labelが、値はインスタンス(のクラス)に依存するため、ルックアップではself使用されることに注意してください。

はい、Pythonで静的変数とメソッドを書くことは間違いなく可能です。

静的変数: クラスレベルで宣言された変数は静的変数と呼ばれ、クラス名を使用して直接アクセスできます。

    >>> class A:
        ...my_var = "shagun"

    >>> print(A.my_var)
        shagun

インスタンス変数:クラスのインスタンスによって関連付けられ、アクセスされる変数は、インスタンス変数です。

   >>> a = A()
   >>> a.my_var = "pruthi"
   >>> print(A.my_var,a.my_var)
       shagun pruthi

静的メソッド:変数と同様に、静的メソッドはクラス名を使用して直接アクセスできます。インスタンスを作成する必要はありません。

ただし、Pythonでは静的メソッドが非静的メソッドを呼び出すことはできません。

    >>> class A:
   ...     @staticmethod
   ...     def my_static_method():
   ...             print("Yippey!!")
   ... 
   >>> A.my_static_method()
   Yippey!!

リストまたは辞書を使用して、インスタンス間の「静的な動作」を取得できます。

class Fud:

     class_vars = {'origin_open':False}

     def __init__(self, origin = True):
         self.origin = origin
         self.opened = True
         if origin:
             self.class_vars['origin_open'] = True


     def make_another_fud(self):
         ''' Generating another Fud() from the origin instance '''

         return Fud(False)


     def close(self):
         self.opened = False
         if self.origin:
             self.class_vars['origin_open'] = False


fud1 = Fud()
fud2 = fud1.make_another_fud()

print (f"is this the original fud: {fud2.origin}")
print (f"is the original fud open: {fud2.class_vars['origin_open']}")
# is this the original fud: False
# is the original fud open: True

fud1.close()

print (f"is the original fud open: {fud2.class_vars['origin_open']}")
# is the original fud open: False

したがって、これはおそらくハックですが、Python 3でeval(str)を使用して、矛盾のような静的オブジェクトを取得しています。

一部の引数を保存する静的メソッドとコンストラクターで定義されたclassオブジェクトのみを含むRecords.pyファイルがあります。次に、別の.pyファイルからimport Recordsimport Recordsますが、各オブジェクトを動的に選択し、読み込まれるデータの種類に応じてオンデマンドでインスタンス化する必要があります。

したがって、 object_name = 'RecordOne'またはクラス名の場合、 cur_type = eval(object_name)を呼び出し、それをインスタンス化するには、 cur_inst = cur_type(args)を実行します。 ただし、インスタンス化する前に、たとえばcur_type.getName()から静的メソッドを呼び出すことができます。たとえば、抽象基本クラスの実装など、目的が何であってもかまいません。ただし、バックエンドでは、おそらくpythonでインスタンス化され、真に静的ではありません。これは、evalがオブジェクトを返しているためです。

たとえば、他のインスタンス間でそれを増やすために静的変数を共有しようとしている場合、次のスクリプトのようなものがうまく機能します。

# -*- coding: utf-8 -*-
class Worker:
    id = 1

    def __init__(self):
        self.name = ''
        self.document = ''
        self.id = Worker.id
        Worker.id += 1

    def __str__(self):
        return u"{}.- {} {}".format(self.id, self.name, self.document).encode('utf8')


class Workers:
    def __init__(self):
        self.list = []

    def add(self, name, doc):
        worker = Worker()
        worker.name = name
        worker.document = doc
        self.list.append(worker)


if __name__ == "__main__":
    workers = Workers()
    for item in (('Fiona', '0009898'), ('Maria', '66328191'), ("Sandra", '2342184'), ('Elvira', '425872')):
        workers.add(item[0], item[1])
    for worker in workers.list:
        print(worker)
    print("next id: %i" % Worker.id)

ユーザー定義のクラスが存在するときに静的変数が作成され、キーワードselfに従う静的変数を定義するように、静的変数を作成します。

class Student:

    the correct way of static declaration
    i = 10

    incorrect
    self.i = 10

Related