Python中是否可以有静态类变量或方法?要执行此操作需要什么语法?

评论

是。缺少关键字“ static”可能会引起误解,但是在类内部初始化的任何对象(仅在类内部而不是在构造函数中的一个缩进)都是静态的。它不依赖于实例化(因为它不属于构造函数)。至于方法,您可以使用@staticmethod装饰器来实现。

对于类的所有实例都存在的事物使用术语“静态”,对我来说总是很奇怪

#1 楼

在类定义中声明但在方法内部声明的变量是类或静态变量:

>>> 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建议使用类方法而不是静态方法,然后将方法接收到类类型作为第一个参数,但是我对这种方法相对于静态方法的优势还是有点模糊。如果您也是,那可能没关系。

评论


我只是在学习Python,但是@classmethod优于@staticmethod AFAIK的优点是,即使方法是子类,您也总是会得到调用该方法的类的名称。静态方法缺少此信息,因此,例如,它不能调用重写的方法。

–Seb
2012年10月2日15:58



@theJollySin的python常量方法是不为常量增加类。只需具有PI = 3.14的const.py,您就可以将其导入到任何地方。从const import PI

– Giszmo
13年6月21日在17:54

这个答案很可能会混淆静态变量问题。首先,i = 3不是静态变量,它是类属性,并且由于它与实例级属性i不同,因此它在其他语言中的行为不像静态变量。请在下面查看millerdev的答案,Yann的答案以及我的答案。

– Rick支持Monica
2014年12月19日15:40



所以即使我创建了数百个此类的实例,i(静态变量)的一个副本也将在内存中?

–梦想
17年7月21日在12:53

对于任何有兴趣的人,@ Dubslow评论中提到的Daniel,它是millerdev(回溯机)

–OfirD
18-2-26在21:22



#2 楼

@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__
{}


当直接在t.i上设置属性i时,请注意实例变量t与“静态”类变量如何不同步。这是因为it命名空间内被重新绑定,这与Test命名空间不同。如果要更改“静态”变量的值,则必须在其最初定义的范围(或对象)内进行更改。我将“ static”用引号引起来,因为Python实际上没有C ++和Java所具有的静态变量。有关类和类对象的一些相关信息。

@Steve Johnson还回答了有关静态方法的问题,这些方法也记录在Python库参考的“内置函数”下。

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


@ beid还提到了classmethod,它类似于staticmethod。类方法的第一个参数是类对象。例如:

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




评论


我建议您稍微扩展一下示例:如果在设置Test.i = 6之后,然后实例化一个新对象(例如u = Test()),则新对象将“继承”新的类值(例如, ui == 6)

–马克
2014年8月20日在13:48



使静态变量保持同步的一种方法是使其具有属性:类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,断言x.i ==Test.i。

– Rick支持Monica
2014-12-19 15:05



所以我可以说所有变量最初都是静态的,然后访问实例会使实例变量在运行时运行吗?

–阿里
2015年11月4日在7:17

也许这很有趣:如果在Test中定义一个更改Test.i的方法,这将同时影响Test.i和t.i值。

–巴勃罗
18 Mar 7 '18 at 13:41

@millerdev,就像您提到的,Python不像C ++或JAVA那样具有静态变量。所以可以说Test.i更像是类变量而不是静态变量吗?

–泰托
18/09/21在10:12

#3 楼

静态方法和类方法

正如其他答案所指出的,使用内置装饰器可以轻松实现静态方法和类方法:

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,而不是更改Testi属性的值。

部分预期的静态变量行为,例如,在多个实例之间同步属性(但不与类本身同步;请参见下面的“陷阱”),可以通过将类属性转换为属性来实现:

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产生错误,因为iTestx属性是两个不同的对象。

许多人会发现这令人惊讶。但是,事实并非如此。如果我们回过头来检查我们的Test类定义(第二个版本),请注意以下这一行: i对象,它是从Test函数返回的对象的类型。

如果发现上述令人困惑的地方,您很可能仍会从其他语言(例如Java或c ++)的角度考虑它。您应该研究property对象,有关返回Python属性的顺序,描述符协议和方法解析顺序(MRO)。

我在下面介绍了上述“陷阱”的解决方案;但是,我建议-努力-至少在您完全理解property引起错误的原因之前,不要尝试执行以下操作。


实际的静态变量-property


我在下面提出(Python 3)解决方案,仅供参考。我不赞成将其作为“好的解决方案”。我对是否真的需要在Python中模拟其他语言的静态变量行为感到怀疑。但是,不管它是否真的有用,下面的内容应有助于进一步了解Python的工作方式。

更新:这种尝试确实非常糟糕;如果您坚持要执行这样的操作(提示:请不要; Python是一种非常优雅的语言,而不必像其他语言那样费劲地使它表现为行为),请改用Ethan Furman的答案中的代码。

