Python 中的静态方法?

2024-12-04 08:56:00
admin
原创
192
摘要:问题描述:我可以定义一个可以在类实例上直接调用的静态方法吗?例如,MyClass.the_static_method() 解决方案 1:是的,使用staticmethod装饰器:class MyClass(object): @staticmethod def the_static_method...

问题描述:

我可以定义一个可以在类实例上直接调用的静态方法吗?例如,

MyClass.the_static_method()

解决方案 1:

是的,使用staticmethod装饰器:

class MyClass(object):
    @staticmethod
    def the_static_method(x):
        print(x)

MyClass.the_static_method(2)  # outputs 2

请注意,某些代码可能会使用定义静态方法的旧方法,将其用作staticmethod函数而不是装饰器。仅当必须支持旧版本的 Python(2.2 和 2.3)时才应使用此方法:

class MyClass(object):
    def the_static_method(x):
        print(x)
    the_static_method = staticmethod(the_static_method)

MyClass.the_static_method(2)  # outputs 2

这与第一个例子(使用)完全相同@staticmethod,只是没有使用好的装饰器语法。

最后,谨慎使用staticmethod!在 Python 中,很少需要使用静态方法,而且我见过很多次在使用单独的“顶级”函数会更清晰的情况下使用它们。


以下内容逐字摘自文档::

静态方法不接收隐式第一个参数。要声明静态方法,请使用以下习惯用法:

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

@staticmethod 形式是一个函数装饰器——有关详细信息,请参阅函数定义中函数定义的描述。

它可以在类(例如C.f())或实例(例如C().f())上调用。除了其类之外,实例将被忽略。

Python 中的静态方法与 Java 或 C++ 中的静态方法类似。有关更高级的概念,请参阅classmethod()

有关静态方法的更多信息,请查阅标准类型层次结构中标准类型层次结构的文档。

2.2 版本中的新功能。

在 2.4 版更改: 添加了函数装饰器语法。

解决方案 2:

我认为史蒂文实际上是对的。为了回答最初的问题,为了设置一个类方法,只需假设第一个参数不会是调用实例,然后确保只从类中调用该方法。

(请注意,这个答案是指 Python 3.x。在 Python 2.x 中,您将获得一个TypeError在类本身上调用方法的函数。)

例如:

class Dog:
    count = 0 # this is a class variable
    dogs = [] # this is a class variable

    def __init__(self, name):
        self.name = name #self.name is an instance variable
        Dog.count += 1
        Dog.dogs.append(name)

    def bark(self, n): # this is an instance method
        print("{} says: {}".format(self.name, "woof! " * n))

    def rollCall(n): #this is implicitly a class method (see comments below)
        print("There are {} dogs.".format(Dog.count))
        if n >= len(Dog.dogs) or n < 0:
            print("They are:")
            for dog in Dog.dogs:
                print("  {}".format(dog))
        else:
            print("The dog indexed at {} is {}.".format(n, Dog.dogs[n]))

fido = Dog("Fido")
fido.bark(3)
Dog.rollCall(-1)
rex = Dog("Rex")
Dog.rollCall(0)

在此代码中,“rollCall”方法假定第一个参数不是实例(如果它是由实例而不是类调用的,则为实例)。只要“rollCall”是从类而不是实例调用的,代码就可以正常工作。如果我们尝试从实例调用“rollCall”,例如:

rex.rollCall(-1)

但是,它会导致引发异常,因为它会发送两个参数:它本身和 -1,而“rollCall”仅定义为接受一个参数。

顺便说一句,rex.rollCall() 会发送正确数量的参数,但也会导致引发异常,因为当函数期望 n 为数字时,现在 n 代表一个 Dog 实例(即 rex)。

这就是装饰的作用所在:如果我们在“rollCall”方法前面加上

@staticmethod

然后,通过明确声明该方法是静态的,我们甚至可以从实例中调用它。现在,

rex.rollCall(-1)

可以工作。在方法定义前插入 @staticmethod 可以阻止实例将自身作为参数发送。

您可以通过尝试以下带有和不带有 @staticmethod 行注释的代码来验证这一点。

