it-swarm-vi.tech

Các biến lớp tĩnh có thể có trên Python không?

Có thể có các biến lớp hoặc phương thức tĩnh trong python không? Cú pháp nào là bắt buộc để làm điều này?

1710
Andrew Walker

Các biến được khai báo bên trong định nghĩa lớp, nhưng không phải bên trong một phương thức là các biến lớp hoặc biến tĩnh:

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

Như @ millerdev chỉ ra, điều này tạo ra biến i cấp độ lớp, nhưng điều này khác với bất kỳ biến i cấp độ cá thể nào, vì vậy bạn có thể có

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

Điều này khác với C++ và Java, nhưng không khác với C #, nơi một thành viên tĩnh không thể được truy cập bằng cách sử dụng một tham chiếu đến một thể hiện.

Xem những gì hướng dẫn Python nói về chủ đề của các lớp và các đối tượng lớp .

@Steve Johnson đã trả lời về phương thức tĩnh , cũng được ghi lại trong "Hàm tích hợp" trong Tham chiếu thư viện Python .

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

@beidy khuyến nghị classmethod s so với staticmethod, vì phương thức sau đó nhận loại lớp làm đối số đầu tiên, nhưng tôi vẫn hơi mờ về những lợi thế của phương pháp này so với phương pháp tĩnh. Nếu bạn cũng vậy, thì có lẽ không vấn đề gì.

1688
Blair Conrad

@Blair Conrad cho biết các biến tĩnh được khai báo bên trong định nghĩa lớp, nhưng không phải bên trong một phương thức là các biến lớp hoặc "tĩnh":

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

Có một vài gotcha ở đây. Tiếp tục từ ví dụ trên:

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

Lưu ý cách biến đối tượng t.i không đồng bộ với biến lớp "tĩnh" khi thuộc tính i được đặt trực tiếp trên t. Điều này là do i được liên kết lại trong không gian tên t, khác với không gian tên Test. Nếu bạn muốn thay đổi giá trị của biến "tĩnh", bạn phải thay đổi nó trong phạm vi (hoặc đối tượng) nơi nó được xác định ban đầu. Tôi đặt "static" trong dấu ngoặc kép vì Python không thực sự có biến tĩnh theo nghĩa mà C++ và Java làm.

Mặc dù nó không nói bất cứ điều gì cụ thể về các biến hoặc phương thức tĩnh, hướng dẫn Python có một số thông tin liên quan về các lớp và các đối tượng lớp .

@Steve Johnson cũng đã trả lời về các phương thức tĩnh, cũng được ghi lại trong phần "Các hàm tích hợp" trong Tài liệu tham khảo thư viện Python.

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

@beid cũng đề cập đến classmethod, tương tự như staticmethod. Đối số đầu tiên của classmethod là đối tượng lớp. Thí dụ:

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

562
millerdev

Phương thức tĩnh và lớp

Như các câu trả lời khác đã lưu ý, các phương thức tĩnh và lớp dễ dàng được thực hiện bằng cách sử dụng các trình trang trí tích hợp:

class Test(object):

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

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

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

Như thường lệ, đối số đầu tiên cho MyMethod() được liên kết với đối tượng thể hiện của lớp. Ngược lại, đối số đầu tiên cho MyClassMethod() bị ràng buộc với chính đối tượng lớp (ví dụ: trong trường hợp này, Test). Đối với MyStaticMethod(), không có đối số nào bị ràng buộc và có tất cả các đối số là tùy chọn.

"Biến tĩnh"

Tuy nhiên, việc triển khai "biến tĩnh" (tốt, biến tĩnh , dù sao đi nữa, nếu đó không phải là mâu thuẫn trong điều khoản ...) thì không đơn giản như vậy. Như millerdev đã chỉ ra trong câu trả lời của anh ấy , vấn đề là các thuộc tính lớp của Python không thực sự là "biến tĩnh". Xem xét:

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

Điều này là do dòng x.i = 12 đã thêm thuộc tính phiên bản mới i thành x thay vì thay đổi giá trị của thuộc tính Test lớp i.

Hành vi biến tĩnh một phần , nghĩa là đồng bộ hóa thuộc tính giữa nhiều trường hợp (nhưng không với bản thân lớp; xem "gotcha" bên dưới), có thể đạt được bằng cách biến thuộc tính lớp thành thuộc tính:

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)

