1 类的格式


1.1 分步展示

类声明三种方式
python class Stuff: python class Stuff(): python class Stuff(object):
类的属性
python pos = 'stuff' python def __init__(self, name): self.name = name
类的方法
python @classmethod def pr1(cls): print(cls.pos) python def pr2(self): print(self.name) python @staticmethod def pr3(): print('静态')
类的实例化
python # 通过索引 bill = Stuff('Bill') python # 通过关键字 bill = Stuff(name = 'Bill')
类的调用
python # 类属性调用 print(bill.pos) # 实例属性调用 print(bill.name) python # 类方法调用 bill.pr1() # 实例方法调用 bill.pr2() # 静态方法调用 bill.pr3()

1.2 整体展示

类定义格式
python # 类的声明 class Stuff: # 类属性 pos = 'stuff' # 类方法 @classmethod def pr1(cls): print(cls.pos) # 实例属性 def __init__(self, name): self.name = name # 实例方法 def pr2(self): print(self.name) # 静态属性 @staticmethod def pr3(): print('静态') # 通过索引实例化 bill = Stuff('Bill') # 通过关键字实例化 bill = Stuff(name = 'Bill') # 类属性调用 print(bill.pos) # 实例属性调用 print(bill.name) # 类方法调用 bill.pr1() # 实例方法调用 bill.pr2() # 静态方法调用 bill.pr3()

1.3 类的声明

类声明的三种方式
python class Stuff: python class Stuff(): python class Stuff(object):
  • 类名通常会以大写字母开头;
  • Python 3 以上,无论你是否显示继承自 object,Python 解释器都会默认你继承 object。

2 类的属性


2.1 类属性

类属性可看作是类的默认属性,在类实例化时不需要赋予变量;更改要在实例化后。

类属性在类方法和实例方法中都可以继续使用。

2.1.1 定义和调用

类属性
python class Stuff: # 类属性声明 pos = 'stuff' # 类的实例化 bill = Stuff() # 类属性调用 print(bill.pos) python # [属性名] = [数据] # 也可写作 bill = Stuff() stuff

2.1.2 实例中更改和调用

实例中更改类属性
python class Stuff: pos = 'stuff' susan = Stuff bill = Stuff peter = Stuff print(susan.pos) print(bill.pos) print(peter.pos) # 实例中更改类属性 susan.pos = 'leader' print(susan.pos) print(bill.pos) print(peter.pos) python stuff stuff stuff leader leader leader python class Stuff: pos = 'stuff' susan = Stuff() bill = Stuff() peter = Stuff() print(susan.pos) print(bill.pos) print(peter.pos) # 实例中更改类属性 susan.pos = 'leader' print(susan.pos) print(bill.pos) print(peter.pos) python stuff stuff stuff leader stuff stuff python class Stuff: pos = 'stuff' susan = Stuff() bill = Stuff() peter = Stuff() print(susan.pos) print(bill.pos) print(peter.pos) # 实例中更改类属性 Stuff.pos = 'leader' print(susan.pos) print(bill.pos) print(peter.pos) python stuff stuff stuff leader leader leader

2.1.3 方法中更改和调用

类方法中更改
python class Staff: pos = 'staff' # 通过 cls.[类属性名] 在类方法中调用 @classmethod def pr1(cls): print(f'{cls.pos} is not ok') # 通过 cls.[类属性名] 在类方法中更改 @classmethod def pr2(cls): cls.pos = 'leader' print(f'{cls.pos} is ok') bill = Staff() bill.pr1() bill.pr2() # 类属性更改随类走 eter = Staff() peter.pr1() python staff is not ok leader is ok leader is not ok
实例方法中更改 — class
python class Staff: pos = 'staff' # 通过 self.__class__.[类属性名] 在类方法中调用 def pr1(self): print(f'{self.__class__.pos} is not ok') # 通过 self.__class__.[类属性名] 在类方法中更改 def pr2(self): self.__class__.pos = 'leader' print(f'{self.__class__.pos} is ok') bill = Staff() # 类方法调用 bill.pr1() bill.pr2() peter = Staff() peter.pr1() python staff is not ok leader is ok leader is not ok

2.2 实例属性

实例属性可以是类实例化时就要赋值的属性,也可像类属性一样做成默认值。

实例属性可以在实例方法中继续使用。

