python中的静态函数的用法(python类函数和静态函数)

发布时间:2022-11-13

本文目录一览:

1、python的静态方法有什么用 2、[python 里面有静态函数吗](#python 里面有静态函数吗) 3、如何在Python中使用static,class,abstract方法 4、Python中静态方法和类方法的区别

python的静态方法有什么用

Python的静态方法和类成员方法都可以被类或实例访问,两者概念不容易理清,但还是有区别的: 1)静态方法无需传入self参数,类成员方法需传入代表本类的cls参数; 2)从第1条,静态方法是无法访问实例变量的,而类成员方法也同样无法访问实例变量,但可以访问类变量; 3)静态方法有点像函数工具库的作用,而类成员方法则更接近类似Java面向对象概念中的静态方法。

python 里面有静态函数吗

Python的类里用@staticmethod的是静态方法,@classmethod的是类方法,如下:

class Person(object):
    person_list = []
    def __init__(self, name, age):
        self.name = name
        self.age = age
        self.person_list.append(self)
    @classmethod
    def one_year_later(cls):
        for p in cls.person_list:
            p.age += 1
    @staticmethod
    def born_one_boby(name):
        return Person(name, 0)
    def __repr__(self):
        return 'Person name:%s, age:%s' % (self.name, self.age)
if __name__ == '__main__':
    petter = Person('Petter', 23)
    merry = Person('Merry', 21)
    print(petter)  # Person name:Petter, age:23
    print(merry)  # Person name:Merry, age:21
    Person.one_year_later()
    print(petter)  # Person name:Petter, age:24
    print(merry)  # Person name:Merry, age:22
    baby = merry.born_one_boby('Tom')
    print(Person.person_list)  # [Person name:Petter, age:24, Person name:Merry, age:22, Person name:Tom, age:0]

如何在Python中使用static,class,abstract方法

方法在Python中是如何工作的

方法就是一个函数,它作为一个类属性而存在,你可以用如下方式来声明、访问一个函数:

class Pizza(object):
    def __init__(self, size):
        self.size = size
    def get_size(self):
        return self.size
Pizza.get_size

Python在告诉你,属性get_size是类Pizza的一个未绑定方法。这是什么意思呢?很快我们就会知道答案:

Pizza.get_size()
Traceback (most recent call last):
File "stdin", line 1, in module
TypeError: unbound method get_size() must be called with Pizza instance as first argument (got nothing instead)

我们不能这么调用,因为它还没有绑定到Pizza类的任何实例上,它需要一个实例作为第一个参数传递进去(Python2必须是该类的实例,Python3中可以是任何东西),尝试一下:

Pizza.get_size(Pizza(42))
42

太棒了,现在用一个实例作为它的的第一个参数来调用,整个世界都清静了。如果我说这种调用方式还不是最方便的,你也会这么认为的;没错,现在每次调用这个方法的时候我们都不得不引用这个类,如果不知道哪个类是我们的对象,长期看来这种方式是行不通的。 那么Python为我们做了什么呢?它绑定了所有来自类Pizza的方法以及该类的任何一个实例的方法。也就意味着现在属性get_sizePizza的一个实例对象的绑定方法,这个方法的第一个参数就是该实例本身。

Pizza(42).get_size
Pizza(42).get_size()
bound method Pizza.get_size of __main__.Pizza object at 0x7f3138827910
42

和我们预期的一样,现在不再需要提供任何参数给get_size,因为它已经是绑定的,它的self参数会自动地设置给Pizza实例,下面代码是最好的证明:

m = Pizza(42).get_size
m()
42

更有甚者,你都没必要使用持有Pizza对象的引用了,因为该方法已经绑定到了这个对象,所以这个方法对它自己来说是已经足够了。 也许,如果你想知道这个绑定的方法是绑定在哪个对象上,下面这种手段就能得知:

m = Pizza(42).get_size
m.__self__
__main__.Pizza object at 0x7f3138827910
m == m.__self__.get_size
True

