有个方法, 明明是属于类的, 却偏要称它为“实例方法”, 你会不会感到困惑呢? 更让人困惑的是后面——还有个“类方法”, 它的开头还要加上个符号, 接收的参数叫做cls而不是self。今天要把这两种方法一次性讲明白搞清楚, 顺便教你如何运用“工厂方法”一连串成功制造对象。咱们接着以工厂为例来进行说明: 类就如同厂房的模板, 实例则好比是出厂的产品。厂房之中, 既有着写明“每个产品自身会做些什么”的内容实例方法, 又有着写明“厂房层面统一的操作”的内容类方法。接下来逐个进行拆分。一、实例方法产品自己会干的事那在类当中所书写的方法, 像speak()用于讲话、run()用于奔跑, 这些方法全部都存储在类之上。可是视频里老师却再三着重强调一个违背直觉的要点:别看方法躺在谁身上要看它到底供谁调用。这些方法主要是给实例去进行调用的, 所以才被称作叫“实例方法”。名字是依据看“谁用”这种情况来起的, 并非是依据看“谁养”这种情形来起的。怎么验证打印一下实例的print(p1.__dict__) # 输出里只有 name、age、gender 这些属性 # 看不到 speak、run —— 方法根本不在实例身上方法明明是在类的身上, 实例身上并没有, 然而却能够借助实例正常进行调用, 依靠的便是前面讲述过的, 那种“先去寻找自身, 要是没有的话再去寻找它的父亲类”的查找顺序。① 通过实例调用 —— 正常p1.speak(你好) # 张三说你好 p1.run(300) # 张三疯狂地奔跑了300米 p2.run(100) # 李四疯狂地奔跑了100米② 通过类调用 —— 直接报错Person.run(你好) # TypeError: run() missing 1 required positional argument: self导致报错的原因相当关键, 你传进去的“你好”, 此物最终被塞给了 self , 如此一来, 跟在后面的参数便没有什么可以接收的了, 自然而然地就产生报错情况, 在某些人眼里, 这个字符串被错当成了“实例对象”, 这完全是张冠李戴的状况。③ 类调用也能救活但不推荐把实例亲手塞进去当self就能跑Person.run(p1, 100) # 张三疯狂地奔跑了100米 Person.run(p2, 100) # 李四疯狂地奔跑了100米能够运行成功, 然而老师原本所说的话是“不如直接就 p1.run(100) 得了”。既然可以运行, 为何要绕这样一个圈子呢? 所以这种书写方式是不值得这样做的。要记住, 方法是存放在类身上的, 不过被称作“实例方法”, 这是由于它是供实例使用的。这名字是依据“供谁调用”来定的, 而不是取决于“在谁身上”。二、类方法厂房层面的统一操作先于类之中书写两个平常的方法, 即刻弹出警告: “或许是”建议将其改成静态方法, 下一个章节才会讲解。若想要消除此警告, 只需于方法里运用一次 self 即可——但那采用的是实例方法的写法。现在正经把它俩改造成类方法class Person: # 实例方法 def speak(self, msg): print(f{self.name}说{msg}) # 类方法头上加 classmethod第一个参数写 cls classmethod def text_1(cls): print(我是text_1) classmethod def text_2(cls): print(我是text_2)① 是个装饰器给它进行翻译的结果呈现为就是“类方法” , 它身为一个装饰器 , 其装饰对象是紧挨着它的那一个特定方法。当你把它添加到相应之上 , 那么就仅仅只管 , 而丝毫碰不到。② 加上之后警告变了第一个参数, 通常被称作 cls, 它是 class 的简写, 它有着这样的要求, 它不想让你使用 self, 而是想让你转而使用 cls。为什么强制用 cls 而不是 self因为类方法收到的第一个参数是类本身不是实例对象。当前实例对象具体来说就是某个特定的与众不同的产品, 在实例方法里, 它是第一个专门被称为 self 的参数。• 类方法第一个参数 cls 类本身整个厂房模板③ 调用方式类方法通过类名调用才正规Person.text_1() # 正常那通过实例调用类方法行不行能跑但不推荐p1.text_1() # 能跑但特别不可取为什么不进行推荐呢, 这种写法给人的感觉好似是“p1创出了什么、p1是首个cls”, 然而实际上根本就不是这样的情况, 在别的语言当中要是你敢运用实例去调配类方法, 那直接就会报错, 毫无商量的余地, 相对比较温和一些, 是允许这么做了, 但是属于“能够运行并不等同于应该这么去写”。三、实战用类方法写个工厂方法类方法最为实用的场景, 在于当工厂方法, 并非沿着直接 new 的旧路径前行, 而是借助类自身的某一方法来协助你对原料予以加工, 并产出实例标点。我仅仅想要甩给你一个字符串, 这串是 “李四-1983-男”, 要让程序自行去拆分, 自己来计算年龄, 自己去构造类别。from datetime import datetime class Person: def __init__(self, name, age, gender): self.name name self.age age self.gender gender # 工厂方法用类方法接收字符串内部拆好、算好再创建实例 classmethod def create(cls, info_str): # 按 - 拆分李四-1983-男 name, birth_year, gender info_str.split(-) # 注意拆出来的全是字符串 # 拿到当前年份算出实际年龄 current_year datetime.now().year age current_year - int(birth_year) # 创建并返回实例 return Person(name, age, gender) # 调用工厂方法 p3 Person.create(李华-2003-女) print(p3.name, p3.age, p3.gender) # 李华 23 女这里面藏着几个新手容易卡的点挨个说用普通方式.你确实明晰了解年龄时, 会采用(李四, 19男)这种的形式而当仅晓得出生年份字符串之际, 会运用.(李四-1983-男)这种形式。这相当于额外给了你一种可选状况, 并非是取而代之, 乃是加以补充。其命名通常情况的话叫 或 , 当然也能够自行进行定义。四、实例方法 VS 类方法 一张表看透对比项实例方法类方法头上要不要装饰器不用必须加第一个参数self当前实例对象cls类本身正规调用方实例.方法()类名.方法()反向调用类名.方法() 要自己补 self不推荐实例.方法() 能跑但不推荐典型用途描述每个产品自己会干啥厂房级操作 / 工厂方法造实例三个坑新手必踩坑一, 要是认为那种写在类里、存在于类身上的方法, 就应该被称作类方法, 嘿嘿, 那就错得瞧瞧它是供谁调用的, 如果是供实例调用的话, 那它其实就是实例方法。坑第二种情况为, 类方法的第一个参数写成了self, 那么会直接给出警告, 应当写成cls, 这是因为接收到的乃是类本身。坑点三: 借助实例去调用类方法, 或者运用类去调用实例方法, 自以为“能跑”便觉得写妥当了, 然而, 能跑并不等同于被推荐, 正规的写法在上面的表格里已然明晰地呈现出来了。一个总结: self接收的是“人”存在具体例证, cls接收的是“厂”具体指类自身。是否带有的标识、第一个参数书写的对象, 构成为这两种方法最为关键的差异所在。下一个章节着重讲解静态方法, 该状态的出现甚至连self、cls都可摒弃, 更为简便省心。