如何在Python中创建类(即静态)变量或方法?


当前回答

所以这可能是一个黑客,但我一直在使用eval(str)来获取一个静态对象,这有点矛盾,在python 3中。

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

因此,在object_name=“RecordOne”或类名的情况下,我调用cur_type=eval(object_name),然后要实例化它,请执行cur_inst=cur_type(args)然而,在实例化之前,您可以从cur_type.getName()调用静态方法,例如,类似于抽象基类实现或任何目标。然而,在后端,它可能是在python中实例化的,并不是真正静态的,因为eval返回一个对象。。。。必须已实例化。。。。这会产生类似静态的行为。

其他回答

使用Object数据类型是可能的。但是对于bool、int、float或str等原始类型,bahaviour与其他OOP语言不同。因为在继承类中不存在静态属性。若继承类中不存在该属性,Python将开始在父类中查找该属性。如果在父类中找到,将返回其值。当您决定更改继承类中的值时,将在运行时创建静态属性。在下一次读取继承的静态属性时,将返回其值,因为它已经定义。对象(列表、字典)用作引用,因此可以安全地将它们用作静态属性并继承它们。对象地址在更改其属性值时不会更改。

整数数据类型示例:

class A:
    static = 1


class B(A):
    pass


print(f"int {A.static}")  # get 1 correctly
print(f"int {B.static}")  # get 1 correctly

A.static = 5
print(f"int {A.static}")  # get 5 correctly
print(f"int {B.static}")  # get 5 correctly

B.static = 6
print(f"int {A.static}")  # expected 6, but get 5 incorrectly
print(f"int {B.static}")  # get 6 correctly

A.static = 7
print(f"int {A.static}")  # get 7 correctly
print(f"int {B.static}")  # get unchanged 6

基于refdatatypes库的解决方案:

from refdatatypes.refint import RefInt


class AAA:
    static = RefInt(1)


class BBB(AAA):
    pass


print(f"refint {AAA.static.value}")  # get 1 correctly
print(f"refint {BBB.static.value}")  # get 1 correctly

AAA.static.value = 5
print(f"refint {AAA.static.value}")  # get 5 correctly
print(f"refint {BBB.static.value}")  # get 5 correctly

BBB.static.value = 6
print(f"refint {AAA.static.value}")  # get 6 correctly
print(f"refint {BBB.static.value}")  # get 6 correctly

AAA.static.value = 7
print(f"refint {AAA.static.value}")  # get 7 correctly
print(f"refint {BBB.static.value}")  # get 7 correctly

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

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,因为尽管标签在不与特定实例关联的意义上是静态的,但值仍然取决于(的类)实例。

您可以创建类变量x、实例变量名、实例方法test1(self)、类方法test2(cls)和静态方法test3(),如下所示:

class Person:
    x = "Hello" # Class variable

    def __init__(self, name):
        self.name = name # Instance variable
    
    def test1(self): # Instance method
        print("Test1")

    @classmethod
    def test2(cls): # Class method
        print("Test2")
        
    @staticmethod
    def test3(): # Static method
        print("Test3")

我在回答中解释了类变量,在回答中说明了类方法和静态方法,并在回答中介绍了实例方法。

@数据类定义提供用于定义实例变量和初始化方法__init__()的类级名称。如果要在@dataclass中使用类级变量,则应使用typeing.ClassVar类型提示。ClassVar类型的参数定义类级别变量的类型。

from typing import ClassVar
from dataclasses import dataclass

@dataclass
class Test:
    i: ClassVar[int] = 10
    x: int
    y: int
    
    def __repr__(self):
        return f"Test({self.x=}, {self.y=}, {Test.i=})"

用法示例:

> test1 = Test(5, 6)
> test2 = Test(10, 11)

> test1
Test(self.x=5, self.y=6, Test.i=10)
> test2
Test(self.x=10, self.y=11, Test.i=10)

可以使用静态类变量,但可能不值得这样做。

这里有一个用Python 3编写的概念证明——如果任何确切的细节都是错误的,那么可以对代码进行调整,以匹配静态变量所指的任何内容:


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