显然,该对象仍然有一个引用存在,只要你愿意你还是可以把它找回来。 在Python3中,依附在类上的函数不再当作是未绑定的方法,而是把它当作一个简单的函数,如果有必要它会绑定到一个对象身上去,原则依然和Python2保持一致,但是模块更简洁:

class Pizza(object):
    def __init__(self, size):
        self.size = size
    def get_size(self):
        return self.size
Pizza.get_size
function Pizza.get_size at 0x7f307f984dd0

静态方法

静态方法是一类特殊的方法,有时你可能需要写一个属于这个类的方法,但是这些代码完全不会使用到实例对象本身,例如:

class Pizza(object):
    @staticmethod
    def mix_ingredients(x, y):
        return x + y
    def cook(self):
        return self.mix_ingredients(self.cheese, self.vegetables)

这个例子中,如果把mix_ingredients作为非静态方法同样可以运行,但是它要提供self参数,而这个参数在方法中根本不会被使用到。这里的@staticmethod装饰器可以给我们带来一些好处:

  • Python不再需要为Pizza对象实例初始化一个绑定方法,绑定方法同样是对象,但是创建他们需要成本,而静态方法就可以避免这些。
Pizza().cook is Pizza().cook
False
Pizza().mix_ingredients is Pizza.mix_ingredients
True
Pizza().mix_ingredients is Pizza().mix_ingredients
True
  • 可读性更好的代码,看到@staticmethod我们就知道这个方法并不需要依赖对象本身的状态。
  • 可以在子类中被覆盖,如果是把mix_ingredients作为模块的顶层函数,那么继承自Pizza的子类就没法改变pizzamix_ingredients了如果不覆盖cook的话。

类方法

话虽如此,什么是类方法呢?类方法不是绑定到对象上,而是绑定在类上的方法。

class Pizza(object):
    radius = 42
    @classmethod
    def get_radius(cls):
        return cls.radius
Pizza.get_radius
Pizza().get_radius
Pizza.get_radius is Pizza().get_radius
Pizza.get_radius()
bound method type.get_radius of class '__main__.Pizza'
bound method type.get_radius of class '__main__.Pizza'
True
42

无论你用哪种方式访问这个方法,它总是绑定到了这个类身上,它的第一个参数是这个类本身(记住:类也是对象)。 什么时候使用这种方法呢?类方法通常在以下两种场景是非常有用的:

工厂方法

它用于创建类的实例,例如一些预处理。如果使用@staticmethod代替,那我们不得不硬编码Pizza类名在函数中,这使得任何继承Pizza的类都不能使用我们这个工厂方法给它自己用。

class Pizza(object):
    def __init__(self, ingredients):
        self.ingredients = ingredients
    @classmethod
    def from_fridge(cls, fridge):
        return cls(fridge.get_cheese() + fridge.get_vegetables())

调用静态类

如果你把一个静态方法拆分成多个静态方法,除非你使用类方法,否则你还是得硬编码类名。使用这种方式声明方法,Pizza类名永远都不会在被直接引用,继承和方法覆盖都可以完美的工作。

class Pizza(object):
    def __init__(self, radius, height):
        self.radius = radius
        self.height = height
    @staticmethod
    def compute_area(radius):
        return math.pi * (radius ** 2)
    @classmethod
    def compute_volume(cls, height, radius):
        return height * cls.compute_area(radius)
    def get_volume(self):
        return self.compute_volume(self.height, self.radius)

抽象方法

抽象方法是定义在基类中的一种方法,它没有提供任何实现,类似于Java中接口(Interface)里面的方法。 在Python中实现抽象方法最简单的方式是:

class Pizza(object):
    def get_radius(self):
        raise NotImplementedError

任何继承自Pizza的类必须覆盖实现方法get_radius,否则会抛出异常。 这种抽象方法的实现有它的弊端,如果你写一个类继承Pizza,但是忘记实现get_radius,异常只有在你真正使用的时候才会抛出来。