class Dog:
    count = 0 # this is a class variable
    dogs = [] # this is a class variable

    def __init__(self, name):
        self.name = name #self.name is an instance variable
        Dog.count += 1
        Dog.dogs.append(name)

    def bark(self, n): # this is an instance method
        print("{} says: {}".format(self.name, "woof! " * n))

    @staticmethod
    def rollCall(n):
        print("There are {} dogs.".format(Dog.count))
        if n >= len(Dog.dogs) or n < 0:
            print("They are:")
            for dog in Dog.dogs:
                print("  {}".format(dog))
        else:
            print("The dog indexed at {} is {}.".format(n, Dog.dogs[n]))


fido = Dog("Fido")
fido.bark(3)
Dog.rollCall(-1)
rex = Dog("Rex")
Dog.rollCall(0)
rex.rollCall(-1)

解决方案 3:

是的,检查一下静态方法装饰器:

>>> class C:
...     @staticmethod
...     def hello():
...             print "Hello World"
...
>>> C.hello()
Hello World

解决方案 4:

您实际上不需要使用@staticmethod装饰器。只需声明一个方法(不需要 self 参数)并从类中调用它。装饰器仅在您希望能够从实例中调用它的情况下存在(这不是您想要做的)

大多数情况下,你只需使用函数......

解决方案 5:

Python 中的静态方法?

Python 中是否可以有静态方法,以便我可以在不初始化类的情况下调用它们,例如:

ClassName.StaticMethod()

是的,静态方法可以像这样创建(尽管对于方法使用下划线而不是 CamelCase更符合Python 风格):

class ClassName(object):

    @staticmethod
    def static_method(kwarg1=None):
        '''return a value that is a function of kwarg1'''

上面使用了装饰器语法。此语法相当于

class ClassName(object):

    def static_method(kwarg1=None):
        '''return a value that is a function of kwarg1'''

    static_method = staticmethod(static_method)

这可以按照您描述的方式使用:

ClassName.static_method()

静态方法的内置示例在 Python 3 中,它是Python 2 中模块str.maketrans()中的一个函数。string


正如您所描述的,可以使用的另一个选项是classmethod,不同之处在于类方法将类作为隐式第一个参数,如果是子类,则它将子类作为隐式第一个参数。

class ClassName(object):

    @classmethod
    def class_method(cls, kwarg1=None):
        '''return a value that is a function of the class and kwarg1'''

请注意,这cls不是第一个参数的必需名称,但是如果您使用其他名称,大多数有经验的 Python 程序员都会认为这样做很糟糕。

这些通常用作替代构造函数。

new_instance = ClassName.class_method()

一个内置示例是dict.fromkeys()

new_dict = dict.fromkeys(['key1', 'key2'])

解决方案 6:

也许最简单的选择就是将这些函数放在类之外:

class Dog(object):
    def __init__(self, name):
        self.name = name

    def bark(self):
        if self.name == "Doggy":
            return barking_sound()
        else:
            return "yip yip"

def barking_sound():
    return "woof woof"

使用此方法,可以将修改或使用内部对象状态(具有副作用)的函数保留在类中,而将可重用的实用函数移到外部。

假设这个文件名为dogs.py。要使用这些,你应该调用dogs.barking_sound()而不是dogs.Dog.barking_sound

如果您确实需要静态方法作为类的一部分,那么可以使用静态方法装饰器。

解决方案 7:

除了静态方法对象行为的特殊性之外,在组织模块级代码时,它们还可以带来某种美感。

# garden.py
def trim(a):
    pass

def strip(a):
    pass

def bunch(a, b):
    pass

def _foo(foo):
    pass

class powertools(object):
    """
    Provides much regarded gardening power tools.
    """
    @staticmethod
    def answer_to_the_ultimate_question_of_life_the_universe_and_everything():
        return 42

    @staticmethod
    def random():
        return 13

    @staticmethod
    def promise():
        return True

def _bar(baz, quux):
    pass

class _Dice(object):
    pass

class _6d(_Dice):
    pass

class _12d(_Dice):
    pass

class _Smarter:
    pass

class _MagicalPonies:
    pass

class _Samurai:
    pass

