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