Pizza()
Pizza().get_radius()
__main__.Pizza object at 0x7fb747353d90
Traceback (most recent call last):
File "stdin", line 1, in module
File "stdin", line 3, in get_radius
NotImplementedError

还有一种方式可以让错误更早的触发,使用Python提供的abc模块,对象被初始化之后就可以抛出异常:

import abc
class BasePizza(object):
    __metaclass__ = abc.ABCMeta
    @abc.abstractmethod
    def get_radius(self):
        """Method that should do something."""
BasePizza()
Traceback (most recent call last):
File "stdin", line 1, in module
TypeError: Can't instantiate abstract class BasePizza with abstract methods get_radius

混合静态方法、类方法、抽象方法

当你开始构建类和继承结构时,混合使用这些装饰器的时候到了,所以这里列出了一些技巧。 记住,声明一个抽象的方法,不会固定方法的原型,这就意味着虽然你必须实现它,但是我可以用任何参数列表来实现:

import abc
class BasePizza(object):
    __metaclass__ = abc.ABCMeta
    @abc.abstractmethod
    def get_ingredients(self):
        """Returns the ingredient list."""
class Calzone(BasePizza):
    def get_ingredients(self, with_egg=False):
        egg = Egg() if with_egg else None
        return self.ingredients + egg

这样是允许的,因为Calzone满足BasePizza对象所定义的接口需求。同样我们也可以用一个类方法或静态方法来实现:

import abc
class BasePizza(object):
    __metaclass__ = abc.ABCMeta
    @abc.abstractmethod
    def get_ingredients(self):
        """Returns the ingredient list."""
class DietPizza(BasePizza):
    @staticmethod
    def get_ingredients():
        return None

这同样是正确的,因为它遵循抽象类BasePizza设定的契约。事实上get_ingredients方法并不需要知道返回结果是什么,结果是实现细节,不是契约条件。 因此,你不能强制抽象方法的实现是一个常规方法、或者是类方法还是静态方法,也没什么可争论的。从Python3开始(在Python2中不能如你期待的运行,见issue5867),在abstractmethod方法上面使用@staticmethod@classmethod装饰器成为可能。

import abc
class BasePizza(object):
    __metaclass__ = abc.ABCMeta
    ingredient = ['cheese']
    @classmethod
    @abc.abstractmethod
    def get_ingredients(cls):
        """Returns the ingredient list."""
        return cls.ingredients

别误会了,如果你认为它会强制子类作为一个类方法来实现get_ingredients那你就错了,它仅仅表示你实现的get_ingredientsBasePizza中是一个类方法。 可以在抽象方法中做代码的实现?没错,Python与Java接口中的方法相反,你可以在抽象方法编写实现代码通过super()来调用它。(译注:在Java8中,接口也提供了默认方法,允许在接口中写方法的实现)

import abc
class BasePizza(object):
    __metaclass__ = abc.ABCMeta
    default_ingredients = ['cheese']
    @classmethod
    @abc.abstractmethod
    def get_ingredients(cls):
        """Returns the ingredient list."""
        return cls.default_ingredients
class DietPizza(BasePizza):
    def get_ingredients(self):
        return ['egg'] + super(DietPizza, self).get_ingredients()

这个例子中,你构建的每个pizza都通过继承BasePizza的方式,你不得不覆盖get_ingredients方法,但是能够使用默认机制通过super()来获取ingredient列表。 打赏支持我翻译更多好文章,谢谢!

Python中静态方法和类方法的区别

一、先是在语法上面的区别: 1、静态方法不需要传入self参数,类成员方法需要传入代表本类的cls参数; 2、静态方法是无法访问实例变量和类变量的,类成员方法无法访问实例变量但是可以访问类变量。 二、使用的区别: 由于静态方法无法访问类属性,实例属性,相当于一个相对独立的方法,跟类其实并没有什么关系。这样说来,静态方法就是在类的作用域里的函数而已。