class Foo(_6d, _Samurai):
    pass

class Bar(_12d, _Smarter, _MagicalPonies):
    pass

...

# tests.py
import unittest
import garden

class GardenTests(unittest.TestCase):
    pass

class PowertoolsTests(unittest.TestCase):
    pass

class FooTests(unittest.TestCase):
    pass

class BarTests(unittest.TestCase):
    pass

...

# interactive.py
from garden import trim, bunch, Foo

f = trim(Foo())
bunch(f, Foo())

...

# my_garden.py
import garden
from garden import powertools

class _Cowboy(garden._Samurai):
    def hit():
        return powertools.promise() and powertools.random() or 0

class Foo(_Cowboy, garden.Foo):
    pass

现在,它变得更加直观和自我记录,在何种情况下应该使用某些组件,并且它非常适合命名不同的测试用例,以及为纯粹主义者提供一种直接的方法来了解测试模块如何映射到实际测试模块。

我经常发现将这种方法应用于组织项目的实用代码是可行的。很多时候,人们会立即匆忙创建一个utils包,最终得到 9 个模块,其中一个模块有 120 行代码,其余模块最多只有 24 行代码。我更喜欢从这个开始,将其转换为包,然后只为真正值得拥有的模块创建模块:

# utils.py
class socket(object):
    @staticmethod
    def check_if_port_available(port):
        pass

    @staticmethod
    def get_free_port(port)
        pass

class image(object):
    @staticmethod
    def to_rgb(image):
        pass

    @staticmethod
    def to_cmyk(image):
        pass

解决方案 8:

因此,静态方法是无需创建类的对象即可调用的方法。例如:-

    @staticmethod
    def add(a, b):
        return a + b

b = A.add(12,12)
print b

在上面的例子中,方法add是通过类名A而不是对象名来调用的。

解决方案 9:

总结其他人的答案并补充,在python中有很多方法可以声明静态方法或变量。

  1. 使用staticmethod()作为装饰器:可以简单地将装饰器放在声明的方法(函数)上方,使其成为静态方法。例如。

class Calculator:
    @staticmethod
    def multiply(n1, n2, *args):
        Res = 1
        for num in args: Res *= num
        return n1 * n2 * Res

print(Calculator.multiply(1, 2, 3, 4))              # 24
  1. 使用staticmethod()作为参数函数:此方法可以接收函数类型的参数,并返回所传递函数的静态版本。例如。

class Calculator:
    def add(n1, n2, *args):
        return n1 + n2 + sum(args)

Calculator.add = staticmethod(Calculator.add)
print(Calculator.add(1, 2, 3, 4))                   # 10
  1. 使用classmethod()作为装饰器:@classmethod 对函数的作用与 @staticmethod 类似,但这次需要在函数中接受一个附加参数(类似于实例变量的 self 参数)。例如。

class Calculator:
    num = 0
    def __init__(self, digits) -> None:
        Calculator.num = int(''.join(digits))

    @classmethod
    def get_digits(cls, num):
        digits = list(str(num))
        calc = cls(digits)
        return calc.num

print(Calculator.get_digits(314159))                # 314159
  1. 使用classmethod()作为参数函数:如果不想修改类定义,也可以使用 @classmethod 作为参数函数。例如:

class Calculator:
    def divide(cls, n1, n2, *args):
        Res = 1
        for num in args: Res *= num
        return n1 / n2 / Res

Calculator.divide = classmethod(Calculator.divide)

print(Calculator.divide(15, 3, 5))                  # 1.0
  1. 直接声明 在所有其他方法之外但在类内部声明的方法/变量自动为静态。

class Calculator:   
    def subtract(n1, n2, *args):
        return n1 - n2 - sum(args)

print(Calculator.subtract(10, 2, 3, 4))             # 1

整个计划

class Calculator:
    num = 0
    def __init__(self, digits) -> None:
        Calculator.num = int(''.join(digits))
    
    
    @staticmethod
    def multiply(n1, n2, *args):
        Res = 1
        for num in args: Res *= num
        return n1 * n2 * Res


    def add(n1, n2, *args):
        return n1 + n2 + sum(args)
    

    @classmethod
    def get_digits(cls, num):
        digits = list(str(num))
        calc = cls(digits)
        return calc.num


    def divide(cls, n1, n2, *args):
        Res = 1
        for num in args: Res *= num
        return n1 / n2 / Res


    def subtract(n1, n2, *args):
        return n1 - n2 - sum(args)
    



