1. 类的成员
class Foo: # 方法 def __init__(self,name): # 实例变量/字段 self.name = name # 方法 def func(self): pass # 属性 @ property def func2(self): return .. # obj,Foo类的对象 # obj,Foo类的实例 obj = Foo('闫子哲') 成员共分为三类: 1. 变量 2. 方法 3. 属性
1.1 变量 变量: - 实例变量(字段) - 公有实例变量(公有字段) - 私有实例变量(私有字段) - 类变量(静态字段) - 公有类变量(公有静态字段) - 私有类变量(私有静态字段) (1) 字段 class Foo: # 类变量(静态字段) conutry = "中国" def __init__(self, name): # 实例变量/字段 self.name = name def func(self): pass 知识点一: # 准则: # 对于实例变量(字段)访问时,使用对象访问,即: obj1.name # 类变量(静态字段)访问时,使用类方法,即: Foo.country (实在不方便时,才用对象) obj1 = Foo('西瓜') obj2 = Foo('冬瓜') print(obj1.name) print(Foo.country) # obj1.conutry 易错点: obj1 = Foo('西瓜') obj2 = Foo('冬瓜') # 练习1 obj1.name = 'alex' print(obj1.name) # alex print(obj2.name) # 冬瓜 # 练习2 obj1.country = '美国' print(obj1.country) # 美国 print(obj2.country) # 中国 # 练习3 Foo.country = '美国' print(obj1.country) # 美国 print(obj2.country) # 美国 (2) 字段成员修饰符 -----------------------公有实例变量(字段) ----------------------- # 公有实例变量(字段): 内外部都可以访问 class Foo: def __init__(self,name): self.name = name self.age = 123 def func(self): print(self.name) obj = Foo('闫子哲') print(obj.name) print(obj.age) # 外部可以访问 obj.func() # 内部也可以访问 ---------------------- 私有实例变量(私有字段) ------------------- # 私有实例变量(私有字段): 内部可以访问,外部不能访问 class Foo: def __init__(self, name): # 私有实例变量(私有字段) self.__name = name self.age = 123 def func(self): print(self.__name) obj = Foo('闫子哲') print(obj.age) # obj.__name # 无法访问(外部) obj.func() # 间接访问,找一个内部人:func, 让func帮助你执行内部私有__name --------------------- 公有类变量(公有静态字段) --------------- class Foo: country = "中国" def __init__(self): pass def func(self): # 内部调用 print(self.country) print(Foo.country) # 推荐 # 外部调用 print(Foo.country) obj = Foo() obj.func() -------------------- 私有类变量(私有静态字段) --------------- class Foo: __country = "中国" def __init__(self): pass def func(self): # 内部调用 print(self.__country) print(Foo.__country) # 推荐 # 外部无法调用私有类变量 # print(Foo.__country) obj = Foo() obj.func()
思考题: 如何验证儿子都不知道私有字段的存在. 无法访问: class Base(object): __secret = "受贿" class Foo(Base): def func(self): print(self.__secret) print(Foo.__secret) obj = Foo() obj.func() 可以访问: class Base(object): __secret = "受贿" def zt(self): print(Base.__secret) class Foo(Base): def func(self): print(self.__secret) print(Foo.__secret) obj = Foo() obj.zt()
1.2 方法 (1) 方法 ------------------------ 实例化方法 ----------------------------- ############ 没必要写实例化方法 ############ 没有用到对象内部的数据 class Foo(object): def __init__(self, name): self.name = name def func(self): print("123") obj = Foo("李华") obj.func() ############ 有必要写实例化方法 ############# 需要用到对象内部的数据 class Foo(object): def __init__(self, name): self.name = name def func(self): print(self.name) obj = Foo("李华") obj.func() -------------------------- 静态方法 --------------------------- class Foo(object): def __init__(self, name): self.name = name # 实例方法 def func(self): print(self.name) # 静态方法,如果方法中无需使用对象中封装的值,那么就可以使用静态方法 @staticmethod def display(a1, a2): return a1 + a2 obj = Foo("李华") obj.func() # 调用实例方法 ret = Foo.display(1, 3) # 调用静态方法 print(ret) # 总结 # 1. 编写时: # - 方法上方写 @staticmethod # - 方法参数可有可无 # 2. 调用时: # - 类.方法名() # 推荐 # - 对象.方法名() # 3. 什么时候写静态方法? # - 无需调用对象中已封装的值 -------------------------- 类方法 ------------------------------ class Foo(object): def __init__(self, name): self.name = name # 实例方法,self是对象 def func(self): print(self.name) # 静态方法,如果方法中无需使用对象中封装的值,那么就可以使用静态方法 @staticmethod def display(a1, a2): return a1 + a2 # 类方法,cls是类,自动传递了类,无需手动传递 @classmethod def show(cls, x1, x2): print(cls, x1, x2) # 执行类方法 Foo.show(1, 8) # 总结 # 1. 定义时: # - 方法上方写: @classmethod # - 方法的参数: 至少有一个cls参数 # 2. 执行时: # - 类名.方法名 # 默认会将当前类传递到参数中 # 3. 什么时候用? # - 如果在方法中会使用到当前类,那么就可以使用类方法 (2) 方法成员修饰符 --------------------- 私有的实例方法 --------------------- class Foo(object): def __init__(self): pass def __dispaly(self, arg): print('私有方法', arg) def func(self): self.__dispaly(123) obj = Foo() # obj.__display # 外部无法访问 obj.func() # 通过内部访问 ------------------------- 私有的静态方法 ----------------------- class Foo(object): def __init__(self): pass @staticmethod def __dispaly(arg): print('私有方法', arg) def func(self): Foo.__dispaly(123) @staticmethod def get_display(): Foo.__dispaly(888) # Foo.__display(123) 报错 obj = Foo() obj.func() Foo.get_display() ------------------------- 私有的类方法 -------------------------- class Foo: def __init__(self): pass @classmethod def __display(cls, a1): print("我爱你", a1) def func(self): Foo.__display('大西瓜') @classmethod def get_display(cls): Foo.__display('冬瓜') # Foo.__dispaly('南瓜') # 报错 obj = Foo() obj.func() Foo.get_display()
# 面试题: 静态方法 / 类方法和实例方法的区别? 答: # 定义: # 静态方法和类方法上面都要加一个东西 # 静态方法: @staticmethod # 类方法: @classmethod # 实例方法不用加 # 调用: # 静态方法/类方法调用时,通过 类.方法 调用 # 实例方法调用时,先实例化,再通过 对象.方法 调用 # 应用场景: # 如果在方法内部不会用到对象内部的数据, 就可以用静态方法 / 类方法 # 类方法: 如果你在代码中会用到当前类, 为了简便, 就用类方法 # 如果需要用对象内部的数据, 才用实例方法
1.3 属性(通过方法改造出来的) class Foo(object): def __init__(self): pass @property def start(self): return 1 @property def end(self): return 10 obj = Foo() print(obj.start) print(obj.end) # 总结: # 1. 编写时 # - 方法的上方写: @property # - 方法参数: 只有一个self # 2. 调用时: 无需加括号 对象.方法 # 3. 应用场景: 对于简单的方法,当无需传参且有返回值时,可以使用 @property
练习题: """ 有一个列表,里面有900条数据,要求输入页码显示该页的数据,每页显示10条数据 """ # 以前的写法 data_list = [] for i in range(1, 901): data_list.append('alex-%s' % i) while 1: # 1. 要查看的页面 page = int(input('请输入要查看的页码:')) # 2. 每页显示 10 条 per_page_num = 10 start = (page-1) * per_page_num end = page * per_page_num page_data_list = data_list[start:end] for item in page_data_list: print(item) # 面向对象的写法: 把处理分页的函数写一个类 class Pagenation(object): """ 处理分页相关的代码 """ def __init__(self, page, per_page_num=10): """ 初始化 :param page: 当前要查看的页码 :param per_page_num: 每页默认要显示的数据行数 """ self.page = page self.per_page_num = per_page_num @property def start(self): """ 计算索引的起始位置 :return: """ return (self.page-1) * self.per_page_num @property def end(self): """ 计算索引的结束位置 :return: """ return self.page * self.per_page_num data_list = [] for i in range(1, 901): data_list.append('alex-%s' % i) while 1: # 1. 要查看的页面 page = int(input('请输入要查看的页码:')) obj = Pagenation(page) page_data_list = data_list[obj.start:obj.end] for item in page_data_list: print(item) # 把显示数据的功能也归到这个类 class Pagenation(object): """ 处理分页相关的代码 """ def __init__(self, data_list, page, per_page_num=10): """ 初始化 :param data_list: 所有的数据 :param page: 当前要查看的页码 :param per_page_num: 每页默认要显示的数据行数 """ self.data_list = data_list self.page = page self.per_page_num = per_page_num @property def start(self): """ 计算索引的起始位置 :return: """ return (self.page-1) * self.per_page_num @property def end(self): """ 计算索引的结束位置 :return: """ return self.page * self.per_page_num def show(self): """ 显示输入页码的数据 :return: """ result = self.data_list[self.start:self.end] for row in result: print(row) data_list = [] for i in range(1, 901): data_list.append('alex-%s' % i) while 1: # 1. 要查看的页面 page = int(input('请输入要查看的页码:')) obj = Pagenation(data_list, page) obj.show()
2. 嵌套(组合/建模)
# 面向对象: """ 创建三个学校且三个学校的设施内容等都是一致. """ class School(object): def __init__(self, name, address): self.name = name self.address = address def speech(self): print("讲课") obj1 = School('老男孩北京校区', '美丽富饶的沙河') obj2 = School('老男孩上海校区', '浦东新区') obj3 = School('老男孩深圳校区', '南山区') class Teacher(object): def __init__(self, name, age, salary): self.name = name self.age = age self.__aslary = salary self.school = None t1 = Teacher('李杰', 19, 188888) t2 = Teacher('颜涛', 18, 60) t3 = Teacher('女神', 16, 900000) ############## 老师分配了校区 ############## t1.school = obj1 t2.school = obj1 t3.school = obj2 ###################################### # 查看t1老师,所在的校区名称/地址 print(t1.school.name) # 老男孩北京校区 print(t1.school.address) # 美丽富饶的沙河 print(t1.name) # 李杰 print(t1.age) # 19 t1.school.speech() # 演讲 # 准则: 字段和方法的归类.