代码之家  ›  专栏  ›  技术社区  ›  Andrew Walker

静态类变量是否可能?

  •  1642
  • Andrew Walker  · 技术社区  · 16 年前

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

    17 回复  |  直到 6 年前
        1
  •  1616
  •   Melebius    7 年前

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

    millerdev i

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

    what the Python tutorial has to say on the subject of classes and class objects

    static methods "Built-in Functions" in the Python Library Reference

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

    classmethod

        2
  •  548
  •   NITIN SRIVASTAV    7 年前

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

    Python tutorial classes and class objects

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

    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 the the same as  Test.i = arg1
    

    Pictorial Representation Of Above Example

        3
  •  161
  •   Rick SilentGhost    7 年前

    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()

    pointed out in his answer

    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

    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

    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)
    

    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 = property(get_i) 
    

    assert Test.i = x.i

    Test.i == x.i

    Ethan Furman's answer

    type

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

    class MyMeta(type): pass
    

    class MyClass(metaclass = MyMeta):
        pass
    
    type(MyClass)  # class MyMeta
    

    StaticVarMeta.statics

    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
    
        4
  •  24
  •   Ned Batchelder    10 年前

    >>> 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]
    
        5
  •  14
  •   emb    16 年前

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

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

        6
  •  13
  •   jondinham    13 年前

    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
    

        7
  •  13
  •   Andrii Abramov Mk.Sl.    7 年前

    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
    

    decorator

    >>> MyClass.myInstanceMethod(MyClass())
    output from an instance method
    
        8
  •  8
  •   Markus    8 年前

    #!/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
    
        9
  •  6
  •   Bartosz Ptaszynski    13 年前

    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
    

        10
  •  5
  •   Ethan Furman    9 年前

    static

    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
    
        11
  •  5
  •   Sanju    7 年前

    virtual

    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

        12
  •  3
  •   Ross    16 年前

        13
  •  3
  •   Remi Guan cdlane    8 年前

    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

    tryArr


    False
    False
    False
    False
    False
    True
    True
    True
    True
    True
    
        14
  •  3
  •   Mari Selvan    8 年前

    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
  •  2
  •   Community CDub    7 年前

    answer

    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

    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
    

    this answer HOWTO

        16
  •  1
  •   jmunsch Colin Pickard    8 年前

    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
    
        17
  •  1
  •   Shagun Pruthi    6 年前

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

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