Bây giờ bạn có thể làm:

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

Biến tĩnh bây giờ sẽ vẫn được đồng bộ hóa giữa tất cả các thể hiện của lớp .

(LƯU Ý: Nghĩa là, trừ khi một cá thể lớp quyết định xác định phiên bản _i của chính nó! Nhưng nếu ai đó quyết định làm THAT, họ xứng đáng với những gì họ nhận được, phải không ???)

Lưu ý rằng về mặt kỹ thuật, i hoàn toàn không phải là "biến tĩnh"; nó là một property, một loại mô tả đặc biệt. Tuy nhiên, hành vi property hiện tương đương với một biến tĩnh (có thể thay đổi) được đồng bộ hóa trên tất cả các thể hiện của lớp.

"Biến tĩnh" bất biến

Đối với hành vi biến tĩnh bất biến, chỉ cần bỏ qua bộ set 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)

Bây giờ khi cố gắng đặt thuộc tính i sẽ trả về một AttributeError:

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

Một Gotcha phải cảnh giác

Lưu ý rằng các phương thức trên chỉ hoạt động với thể hiện của lớp của bạn - chúng sẽ không hoạt động khi sử dụng chính lớp đó . Ví dụ:

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'

Dòng assert Test.i == x.i tạo ra lỗi, vì thuộc tính i của Testx là hai đối tượng khác nhau.

Nhiều người sẽ thấy điều này đáng ngạc nhiên. Tuy nhiên, nó không nên Nếu chúng tôi quay lại và kiểm tra định nghĩa lớp Test của chúng tôi (phiên bản thứ hai), chúng tôi lưu ý đến dòng này:

    i = property(get_i) 

Rõ ràng, thành viên i của Test phải là một đối tượng property, là loại đối tượng được trả về từ hàm property.

Nếu bạn thấy khó hiểu ở trên, rất có thể bạn vẫn đang nghĩ về nó từ quan điểm của các ngôn ngữ khác (ví dụ: Java hoặc c ++). Bạn nên nghiên cứu đối tượng property, về thứ tự trả về các thuộc tính Python, giao thức mô tả và thứ tự phân giải phương thức (MRO).

Tôi trình bày một giải pháp cho 'gotcha' ở trên; tuy nhiên tôi sẽ đề nghị - vất vả - rằng bạn không cố gắng làm điều gì đó như sau cho đến khi - tối thiểu - bạn hiểu thấu đáo lý do tại sao assert Test.i = x.i gây ra lỗi.

THỰC SỰ, THỰC TẾ Biến tĩnh - Test.i == x.i

Tôi trình bày giải pháp (Python 3) dưới đây chỉ cho mục đích thông tin. Tôi không xác nhận nó là một "giải pháp tốt". Tôi nghi ngờ liệu việc mô phỏng hành vi biến tĩnh của các ngôn ngữ khác trong Python có thực sự cần thiết hay không. Tuy nhiên, bất kể nó có thực sự hữu ích hay không, phần dưới đây sẽ giúp hiểu thêm về cách thức hoạt động của Python.

CẬP NHẬT: nỗ lực này thực sự khá khủng khiếp ; nếu bạn khăng khăng làm điều gì đó như thế này (gợi ý: xin đừng; Python là một ngôn ngữ rất tao nhã và khiến nó hành xử như một ngôn ngữ khác là không cần thiết), hãy sử dụng mã trong câu trả lời của Ethan Furman thay vào đó.

Mô phỏng hành vi biến tĩnh của các ngôn ngữ khác bằng cách sử dụng siêu dữ liệu

Một metaclass là lớp của một lớp. Siêu dữ liệu mặc định cho tất cả các lớp trong Python (tức là, các lớp "kiểu mới" đăng Python 2.3 tôi tin) là type. Ví dụ:

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

Tuy nhiên, bạn có thể định nghĩa siêu dữ liệu của riêng mình như thế này:

class MyMeta(type): pass

Và áp dụng nó cho lớp của riêng bạn như thế này (chỉ Python 3):

class MyClass(metaclass = MyMeta):
    pass

type(MyClass)  # class MyMeta

