python中实例方法类方法和静态方法的区别,python中类方法,类实例方法,静态方法有何区别
Python中的方法是如何工作的
方法是作为类属性存在的函数。您可以通过以下方式声明和访问函数:
ClassPizza(对象):def _ _ init _ _ (self,size):自我。尺寸=大小.def get_size(自身):回归自我。大小.披萨。get _ size未绑定方法pizza。get _ size Python在告诉你。这是什么意思?很快我们就会知道答案:
pizza.get_size()Traceback(最近一次调用last):文件 stdin ,第1行,模块类型错误:必须用Pizza实例作为第一个参数调用无界方法get_size()我们不能调用这个,因为它还没有绑定到Pizza类的任何实例对象,它需要一个实例作为第一个参数传入(Python2必须是这个类的实例,它可以是Python3中的任何东西)。试试看:
Pizza.get_size(Pizza(42)) 42太棒了。现在用实例对象作为第一个参数调用它,整个世界都安静了。如果我说这种通话方式不是最方便的,你也会这么想;没错,现在我们每次调用这个方法都要引用这个类。随着代码量的增加,如果我们忘记了需要哪个类,就会造成程序的混乱,所以这种方法从长远来看是行不通的。
那么Python为我们做了什么呢?它绑定了Pizza类的所有方法和该类的任何实例的方法。这意味着现在属性get_size是Pizza的一个实例对象的绑定方法,这个方法的第一个参数是实例本身。
披萨(42)。get_size绑定方法Pizza。获取_ _ Main _ _的大小。0x7F3138827910 Pizza (42)处的Pizza对象。Get _ Size () 42正如我们所料,不再需要为Get _ Size提供任何参数,因为它已经被绑定了,它的self参数会自动。
M=比萨饼(42)。get_size m()42更重要的是,你不需要使用保存Pizza对象的引用,因为这个方法已经绑定了这个对象,所以这个方法本身就足够了。
也许,如果你想知道这个绑定方法绑定到哪个对象,下面的方法可以告诉你:
M=比萨饼(42)。Get _ size m. _ _ self _ _ _ main _ _。0x7F3138827910 #处的Pizza对象您可能会猜到,请看这个:m==m. _ _ self _ _。Get _ size true显然,这个对象还是有引用的。
在Python3中,附加在类上的函数不再被认为是一个未绑定的方法,而是一个简单的函数,如果需要的话,它将被绑定到一个对象上。原理仍然与Python2一致,但是模块更简单:
比萨类(对象):def __init__(self,Size):自我。尺寸=大小.def get _ size(自身):回归自我。大小.披萨。get _ size函数披萨。get _ size at0x7f 307 f 984 DD 0静态方法是一种特殊的方法。有时候你可能需要写一个属于这个类的方法,但是这些代码根本不会使用实例对象。
类Pizza(object):@ static method 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对象实例初始化绑定方法。绑定方法也是对象,但是创建它们是有代价的,静态方法可以避免这些。
披萨()。CookIsPizza()。烹饪假披萨()。Mix _ ingredients是披萨。Mix _ ingredients是真正的披萨()。Mix _ ingredients是披萨()。Mix _ ingredients是真的。这是一个可读性更强的代码。当我们看到@staticmethod时,我们知道这个方法不需要依赖于对象本身的状态。它可以在子类中被覆盖。如果将mix_ingredients作为模块的顶层函数,那么从pizza继承的子类如果不重写cook,就不能更改Pizza的mix_ingredients。什么是类方法?类不绑定到对象,而是绑定到类的方法。
比萨类(对象):半径=42.@classmethod.def get_radius(cls):返回cls.radius.类“__main__”的Pizza.get_radiusbound方法type.get_radius。披萨的披萨()。get _ radius绑定方法类型。获取类“_ _ main _ _”的半径。披萨披萨。get _ radius是pizza()。get _ radius真披萨。get _ radius () 42无论你以哪种方式访问这个方法,它总是绑定到这个类,它的第一个参数是类本身(记住
什么时候使用这种方法?在以下两种情况下,类通常非常有用:
工厂方法:用来创建类的实例,比如一些预处理。如果改为使用@staticmethod,那么我们必须在函数中硬编码Pizza类名,这使得任何继承Pizza的类都无法将我们的工厂方法用于自己的用途。class Pizza(object):def _ _ init _ _(self,ingredients):self . ingredients=ingredients @ class method def from _冰箱(cls,冰箱):Return CLS(冰箱. get _ cheese()冰箱. get _蔬菜())调用静态类:如果将一个静态方法拆分成多个静态方法,除非使用类方法,否则仍然需要硬编码类名。通过以这种方式声明方法,Pizza名称将不再被直接引用,并且继承和方法覆盖都可以完美地工作。类Pizza(object): def __init__(self,radius,height):self.radius=radius self . height=height @ static method def compute _ area(radius):return math . pi *(radius * * 2)@ classmethoddefcompute _ volume(cls,height,radius):return height * cls.com put _ area(radius)def get _ volume(self):return self.com put _ volume(self . height,self . radius)抽象方法
抽象方法是在基类中定义的方法,它不提供任何实现,类似于Java中接口中的方法。
在Python中实现抽象方法的最简单方式是:
class Pizza(object):def get_radius(self):raise notimplementerror任何从_Pizza继承的类都必须重写实现方法get _ radius,否则会抛出异常。
这种抽象方法的实现有其缺点。如果你写了一个继承Pizza的类,但是忘了实现get_radius,只有在你实际使用的时候才会抛出异常。
Pizza()__main__。0x7fb747353d90 Pizza()处的Pizza对象。Get _ radius()trace back(last recent call last):File stdin ,line 1,in module File stdin ,3,In Get _ RadiusNotImplementedError有另一种方法可以使错误提前触发。使用Python提供的abc模块,可以在对象初始化后抛出异常:
导入ABC class base pizza(object):_ _ metaclass _ _=ABC . ABC meta @ ABC . abstract method def get _ radius(self): 应该做一些事情的方法。使用abc后,当慢红酒尝试初始化BasePizza或者任何子类时,会立即得到TypeError,而不是等到实际调用get_radius才发现异常。
BasePizza()Traceback(最近一次调用last):文件 stdin ,第1行,模块类型错误:无法使用抽象方法get _ radius混合静态方法、类方法和抽象方法即时抽象基类Pizza。当慢红酒开始构建类和继承结构的时候,就是混合这些装饰器的时候了,所以这里有一些提示。
请记住,声明一个抽象方法不会修复方法的原型,这意味着尽管您必须实现它,但我可以用任何参数列表来实现它:
导入ABC类别基础pizza(对象):_ _元类__=abc .ABC meta @ ABC。抽象方法def get _ ingredients(self): 返回配料列表 class Calzone(基础披萨):def get _ ingredients(self,with _ Egg=False):Egg=Egg()if with _ Egg else None返回自制鸡蛋这样是允许的,因为Calzone满足基础披萨对象所定义的接口需求。同样我们也可以用一个类方法或静态方法来实现:
导入ABC类别基础pizza(对象):_ _元类__=abc .ABC meta @ ABC。抽象方法def get _ ingredients(self): 返回配料列表 class diet pizza(base pizza):@ static method def get _ ingredients():return None这同样是正确的,因为它遵循抽象类基础披萨设定的契约。事实上获取_配料方法并不需要知道返回结果是什么,结果是实现细节,不是契约条件。
因此,你不能强制抽象方法的实现是一个常规方法、或者是类方法还是静态方法,也没什么可争论的。从Python3开始(在Python2中不能如你期待的运行,见第5867期),在抽象方法方法上面使用@静态方法和@classmethod装饰器成为可能。
导入ABC类别基础pizza(对象):_ _元类__=abc .ABC元配料=[奶酪]@类方法@ ABC。抽象方法定义get _ ingredients(cls): 返回配料列表。返回cls .配料别误会了,如果你认为它会强制子类作为一个类方法来实现获取_配料那你就错了,它仅仅表示你实现的获取_配料在基础披萨中是一个类方法。
可以在抽象方法中做代码的实现?没错,Python与爪哇接口中的方法相反,你可以在抽象方法编写实现代码通过超级()来调用它。(译注:在Java8中,接口也提供的默认方法,允许在接口中写方法的实现)
导入ABC类别基础pizza(对象):_ _元类__=abc .ABC meta default _ ingredients=[ cheese ]@类方法@ ABC。抽象方法定义get _ ingredients(cls): 返回配料列表 返回cls。default _ ingredients类减肥披萨(基础披萨):def get _ ingredients(自我):return[ egg ]super(减肥披萨,自我).获取_配料()这个例子中,你构建的每个比萨饼都通过继承基础披萨的方式,你不得不覆盖获取_配料方法,但是能够使用默认机制通过超级()来获取原料列表。
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。