使用元类模拟其他语言的静态变量行为

元类是类的类。 Python中所有类的默认元类(即我认为Python 2.3之后的“新样式”类)是assert Test.i = x.i。例如:

    i = property(get_i) 


但是,您可以这样定义自己的元类:

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


并应用如下所示(仅Python 3):它基本上是通过将默认的getter,setter和deleter替换为版本来工作的,该版本检查以查看所请求的属性是否为“静态变量”。

“静态变量”的目录存储在Test.i == x.i属性中。最初尝试使用替代解决顺序解决所有属性请求。我将其称为“静态解决方案命令”或“ SRO”。这是通过在给定类(或其父类)的“静态变量”集合中查找请求的属性来完成的。如果该属性未出现在“ SRO”中,则该类将回退到默认属性的“获取/设置/删除”行为(即“ MRO”)。

class MyMeta(type): pass


评论


我尝试使用您的方式,但遇到了问题,请在此处查看我的问题stackoverflow.com/questions/29329850/get-static-variable-value

–穆罕默德·里法特(Muhammed Refaat)
15年3月29日在15:22

@RickTeachey:我想您通常应该将您在类实例测试上所做的任何事情(在使用它实例化实例之前)都视为在元编程领域?例如,您通过执行Test.i = 0来更改类行为(在这里,您只是完全破坏了属性对象)。我猜想“属性机制”仅在类实例的属性访问中起作用(除非您可能使用元类作为中介来更改基本行为)。顺便说一句,请完成此答案:-)

–奥勒·汤姆森·布斯(Ole Thomsen Buus)
2015年5月11日15:20

@RickTeachey谢谢:-)最后,您的元类很有趣,但实际上对我来说有点太复杂了。在绝对需要此机制的大型框架/应用程序中,这可能很有用。无论如何,这表明如果确实需要新的(复杂的)非默认元行为,Python可以实现:)

–奥勒·汤姆森·布斯(Ole Thomsen Buus)
15年5月14日在21:54

@OleThomsenBuus:检查我的答案,找到一个能完成工作的更简单的元类。

– Ethan Furman
17年2月22日在16:40

@taper你是正确的;我已经编辑了解决此问题的答案(不能相信它在那里坐了太久了!)。对困惑感到抱歉。

– Rick支持Monica
17年12月8日在16:14

#4 楼

您还可以随时将类变量添加到类中。

>>> 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]


评论


即使将类导入另一个模块,新的类变量也会保留吗?

– Zakdances
13年1月1日在12:20

是。类实际上是单例,无论您从何处调用它们。

– Pedro
18年7月25日在14:11

@Gregory您说过“并且类实例可以更改类变量”实际上,此示例称为访问而不是修改。修改是由对象本身通过自己的append()函数完成的。

– Amr ALHOSSARY
19年11月26日在12:18

#5 楼

就个人而言,每当需要静态方法时,我都会使用类方法。主要是因为我将类作为参数。

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


或使用装饰器

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


用于静态属性..它时候您查找一些python定义..变量可以随时更改。它们有两种类型,它们是可变的和不可变的。此外,还有类属性和实例属性。从Java和c ++的意义上说,没有什么比静态属性更真正的

为什么从pythonic的意义上使用静态方法,如果与班级没有任何关系!如果您是我,则可以使用classmethod或独立于类定义方法。

评论


变量不是可变的或不可变的。对象是。 (但是,对象可以以不同程度的成功尝试阻止分配给某些属性。)

–戴维斯·鲱鱼
17年9月21日在3:55

Java和C ++完全使用静态(不使用单词imho),就像使用实例与类属性一样。在Java和C ++中,类属性/方法是静态的,没有区别,只是在Python中,类方法调用的第一个参数是类。

–天使O'Sphere
19年11月1日在8:35

#6 楼

关于静态属性和实例属性的一件事要特别注意,如下面的示例所示:通过实例的属性,使用静态值。 python类中声明的每个属性在内存中始终具有一个静态插槽。

#7 楼

python中的静态方法称为类方法。请看下面的代码

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时,会出现错误。这是因为它要求在此类的实例上调用该方法。使用装饰器@classmethod将方法myStaticMethod设置为类方法。

对于踢和傻笑,我们可以通过传入类的实例来调用类的myInstanceMethod,如下所示:

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


评论


嗯...静态方法是用@staticmethod制作的; @classmethod(显然)用于类方法(主要用于替代构造函数,但可以在某些情况下用作静态方法,恰好接收对其调用的类的引用)。

–ShadowRanger
19年6月14日在3:20

#8 楼

当在任何成员方法之外定义某个成员变量时,根据变量的表示方式,变量可以是静态的也可以是非静态的。


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


评论


压痕已损坏。这不会执行