Dưới đây là một siêu dữ liệu tôi đã tạo để cố gắng mô phỏng hành vi "biến tĩnh" của các ngôn ngữ khác. Về cơ bản, nó hoạt động bằng cách thay thế getter, setter và deleter mặc định bằng các phiên bản kiểm tra xem liệu thuộc tính đang được yêu cầu có phải là "biến tĩnh" hay không.

Một danh mục của "biến tĩnh" được lưu trữ trong thuộc tính StaticVarMeta.statics. Tất cả các yêu cầu thuộc tính ban đầu được cố gắng giải quyết bằng cách sử dụng lệnh giải quyết thay thế. Tôi đã đặt tên này là "thứ tự độ phân giải tĩnh" hay "SRO". Điều này được thực hiện bằng cách tìm kiếm thuộc tính được yêu cầu trong tập hợp "biến tĩnh" cho một lớp nhất định (hoặc các lớp cha của nó). Nếu thuộc tính không xuất hiện trong "SRO", lớp sẽ rơi trở lại thuộc tính get/set/xóa thuộc tính mặc định (nghĩa là, "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.__+ " 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.__+ " 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
167
Rick Teachey

Bạn cũng có thể thêm các biến lớp vào các lớp một cách nhanh chóng

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

Và các thể hiện của lớp có thể thay đổi các biến lớp

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

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

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

Cá nhân tôi sẽ sử dụng một classmethod bất cứ khi nào tôi cần một phương thức tĩnh. Chủ yếu là vì tôi lấy lớp làm đối số.

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

hoặc sử dụng một trang trí

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

Đối với các thuộc tính tĩnh .. Đã đến lúc bạn tra cứu một số định nghĩa python .. biến luôn có thể thay đổi. Có hai loại trong số chúng có thể thay đổi và không thay đổi .. Ngoài ra, có các thuộc tính lớp và thuộc tính cá thể .. Không có gì thực sự giống như các thuộc tính tĩnh theo nghĩa của Java & c ++

Tại sao sử dụng phương thức tĩnh theo nghĩa Pythonic, nếu nó không liên quan gì đến lớp! Nếu tôi là bạn, tôi sẽ sử dụng classmethod hoặc định nghĩa phương thức độc lập với lớp.

15
emb

Các phương thức tĩnh trong python được gọi là classmethod s. Hãy xem đoạn mã sau

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

Lưu ý rằng khi chúng ta gọi phương thức myInstanceMethod , chúng ta sẽ gặp lỗi. Điều này là do nó yêu cầu phương thức đó được gọi trong một thể hiện của lớp này. Phương thức myStaticMethod được đặt làm phân loại bằng cách sử dụng trang trí @ classmethod .

Chỉ cần đá và cười khúc khích, chúng ta có thể gọi myInstanceMethod trên lớp bằng cách chuyển qua một thể hiện của lớp, như vậy:

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

Một điều đặc biệt cần lưu ý về thuộc tính tĩnh & thuộc tính thể hiện, được hiển thị trong ví dụ bên dưới:

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

Điều này có nghĩa là trước khi gán giá trị cho thuộc tính cá thể, nếu chúng ta cố gắng truy cập vào thể hiện của thuộc tính, giá trị tĩnh được sử dụng. Mỗi thuộc tính được khai báo trong lớp python luôn có một khe tĩnh trong bộ nhớ.

13
jondinham

Khi định nghĩa một số biến thành viên bên ngoài bất kỳ phương thức thành viên nào, biến có thể là tĩnh hoặc không tĩnh tùy thuộc vào cách biến được thể hiện.

  • ClassNAME.var là biến tĩnh
  • INSTANCENAME.var không phải là biến tĩnh.
  • self.var bên trong lớp không phải là biến tĩnh.
  • var bên trong hàm thành viên lớp không được xác định.

Ví dụ:

#!/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()

Kết quả là

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

Có thể có các biến lớp static, nhưng có lẽ không đáng để bỏ công sức.

Đây là một bằng chứng về khái niệm được viết bằng Python 3 - nếu bất kỳ chi tiết chính xác nào sai, mã có thể được điều chỉnh để khớp với bất cứ điều gì bạn muốn nói với một 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)

và đang sử dụng:

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

và một số xét nghiệm:

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
6
Ethan Furman

