关于如何在Python中使用静态、类或抽象方法的权威指南

Python中方法的工作方式

方法是存储在类属性中的函数,你可以用下面这种方式声明和访问一个函数

    >>> class Pizza(object):...     def __init__(self, size):...         self.size = size...     def get_size(self):...         return self.size...>>> Pizza.get_size<unbound method Pizza.get_size>

 Python在这里说明了什么?Pizza类的属性get_size是unbound(未绑定的),这代表什么含义?我们调用一下就明白了:

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

我们无法调用它(get_size),因为它没有绑定到Pizza的任何实例上,而且一个方法需要一个实例作为它的第一个参数(Python2中必须是类的实例,Python3没有这个强制要求),让我们试一下:

    >>> Pizza.get_size(Pizza(42))42

我们使用一个实例作为这个方法的第一个参数来调用它,没有出现任何问题。但是如果我说这不是一个方便的调用方法的方式,你将会同意我的观点。我们每次调用方法都要涉及(这里我理解是引用)类

来看Python打算为我们做些什么,就是它从Pizza类中绑定所有的方法到这个类的任何实例上。意思就是Pizza实例化后get_size这个属性是一个绑定方法,方法的第一个参数会是实例对象自己

    >>> Pizza(42).get_size<bound method Pizza.get_size of <__main__.Pizza object at 0x7f3138827910>>>>> Pizza(42).get_size()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>>>> # You could guess, look at this:...>>> m == m.__self__.get_sizeTrue

明显可以看出,我们仍然保持对我们对象的引用,而且如果需要我们可以找到它

在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):@staticmethoddef mix_ingredients(x, y):return x + ydef cook(self):return self.mix_ingredients(self.cheese, self.vegetables)

上面这个例子,mix_ingredients完全可以写成一个非静态方法,但是这样会将self作为第一个参数传入。在这个例子里,装饰器@staticmethod 会实现几个功能:

Python不会为Pizza的实例对象实例化一个绑定方法,绑定方法也是对象,会产生开销,静态方法可以避免这类情况

        >>> Pizza().cook is Pizza().cookFalse>>> Pizza().mix_ingredients is Pizza.mix_ingredientsTrue>>> Pizza().mix_ingredients is Pizza().mix_ingredientsTrue

简化了代码的可读性,看到@staticmethod我们就会知道这个方法不会依赖这个对象的状态(一国两制,高度自治)
允许在子类中重写mix_ingredients方法。如果我们在顶级模型中定义了mix_ingredients函数,继承自Pizza的类除了重写,否则无法改变mix_ingredients的功能

类方法

什么是类方法,类方法是方法不会被绑定到一个对象,而是被绑定到一个类中

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

无论以何种方式访问这个方法,它都会被绑定到类中,它的第一个参数必须是类本身(记住类也是对象)


什么时候使用类方法,类方法在以下两种场合会有很好的效果:
    1、工厂方法,为类创建实例,例如某种程度的预处理。如果我们使用@staticmethod代替,我们必须要在代码中硬编码Pizza(写死Pizza),这样从Pizza继承的类就不能使用了

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

  2、使用静态方法调用静态方法,如果你需要将一个静态方法拆分为多个,可以使用类方法来避免硬编码类名。使用这种方法来声明我们的方法Pizza的名字永远不会被直接引用,而且继承和重写方法都很方便

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

抽象方法

抽象方法是定义在基类中的,可以是不提供任何功能代码的方法
在Python中简单的写抽象方法的方式是:

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

继承自Pizza的类都必须要实现并重写get_redius,否则就会报错

这种方式的抽象方法有一个问题,如果你忘记实现了get_radius,只有在你调用这个方法的时候才会报错

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

使用python的abc模块可以是这个异常被更早的触发

    import abcclass BasePizza(object):__metaclass__  = abc.ABCMeta@abc.abstractmethoddef get_radius(self):"""Method that should do something."""

使用abc和它的特殊类,如果你尝试实例化BasePizza或者继承它,都会得到TypeError错误

    >>> BasePizza()
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: Can't instantiate abstract class BasePizza with abstract methods get_radius

备注:我使用Python3.6实现的代码  

    In [8]: import abc...:...: class BasePizza(abc.ABC):...:...:     @abc.abstractmethod...:     def get_radius(self):...:          """:return"""...:In [9]: BasePizza()---------------------------------------------------------------------------TypeError                                 Traceback (most recent call last)<ipython-input-9-70b53ea21e68> in <module>()----> 1 BasePizza()TypeError: Can't instantiate abstract class BasePizza with abstract methods get_radius

混合静态,类和抽象方法