Calculator.add = staticmethod(Calculator.add)
Calculator.divide = classmethod(Calculator.divide)

print(Calculator.multiply(1, 2, 3, 4))              # 24
print(Calculator.add(1, 2, 3, 4))                   # 10
print(Calculator.get_digits(314159))                # 314159
print(Calculator.divide(15, 3, 5))                  # 1.0
print(Calculator.subtract(10, 2, 3, 4))             # 1

请参阅Python 文档以掌握 Python 中的 OOP。

解决方案 10:

Python 静态方法可以通过两种方式创建。

  1. 使用 staticmethod()

class Arithmetic:
    def add(x, y):
        return x + y
# create add static method
Arithmetic.add = staticmethod(Arithmetic.add)

print('Result:', Arithmetic.add(15, 10))

输出:

结果:25

  1. 使用 @staticmethod

class Arithmetic:

# create add static method
@staticmethod
def add(x, y):
    return x + y

print('Result:', Arithmetic.add(15, 10))

输出:

结果:25

解决方案 11:

您可以使用@staticmethod装饰器来定义静态方法,如下所示。详细地,我在Python 中的 @classmethod vs @staticmethod的回答中解释了@staticmethod装饰器@classmethod装饰器,并在Python 中的“实例方法”是什么的回答解释实例方法

class Person:
    @staticmethod # Here
    def test():
        print("Test")

解决方案 12:

我时不时会遇到这个问题。我喜欢的用例和示例是:

jeffs@jeffs-desktop:/home/jeffs  $ python36
Python 3.6.1 (default, Sep  7 2017, 16:36:03) 
[GCC 6.3.0 20170406] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import cmath
>>> print(cmath.sqrt(-4))
2j
>>>
>>> dir(cmath)
['__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'acos', 'acosh', 'asin', 'asinh', 'atan', 'atanh', 'cos', 'cosh', 'e', 'exp', 'inf', 'infj', 'isclose', 'isfinite', 'isinf', 'isnan', 'log', 'log10', 'nan', 'nanj', 'phase', 'pi', 'polar', 'rect', 'sin', 'sinh', 'sqrt', 'tan', 'tanh', 'tau']
>>> 

创建 cmath 类的对象是没有意义的,因为 cmath 对象中没有状态。但是,cmath 是一组以某种方式相互关联的方法。在我上面的示例中,cmath 中的所有函数都以某种方式作用于复数。

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1565  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1354  
  信创国产芯片作为信息技术创新的核心领域,对于推动国家自主可控生态建设具有至关重要的意义。在全球科技竞争日益激烈的背景下,实现信息技术的自主可控,摆脱对国外技术的依赖,已成为保障国家信息安全和产业可持续发展的关键。国产芯片作为信创产业的基石,其发展水平直接影响着整个信创生态的构建与完善。通过不断提升国产芯片的技术实力、产...
国产信创系统   21  
  信创生态建设旨在实现信息技术领域的自主创新和安全可控,涵盖了从硬件到软件的全产业链。随着数字化转型的加速,信创生态建设的重要性日益凸显,它不仅关乎国家的信息安全,更是推动产业升级和经济高质量发展的关键力量。然而,在推进信创生态建设的过程中,面临着诸多复杂且严峻的挑战,需要深入剖析并寻找切实可行的解决方案。技术创新难题技...
信创操作系统   27  
  信创产业作为国家信息技术创新发展的重要领域,对于保障国家信息安全、推动产业升级具有关键意义。而国产芯片作为信创产业的核心基石,其研发进展备受关注。在信创国产芯片的研发征程中,面临着诸多复杂且艰巨的难点,这些难点犹如一道道关卡,阻碍着国产芯片的快速发展。然而,科研人员和相关企业并未退缩,积极探索并提出了一系列切实可行的解...
国产化替代产品目录   28  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用