Pythonで静的クラス変数またはメソッドを持つことは可能ですか?これを行うにはどのような構文が必要ですか?
Pythonで静的クラス変数またはメソッドを持つことは可能ですか?これを行うにはどのような構文が必要ですか?
回答:
メソッド内ではなくクラス定義内で宣言された変数は、クラス変数または静的変数です。
>>> 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は静的メソッドよりもクラスメソッドを推奨しますが、静的メソッドに対するこのアプローチの利点についてはまだ少し曖昧です。あなたもそうなら、それはおそらく問題ではありません。
const.py
を持っているだけPI = 3.14
で、どこにでもインポートできます。from const import PI
i = 3
は静的変数ではなくクラス属性であり、インスタンスレベルの属性i
とは異なるため、他の言語では静的変数のように動作しません。参照してくださいmillerdevの答え、ヤンの答え、そして私の答え下記を。
i
、このクラスの数百のインスタンスを作成した場合でも、(静的変数)の1つのコピーのみがメモリに存在しますか?
@Blairコンラッド氏によると、クラス定義内で宣言された静的変数はメソッド内ではなくクラスまたは「静的」変数であるとのことです。
>>> 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__
{}
t.i
属性i
がに直接設定されたときに、インスタンス変数が「静的」クラス変数と同期しなくなったことに注意してくださいt
。これは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
class Test(object):
、_i = 3
、@property
、def i(self)
、return type(self)._i
、@i.setter
、def i(self,val):
、type(self)._i = val
。今、あなたが行うことができますx = Test()
、x.i = 12
、assert x.i == Test.i
。
他の回答が指摘しているように、静的メソッドとクラスメソッドは、組み込みのデコレータを使用して簡単に実行できます。
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
これは、行x.i = 12
がクラス属性の値を変更i
するx
代わりに新しいインスタンス属性を追加したためです。Test
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
セッターを省略します。
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
上記の方法でのみ動作することに注意してくださいインスタンス彼らはなります-あなたのクラスのがない作業クラス自体を使用。だから例えば:
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 == x.i
のi
属性は2つの異なるオブジェクトであるため、この行ではエラーが発生します。Test
x
多くの人々はこれを意外と感じるでしょう。しかし、そうであってはなりません。前に戻ってTest
クラス定義(2番目のバージョン)を調べたら、次の行に注意してください。
i = property(get_i)
明らかに、のメンバーi
は、関数から返されるオブジェクトのタイプであるオブジェクトでTest
なければなりません。property
property
上記の混乱を見つけた場合でも、他の言語(Javaやc ++など)の観点から考えている可能性があります。あなたは勉強に行くべきですproperty
Python属性が返される順序、記述子プロトコル、メソッド解決順序(MRO)についてオブジェクトを。
私は上記の「問題」の解決策を以下に示します。しかし、私は-激しく--少なくとも-あなたが完全に理由を理解するまで、次のようなことをしようとしないことをお勧めしますassert Test.i = x.i
エラーが発生します。
Test.i == x.i
以下の(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
以下は、他の言語の「静的変数」の動作をエミュレートしようとする、私が作成したメタクラスです。基本的には、デフォルトのゲッター、セッター、およびデリーターを、要求されている属性が「静的変数」であるかどうかを確認するバージョンに置き換えることで機能します。
「静的変数」のカタログは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
Test
(インスタンスをインスタンス化するために使用する前に)で行うことは一般に、メタプログラミングの領域にあるものとして表示する必要があると思いますか?たとえば、クラスの動作を変更して変更しますTest.i = 0
(ここでは、プロパティオブジェクトを完全に破棄するだけです)。「プロパティメカニズム」は、クラスのインスタンスのプロパティアクセスでのみ発生すると思います(メタクラスを中間として使用して基本的な動作を変更しない限り)。ところで、この回答を終了してください:-)
クラス変数をその場でクラスに追加することもできます
>>> 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 myObj(object):
def myMethod(cls)
...
myMethod = classmethod(myMethod)
またはデコレータを使用する
class myObj(object):
@classmethod
def myMethod(cls)
静的プロパティの場合..そのときは、いくつかのpython定義を調べます。変数は常に変更できます。それらには、変更可能と不変の2つのタイプがあります。また、クラス属性とインスタンス属性があります。
クラスと何の関係もないのに、なぜ静的メソッドをPythonicの意味で使用するのですか?私があなたなら、classmethodを使用するか、クラスから独立したメソッドを定義します。
次の例に示すように、静的プロパティとインスタンスプロパティについて特筆すべき点は次のとおりです。
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クラスで宣言された各プロパティは、常にメモリ内に静的スロットを持っています。
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
@staticmethod
; @classmethod
(明らかに)クラスメソッド用です(これは主に代替コンストラクタとしての使用を目的としていますが、たまたま呼び出されたクラスへの参照を受け取る静的メソッドとしてピンチで機能します)。
メンバーメソッドの外部でメンバー変数を定義する場合、変数の表現方法に応じて、変数は静的または非静的のいずれかになります。
例えば:
#!/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
static
クラス変数を持つことは可能ですが、おそらく努力する価値はありません。
Python 3で記述された概念実証は次のとおりです。正確な詳細のいずれかが間違っている場合、コードを微調整して、あなたが何を意味しているのかほぼ一致するようにできます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
メタクラスを使用して、クラスを静的にすることもできます。
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が発生します。
__new__
がその親のを呼び出すためにsuper()を使用しないことを願っています...
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!
通常、作成後にこれらへの割り当てはありません。特定のインスタンスに関連付けられていないという意味では静的ですが、値はインスタンス(のクラス)に依存しているself
ため、ルックアップが使用することに注意してください。label
この回答に関しては、静的定数の場合、記述子を使用できます。次に例を示します。
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
@property
。これは記述子を使用するのと同じですが、コードははるかに少なくなります。
もちろん、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で静的変数とメソッドを書くことは間違いなく可能です。
静的変数: クラスレベルで宣言された変数は静的変数と呼ばれ、クラス名を使用して直接アクセスできます。
>>> 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!!
潜在的な混乱を避けるために、静的変数と不変オブジェクトを対比したいと思います。
整数、浮動小数点数、文字列、touplesのようないくつかのプリミティブオブジェクトタイプは、Pythonでは不変です。つまり、特定の名前で参照されるオブジェクトは、前述のオブジェクトタイプのいずれかである場合は変更できません。名前は別のオブジェクトに再割り当てできますが、オブジェクト自体は変更できません。
変数を静的にすることで、変数名が現在指しているオブジェクト以外のオブジェクトを指すことを禁止することで、これをさらに一歩進めます。(注:これは一般的なソフトウェアの概念であり、Pythonに固有のものではありません。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
(Private Static Var)を提示する必要があります。
tryIt
クラスは、使用する必要がある通常のクラスを表します。
次に、1つのフラグのオブジェクトを作成しました(staticFlag
)。このフラグは、すべての通常のオブジェクトへの参照として送信されます。
これらのオブジェクトはすべてリストに追加されていますtryArr
。
このスクリプトの結果:
False
False
False
False
False
True
True
True
True
True
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
hasattr(SomeClass, 'x')
はFalse
です。私はこれが静的変数によって何を意味するのかを疑っています。
some_var
不変、および静的に定義された、またはそうではありませんか?外部ゲッターアクセスは、変数が静的であるかどうかに関係していますか?今、たくさん質問があります。時間があるときは、いくつかの答えを聞きたいです。
some_var
は、上記はクラスのメンバーではありません。Pythonでは、すべてのクラスメンバーにクラスの外部からアクセスできます。
nonlocal
keywoardは、変数のスコープを「バンプ」。クラス本体定義のスコープは、それ自体が見つけたスコープとは無関係です。つまりnonlocal some_var
、別の名前付きオブジェクトへの非ローカル(クラス定義スコープではない)の名前参照を作成するだけです。したがって、クラス本体のスコープにないため、クラス定義にアタッチされません。
これはおそらくハックですが、私は eval(str)
python 3で矛盾のような静的オブジェクトを取得するためにしています。
class
一部の引数を保存する静的メソッドとコンストラクターで定義されたオブジェクトのみを含むRecords.pyファイルがあります。次に、別の.pyファイルからimport Records
、各オブジェクトを動的に選択し、読み込まれるデータのタイプに応じてオンデマンドでインスタンス化する必要があります。
したがってobject_name = 'RecordOne'
、クラス名のどこで、私はcur_type = eval(object_name)
それを呼び出してインスタンス化しますが、インスタンス化するcur_inst = cur_type(args)
前にcur_type.getName()
、たとえば抽象的な基本クラスの実装などの目的から静的メソッドを呼び出すことができます。ただし、バックエンドでは、それはおそらくPythonでインスタンス化され、真に静的ではありません。なぜなら、evalはオブジェクトを返しているからです。
リストまたは辞書を使用して、インスタンス間の「静的な動作」を取得できます。
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
たとえば、他のインスタンス間でそれを増やすために静的変数を共有しようとしている場合、次のスクリプトのようなものがうまく機能します。
# -*- 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)
@classmethod
よりも@staticmethod
優れている点は、サブクラスであっても、メソッドが呼び出されたクラスの名前を常に取得できることです。静的メソッドにはこの情報がないため、たとえばオーバーライドされたメソッドを呼び出すことはできません。