当需要创建类和继承时,如果你需要混合这些方法装饰器,这里有一些小窍门建议给你
记住要将方法声明为抽象,不要冻结这个方法的原型。意思是它(声明的方法)必须要执行,但是它在执行的时候,参数不会有任何限制

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

这样是有效的,因为Calzone实现了我们为BasePizza定义的接口要求,这意味着我们也可以将它实现为一个类或者静态方法,例如:

        import abcclass BasePizza(object):__metaclass__  = abc.ABCMeta@abc.abstractmethoddef get_ingredients(self):"""Returns the ingredient list."""class DietPizza(BasePizza):@staticmethoddef get_ingredients():return None

这也是正确的,它实现了抽要BasePizza的要求,事实上是get_ingredioents方法不需要知道对象返回的结果,
因此,你不需要强制抽象方法实现成为常规方法、类或者静态方法。在python3中,可以将@staticmethod和@classmethod装饰器放在@abstractmethod上面

        import abcclass BasePizza(object):__metaclass__  = abc.ABCMetaingredient = ['cheese']@classmethod@abc.abstractmethoddef get_ingredients(cls):"""Returns the ingredient list."""return cls.ingredients

和Java的接口相反,你可以在抽象方法中实现代码并通过super()调用它

        import abcclass BasePizza(object):__metaclass__  = abc.ABCMetadefault_ingredients = ['cheese']@classmethod@abc.abstractmethoddef get_ingredients(cls):"""Returns the ingredient list."""return cls.default_ingredientsclass DietPizza(BasePizza):def get_ingredients(self):return ['egg'] + super(DietPizza, self).get_ingredients()

在上面的例子中,继承BasePizza来创建的每个Pizza都必须重写get_ingredients 方法,但是可以使用super()来获取default_ingredients

 

本文翻译自:https://julien.danjou.info/guide-python-static-class-abstract-methods/

转载于:https://www.cnblogs.com/flashBoxer/p/9814012.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/388199.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

广义估计方程估计方法_广义估计方程简介

广义估计方程估计方法A key assumption underpinning generalized linear models (which linear regression is a type of) is the independence of observations. In longitudinal data this will simply not hold. Observations within an individual (between time points) …

css二

结构性伪类:nth-child(index)系列1.:first-child2.:last-child3.nth-last-child(index)4.only-child :nth-of-type(index)系列1.first-of-type2.last-of-type3.nth-last-type(index)4.only-of-type :not伪类处理导航栏最后一个竖划线a:not(:last-of-type) :empty伪类 选中所有内…

Unity3d鼠标点击屏幕来控制人物的走动

今天呢&#xff0c;我们来一起实现一个在RPG中游戏中十分常见的功能&#xff0c;通过鼠标点击屏幕来控制人物的走动。首先来说一下原理&#xff0c;当我们点击屏幕时&#xff0c;我们按照一定的方法&#xff0c;将屏幕上的二维坐标转化为三维坐标&#xff0c;然后我们从摄像机位…

Java中的ReentrantLock和synchronized两种锁定机制的对比

2019独角兽企业重金招聘Python工程师标准>>> 多线程和并发性并不是什么新内容&#xff0c;但是 Java 语言设计中的创新之一就是&#xff0c;它是第一个直接把跨平台线程模型和正规的内存模型集成到语言中的主流语言。核心类库包含一个 Thread 类&#xff0c;可以用它…

10.15 lzxkj

几天前写的&#xff0c;忘了放了&#xff0c;在此填坑 10月16的题我出的不写题解了 lzxkj 题目背景 众所不周知的是&#xff0c; 酒店之王 xkj 一个经常迷失自我的人 有一天&#xff0c; 当起床铃再一次打响的时候&#xff0c; TA 用 O(1)的时间在 TA 那早就已经生锈的大脑中自…

大数定理 中心极限定理_中心极限定理:直观的遍历

大数定理 中心极限定理One of the most beautiful concepts in statistics and probability is Central Limit Theorem,people often face difficulties in getting a clear understanding of this and the related concepts, I myself struggled understanding this during my…

万恶之源 - Python数据类型二

列表 列表的介绍 列表是python的基础数据类型之一 ,其他编程语言也有类似的数据类型. 比如JS中的数 组, java中的数组等等. 它是以[ ]括起来, 每个元素用 , 隔开而且可以存放各种数据类型: lst [1,a,True,[2,3,4]]列表相比于字符串,不仅可以存放不同的数据类型.而且可…

230. Kth Smallest Element in a BST

Given a binary search tree, write a function kthSmallest to find the kth smallest element in it.Note: You may assume k is always valid, 1 ≤ k ≤ BSTs total elements.Example 1: Input: root [3,1,4,null,2], k 13/ \1 4\2 Output: 1 Example 2: Input: root …