Bạn cũng có thể thực thi một lớp tĩnh bằng siêu dữ liệu.

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

Sau đó, bất cứ khi nào bạn vô tình cố gắng khởi tạo MyClass bạn sẽ nhận được một StaticClassError.

6
Bartosz Ptaszynski

Một điểm rất thú vị về tra cứu thuộc tính của Python là nó có thể được sử dụng để tạo " virtual biến":

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!

Thông thường không có bất kỳ sự phân công nào sau khi chúng được tạo. Lưu ý rằng việc tra cứu sử dụng self bởi vì, mặc dù label là tĩnh theo nghĩa không được liên kết với một thể hiện cụ thể , giá trị vẫn phụ thuộc vào (lớp) của ví dụ).

5
Davis Herring

Hoàn toàn có, Python tự nó không có bất kỳ thành viên dữ liệu tĩnh nào, nhưng chúng ta có thể có bằng cách làm như vậy

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

đầu ra

0
0
1
1

giải trình

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

Liên quan đến điều này câu trả lời , đối với biến tĩnh , bạn có thể sử dụng một mô tả. Đây là một ví dụ:

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

dẫn đến ...

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

Bạn luôn có thể đưa ra một ngoại lệ nếu lặng lẽ bỏ qua giá trị cài đặt (pass ở trên) không phải là vấn đề của bạn. Nếu bạn đang tìm kiếm một biến lớp tĩnh C++, kiểu 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

Hãy xem câu trả lời này và các tài liệu chính thức HOWTO để biết thêm thông tin về mô tả.

4
Yann

Cách tốt nhất tôi tìm thấy là sử dụng một lớp khác. Bạn có thể tạo một đối tượng và sau đó sử dụng nó trên các đối tượng khác.

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

Với ví dụ trên, tôi đã tạo một lớp có tên staticFlag.

Lớp này sẽ trình bày var __success (Var tĩnh riêng).

Lớp tryIt đại diện cho lớp thông thường mà chúng ta cần sử dụng.

Bây giờ tôi đã tạo một đối tượng cho một cờ (staticFlag). Cờ này sẽ được gửi làm tham chiếu cho tất cả các đối tượng thông thường.

Tất cả các đối tượng này đang được thêm vào danh sách tryArr.


Kết quả Script này:

False
False
False
False
False
True
True
True
True
True
3
Tomer Zait

Để tránh bất kỳ sự nhầm lẫn tiềm ẩn nào, tôi muốn đối chiếu các biến tĩnh và các đối tượng bất biến.

Một số loại đối tượng nguyên thủy như số nguyên, số float, chuỗi và touples là bất biến trong Python. Điều này có nghĩa là đối tượng được gọi bằng một tên cụ thể không thể thay đổi nếu nó thuộc một trong các loại đối tượng đã nói ở trên. Tên có thể được gán lại cho một đối tượng khác, nhưng bản thân đối tượng có thể không được thay đổi.

Làm cho một biến tĩnh thực hiện bước này thêm một bước nữa bằng cách không cho phép tên biến để trỏ đến bất kỳ đối tượng nào mà nó hiện đang trỏ tới. (Lưu ý: đây là khái niệm phần mềm chung và không dành riêng cho Python; vui lòng xem bài đăng của người khác để biết thông tin về việc triển khai thống kê trong Python).

3
Ross

Có, chắc chắn có thể viết các biến và phương thức tĩnh trong python.

Biến tĩnh : Biến được khai báo ở cấp lớp được gọi là biến tĩnh có thể được truy cập trực tiếp bằng tên lớp.

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

    >>> print(A.my_var)
        shagun

Biến Instance : Các biến có liên quan và được truy cập bởi thể hiện của một lớp là các biến thể hiện.

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

Phương thức tĩnh : Tương tự như biến, phương thức tĩnh có thể được truy cập trực tiếp bằng Tên lớp. Không cần phải tạo một ví dụ.

Nhưng hãy nhớ, một phương thức tĩnh không thể gọi một phương thức không tĩnh trong python.

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

Biến tĩnh trong lớp python3.6

Đối với bất kỳ ai sử dụng một nhà máy lớp với python3.6 và sử dụng từ khóa nonlocal để thêm nó vào phạm vi/bối cảnh của lớp được tạo như vậy:

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