2.2.1 定义和调用(init

init构造函数 创建 实例属性
python class Stuff: # 实例属性(初始化对象) def __init__(self,name): self.name = name # 类实例化并赋值 bill = Stuff('Bill') # 实例属性调用 print(bill.name) python # [属性名] = [数据] # 第一个参数必须是self,其次为其他参数 # self.[实例属性] = [参数] # 也可写作 bill = Stuff(name='Bill') Bill
实例属性默认值 / 实例属性也可实例化后更改
python class Stuff: def __init__(self,name): self.name = name self.pos = 'stuff' susan = Stuff('Susan') print(susan.pos) susan.pos = 'leader' print(susan.pos) python # 默认值不需要实例化时赋值,()不含属性名 # 直接把数据赋给实例属性 staff # 更改实例属性 leader

2.2.2 定义和调用(实例方法)

实例方法 创建 实例属性
python class Staff(): def pos(self, poss): # 通过方法添加实例属性 self.pos = poss # 类实例化 bill = Staff() # 添加实例属性 bill.pos = 'staff' # 实例属性调用 print(bill.pos) python staff

2.2.3 合法性验证(@property)

装饰器验证合法性 — property
python class Stuff: def __init__(self,name): self.name = name @property def age(self): return self.__age @age.setter def age(self, value): if 18 <= value <= 120: self.__age = value else: raise ValueError('Valid value must be in [18, 120]') def pr(self): print(f'{self.name} is {self.age}-year-old.') # 合理数据 bill = Stuff('Bill') bill.age = 29 bill.pr() # 不合理数据 janet = Stuff('Janet') janet.age = 16 janet.pr() python # 读取属性值的装饰器 # return 一个私有变量 # .setter 为对属性赋值的装饰器 Bill is 29-year-old. # 报错:ValueError: Valid value must be in [18, 120]
自制:实例方法 合法性验证(str辅助)
python class Test(object): def __init__(self, score): self.__score = score def __check_score(self): if not isinstance(self.__score, (int, float)): self.__score = 0 def __str__(self): self.__check_score() return str(self.__score) a = Test(123) print(a) a = Test('123') print(a) python 123 0

2.3 两属性技巧

2.3.1 参数统计

类属性 和 实例属性 计数
python class Hobbies(): num = 0 hobbies = [] def __init__(self,name): self.name = name @classmethod def hobby_add(cls,hobby): if hobby != '': cls.hobbies.append(hobby) cls.num += 1 @classmethod def hobbies_output(cls): return f'They have {cls.num} hobbies, thet are {cls.hobbies}.' peter = Hobbies('Peter') peter.hobby_add('learning') peter.hobby_add('video games') print(peter.hobbies_output()) joey = Hobbies('Joey') joey.hobby_add('breakfast') joey.hobby_add('lunch') joey.hobby_add('dinner') print(joey.hobbies_output()) '''返回: They have 2 hobbies, thet are ['learning', 'video games']. They have 5 hobbies, thet are ['learning', 'video games', 'breakfast', 'lunch', 'dinner']. ''' # 类属性,不分具体那个对象使用的方法,都统计在一起 python class Hobbies(): num = 0 def __init__(self,name): self.name = name self.hobbies = [] def hobby_add(self,hobby): if hobby != '': self.hobbies.append(hobby) self.num += 1 def __str__(self): return f'{self.name} has {self.num} hobbies, they are {self.hobbies}' peter = Hobbies('Peter') peter.hobby_add('learning') peter.hobby_add('video games') print(peter) joey = Hobbies('Joey') joey.hobby_add('breakfast') joey.hobby_add('lunch') joey.hobby_add('dinner') print(joey) ''' 返回: Peter has 2 hobbies, they are ['learning', 'video games'] Joey has 3 hobbies, they are ['breakfast', 'lunch', 'dinner'] ''' # 实例属性,会考虑每个方法都是那个对象使用的,分别统计

3 类的方法


笔者认为:类的方法都是为其属性服务的。

如果创建的方法未调用任何属性,则使用静态方法;

若创建的方法中只调用类属性,类方法就好;

只要创建的方法涉及实例参数,就是用实例方法吧!


3.1 类方法(@classmethod)

类方法
python class Stuff: pos = 'stuff' # 声明类方法 @classmethod def pr1(cls): print(f'{cls.pos} is ok') bill = Stuff() # 类方法调用 bill.pr1() python # 该关键字放在def前,说明该def是类方法 # 类方法第一参数必须为 cls # [类名].[类方法名]() stuff is ok

3.2 实例方法

实例方法
python class Stuff: pos = 'stuff' def __init__(self,name): self.name = name self.pr1() # 实例方法 def pr1(self): print(f'{self.name} is a {self.pos}.') bill = Stuff('Bill') # 实例方法调用 bill.pr1() python # 类属性可以 self.[类属性名] 的形式在实例方法中调用 # 实例属性可以 self.[实例属性名] 的形式在实例方法中调用 # 实例方法在类实例化时自动运行 # def的第一个参数必须是self Bill is a stuff. # 因为第6行代码 # [类名].[实例方法名]() Bill is a stuff.

3.3 静态方法(@staticmethod)

装饰器引导的静态方法
python class Stuff: @staticmethod def morning1(): print('Goodmorning.') bill = Stuff() bill.morning1() python # 该装饰器用来声明静态方法 # 静态方法的()不含任何参数 # 实体化 Goodmorning
由 ‘类方法’ 转换
python class Stuff: def morning2(): print('Goodmorning.') Stuff.morning2 = staticmethod(Stuff.morning2) bill = Stuff() bill.morning2() python # 看做()内没有self的实例方法 # staticmethod 将方法设定为静态变量; # 实例化 Goodmorning.

4 类的封装


4.1 属性封装(私有属性)

类属性封装
python class Test: a1 = 'a1' @classmethod def pr1(cls): print(cls.a01) test = Test() # 方法正常执行 test.pr1() # 属性正常返回 print(test.a1) python a1 a1 python class Test: _a2 = 'a2' @classmethod def pr2(cls): print(cls._a2) test = Test() # 方法正常执行 test.pr2() # 属性正常返回 print(test._a2) python a2 a2 python class Test: __a3 = 'a3' @classmethod def pr3(cls): print(cls.__a3) test = Test() # 方法正常执行 test.pr3() # 属性返回报错 print(test.__a3) # 强行返回该属性 print(test._Test__a3) python a3 报错:AttributeError: a3
实例属性封装
python class Test: def __init__(self): self.b1 = 'b1' def pr1(self): print(self.b1) test = Test() # 方法正常执行 test.pr1() # 属性正常返回 print(test.b1) python b1 b1 python class Test: def __init__(self): self._b2 = 'b2' def pr2(self): print(self._b2) test = Test() # 方法正常执行 test.pr1() # 属性正常返回 print(test._b2) python b2 b2 python class Test: def __init__(self): self.__b3 = 'b3' def pr3(self): print(self.__b3) test = Test() # 方法正常执行 test.pr3() # 属性返回报错 print(test.__b3) # 强行返回该属性 print(test._Test__b3) python b3 报错:AttributeError: b3

4.2 方法封装(私有方法)

方法封装
python class Test(object): @staticmethod def __封装方法(): return ('封装方法输出') @staticmethod def 输出方法(): return f'被调用的: {Test.__封装方法()}' a = Test() # 方法封装后无法直接使用 print(a.__封装方法()) # 方法封装后只能在非私有方法中调用 print(a.输出方法()) python 报错:AttributeError: 被调用的: 封装方法输出
方法封装的最常见应用
python class Test(object): __count = 0 def set_count(self, value): if self.__check_value(value): self.__class__.__count = value def get_count(self): return self.__count def __check_value(self, value): if isinstance(value, int): return True a = Test() print(a.get_count()) a.set_count(10) print(a.get_count())

5 类的继承

继承的类叫子类,被继承的类叫父类。


5.1 单继承

类的单继承
python class A(): a1 = 1 def __init__(self,b1): self.b1 = b1 def pr1(self): print(f'{self.a1}\t{self.b1}') def pr2(self): print(f'{self.a1}\t{self.b1}') test1 = A(1) test1.pr1() # 继承时,在()内写父类名,表对其继承 class B(A): def __init__(self,b1,b2): # 类属性继承:[父类名].__init__(self,[参数]) A.__init__(self,b1) self.b2 = b2 # 同名方法将覆盖父类的原方法 def pr2(self): print(f'{self.a1}\t{self.b1},{self.b2}') test2 = B(1,2) test2.pr1() test2.pr2() python 1 1 # 可使用魔法方法super(): # def __init__(self): # super().__init__() 1 1 1 1,2

5.2 多继承

多继承
python class A(): def __init__(self): self.输出 = 'A' def 方法(self): print(f'方法{self.输出}输出') class B(): def __init__(self,参数): self.输出1 = 'B' self.输出2 = 参数 def 方法(self): print(f'方法{self.输出1},{self.输出2}输出') # 传统写法在声明class时带父类名 class X(A,B): def __init__(self,参数): self.输出 = 'X' # 暂存,用参数再现传 self.参数 = 参数 def 方法(self): print(f'方法{self.输出}输出') def 方法_A(self): # 使用父属 父名.__init__(self,参) A.__init__(self) # 使用父方法 父名.方法名(self) A.方法(self) def 方法_B(self): B.__init__(self,self.参数) B.方法(self) # 之前用过的参数都被覆盖了[衰] x = X('B2') x.方法() # 方法X输出 x.方法_A() # 方法A输出 x.方法_B() # 方法B输出 python class A(): def __init__(self): self.输出 = 'A' def 方法(self): print(f'方法{self.输出}输出') class B(): def __init__(self,参数): self.输出1 = 'B' self.输出2 = 参数 def 方法(self): print(f'方法{self.输出1},{self.输出2}输出') # 嵌套式则不需要 class X(): def __init__(self,参数): self.输出 = 'X' # 子属代替父类 self.a = A() self.b = B(参数) def 方法(self): print(f'方法{self.输出}输出') def 方法_A(self): # 之前都整好了,nice self.a.方法() def 方法_B(self): self.b.方法() # 之前用过的参数随时调 def 方法_全参(self): # self.子属.父属 print(f'A参数{self.a.输出};B参数{self.b.输出1},{self.b.输出2}') x = X('B2') x.方法() # 方法X输出 x.方法_A() # 方法A输出 x.方法_B() # 方法B,B2输出 x.方法_全参() # A参数A;B参数B,B2
+ 私有属性和私有方法不能继承; + 私有属性和私有方法可以继承;

5.3 继承顺序

类的继承顺序
python class DA(object): @staticmethod def pr(): print('DA') class D(DA): pass class C(object): @staticmethod def pr(): print('C') class BAA(object): @staticmethod def pr(): print('BAA') class BB(object): @staticmethod def pr(): print('BB') class BA(BAA): pass class B(BA,BB): pass class A(B,C,D): pass # 实例化并输出 a = A() a.pr() # 输出类调用顺序 print(A.__mro__) # inspect 模块输出顺序 import inspect print(inspect.getmro(A)) python # 类在多继承时,如果被继承的类有相同名字的方法,同级的优先继承最左侧参数对应的类 # A > B > BA > BAA > BB > C > D > DA 画板 python BAA (<class '__main__.A'>, <class '__main__.B'>, <class '__main__.BA'>, <class '__main__.BAA'>, <class '__main__.BB'>, <class '__main__.C'>, <class '__main__.D'>, <class '__main__.DA'>, <class 'object'>) # 同上
super 函数
python class A(): def __init__(self): self.属性 = 'A' def 输出(self): print('类A输出') class B(A): def 输出(self): print('类B输出') # super()函数自动寻找顺位继承的类 class C(B): def __int__(self): super().__init__() def 输出(self): super().输出() c = C() print(c.属性) c.输出() python A 类B输出

5.4 类的多态

类的多态
python # 声明一个类A,方法都 pass class Language(object): def hello(self): pass def bye(self): pass # 将类A作为参数,创建两个类,使用和A1同名的方法,且这次带有返回值 class American(Language): def hello(self): print('Hello') def bye(self): print('Bye-Bye') class Chinese(Language): def hello(self): print('你好') def bye(self): print('拜了个拜') # 将两个继承后的类分别实例化 a = American() c = Chinese() # 创建函数,传参为被继承类A,函数中使用类的方法 def say_hello(Language): Language.hello() def say_bye(Language): Language.bye() # 使用实例化类名作为参数使用函数 say_hello(a) say_hello(c) say_bye(a) say_bye(c) python Hello 你好 Bye-Bye 拜了个拜

6 魔法方法


6.1 对象返回(str

对象返回
python class Staff: department = 'TPM' def __init__(self,name,pos='staff'): self.name = name self.pos = pos @property def job(self): return self.__job @job.setter def job(self, value): if value == 'BOM' or value == 'TE' or value == '1 to 1': self.__job = f', who works as a {value}' else: raise ValueError(f'Valid value is not include {value}') # str def __str__(self): return f'{self.name} is a {self.pos} in {self.department}{self.job}.' bill = Staff('Bill') bill.job = "TE print(bill) # 返回:Bill is a staff in TPM, who works as a TE.