探索性数据分析(EDA)-不要问如何,不要问什么

数据科学 &#xff0c; 机器学习 (Data Science, Machine Learning) This is part 1 in a series of articles guiding the reader through an entire data science project.这是一系列文章的第1部分 &#xff0c;指导读者完成整个数据科学项目。 I am a new writer on Medium…

unity3d 摄像机跟随鼠标和键盘的控制

鼠标控制&#xff1a; using UnityEngine; using System.Collections; public class shubiao : MonoBehaviour { //public Transform firepos; public int Ball30; public int CurBall1; public Rigidbody projectile; public Vector3 point; public float time100f; public…

《必然》九、享受重混盛宴,是每个人的机会

今天说的是《必然》的第七个关键词&#xff0c;过滤Filtering。1我们需要过滤如今有一个问题&#xff0c;弥漫在我们的生活当中&#xff0c;困扰着所有人。那就是“今天我要吃什么呢&#xff1f;”同样的&#xff0c;书店里这么多的书&#xff0c;我要看哪一本呢&#xff1f;网…

IDEA 插件开发入门教程

2019独角兽企业重金招聘Python工程师标准>>> IntelliJ IDEA 是目前最好用的 JAVA 开发 IDE&#xff0c;它本身的功能已经非常强大了&#xff0c;但是每个人的需求不一样&#xff0c;有些需求 IDEA 本身无法满足&#xff0c;于是我们就需要自己开发插件来解决。工欲善…

安卓代码还是xml绘制页面_我们应该绘制实际还是预测,预测还是实际还是无关紧要?

安卓代码还是xml绘制页面Plotting the actual and predicted data is frequently used for visualizing and analyzing how the actual data correlate with those predicted by the model. Ideally, this should correspond to a slope of 1 and an intercept of 0. However, …

Mecanim动画系统

本期教程和大家分享Mecanim动画系统的重定向特性&#xff0c;Mecanim动画系统是Unity3D推出的全新的动画系统&#xff0c;具有重定向、可融合等诸多新特性&#xff0c;通过和美工人员的紧密合作&#xff0c;可以帮助程序设计人员快速地设计出角色动画。一起跟着人气博主秦元培学…

【嵌入式硬件Esp32】Ubuntu 1804下ESP32交叉编译环境搭建

一、ESP32概述EPS32是乐鑫最新推出的集成2.4GWi-Fi和蓝牙双模的单芯片方案&#xff0c;采用台积电(TSMC)超低功耗的40nm工艺&#xff0c;拥有最佳的功耗性能、射频性能、稳定性、通用性和可靠性&#xff0c;适用于多种应用和不同的功耗要求。 ESP32搭载低功耗的Xtensa LX6 32bi…

你认为已经过时的C语言,是如何影响500万程序员的?...

看招聘职位要c语言的占比真不多了&#xff0c;是否c语言真得落伍了&#xff1f; 看一下许多招聘平台有关于找纯粹的c语言开发的占比确实没有很多&#xff0c;都被Java&#xff0c;php&#xff0c;python等等語言刷屏。这对于入门正在学习c语言的小白真他妈就是惊天霹雳&#xf…

换热站起停条件

循环泵 自动条件&#xff1a; 一、循环泵启动条件 两台泵/三台泵&#xff1a; 1&#xff09;本循环泵在远程状态 2&#xff09;本循环泵自动状态 3&#xff09;本循环泵没有故障 4&#xff09;二次网的回水压力&#xff08;测量值&#xff09;>设定值 5&#xff09;…

云尚制片管理系统_电影制片厂的未来

云尚制片管理系统Data visualization is a key step of any data science project. During the process of exploratory data analysis, visualizing data allows us to locate outliers and identify distribution, helping us to control for possible biases in our data ea…

JAVA单向链表实现

JAVA单向链表实现 单向链表 链表和数组一样是一种最常用的线性数据结构&#xff0c;两者各有优缺点。数组我们知道是在内存上的一块连续的空间构成&#xff0c;所以其元素访问可以通过下标进行&#xff0c;随机访问速度很快&#xff0c;但数组也有其缺点&#xff0c;由于数组的…

软件公司管理基本原则

商业人格&#xff1a;独立履行责任 独立坚持原则两大要素&#xff1a;1)靠原则做事&#xff0c;原则高于一切。2)靠结果做交换&#xff0c;我要什么我清楚两个标准&#xff1a; 1)我不是孩子&#xff0c;我不需要照顾2)承认逻辑&#xff0c;我履行我的责任社会人心态: 1)用社会…