–托马斯·韦勒(Thomas Weller)
19年7月16日在8:56

#9 楼

可能有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


#10 楼

您还可以使用元类将类强制为静态。

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。

评论


如果不打算实例化它,为什么还要上课呢?感觉就像是将Python转换成Java一样。

– Ned Batchelder
2014年8月24日在17:44

博格成语是解决此问题的更好方法。

– Rick支持Monica
15年1月26日在15:03

@NedBatchelder这是一个抽象类,仅用于子类化(和实例化子类)

–stevepastelan
18-09-24在16:53



我希望子类不要使用super()来调用其父级的__new__。

– Ned Batchelder
18/09/24在20:29

#11 楼

关于Python属性查找的一个非常有趣的观点是,它可以用于创建“虚拟变量”:

创建。请注意,查找使用self是因为尽管label在不与特定实例相关联的意义上是静态的,但该值仍取决于实例的(类别)。

#12 楼

是的,绝对可以在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


静态方法:类似于变量,可以使用Name类直接访问静态方法。无需创建实例。

但是请记住,静态方法不能在python中调用非静态方法。

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


#13 楼

关于此答案,对于常量静态变量,可以使用描述符。举个例子:

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,以获取有关描述符的更多信息。

评论


您也可以只使用@property,它与使用描述符相同,但是代码少得多。

– Rick支持Monica
2014年12月19日15:34

#14 楼

绝对可以,
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"


#15 楼

为了避免任何潜在的混乱,我想对比一下静态变量和不可变对象。

一些原始对象类型,例如整数,浮点数,字符串和touples在Python中是不可变的。这意味着如果给定名称引用的对象属于上述对象类型之一,则该对象无法更改。可以将名称重新分配给其他对象,但是对象本身不能更改。

使变量静态化可以更进一步,不允许变量名指向任何对象,而是指向任何对象。它目前指向。 (注意:这是一个通用的软件概念,并不特定于Python;有关在Python中实现静态信息的信息,请参见其他人的帖子。)

#16 楼

我发现最好的方法是使用另一个类。您可以创建一个对象,然后在其他对象上使用它。

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(私有静态变量)。

tryIt类表示我们需要使用的常规类。

现在我为一个标志创建了一个对象( staticFlag)。此标志将作为对所有常规对象的引用发送。

所有这些对象都将添加到列表tryArr中。


此脚本结果:

False
False
False
False
False
True
True
True
True
True


#17 楼

类工厂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


评论


是的,但是在这种情况下hasattr(SomeClass,'x')为False。我怀疑这是所有人所说的静态变量的全部含义。

– Rick支持Monica
17年7月25日在2:55

@RickTeachey大声笑,看到了您的静态变量代码,stackoverflow.com/a/27568860/2026508 +1互联网先生,我以为hasattr不能那样工作?那么some_var是不可变的并且是静态定义的,不是吗?外部获取方法的访问与变量是否为静态有什么关系?我现在有很多问题。希望在有空的时候听到一些答案。

–jmunsch
17年7月25日在19:09



是的,该元类非常荒谬。我不确定我是否理解问题,但在我看来,上述some_var根本不是类成员。在Python中,可以从类外部访问所有类成员。

– Rick支持Monica
17年7月25日在19:55

非本地键区使变量的范围“颠簸”。当您说非本地some_var时,类主体定义的范围独立于它在自身中找到的范围,也就是说,它只是创建对另一个命名对象的非本地(在类定义范围中为NOT)的名称引用。因此,它不属于类定义,因为它不在类主体范围内。

– Rick支持Monica
17年7月25日在19:59



#18 楼

因此,这可能是一种破解,但是我一直在使用python 3中的eval(str)获取静态对象,这有点矛盾。

有一个Records.py文件,除了class对象外没有其他使用保存一些参数的静态方法和构造函数定义。然后从另一个.py文件我import Records,但是我需要动态选择每个对象,然后根据读取的数据类型按需实例化它。

所以在object_name = 'RecordOne'或类名中,我调用cur_type = eval(object_name),然后实例化它,您可以执行cur_inst = cur_type(args),但是在实例化之前,您可以从cur_type.getName()调用静态方法,例如,类似于抽象基类实现或目标是什么。但是在后端,它可能是在python中实例化的,并且不是真正的静态对象,因为eval返回的是一个对象……必须已经实例化……会产生类似静态的行为。

#19 楼

您可以使用列表或字典来获取实例之间的“静态行为”。

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


#20 楼

例如,如果您尝试共享静态变量,例如在其他实例之间增加静态变量,则类似此脚本的代码就可以正常工作:

# -*- 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)


#21 楼

这样说来,当用户定义的类存在时将创建静态变量,并且定义静态变量时应在其后加上关键字self,
class Student:

    the correct way of static declaration
    i = 10

    incorrect
    self.i = 10