python 面向对象 (成员 + 组合(嵌套))
1. 类的成员
面向对象中类的成员有三大类 : 2 + 3 + 1 每个都包括公有和私有(名称前加双下划线)
变量 :
- 实例变量 (字段) 公有和私有
- 类变量 (静态字段) 公有和私有
方法 :
- 实例方法
- 静态方法 @staticmethod
- 类方法 @classmethod
属性 :
- 属性 @property 只有self参数 有返回值
1.1 变量
class Foo: # 类变量(静态字段) country = "中国" def __init__(self, name): # 实例变量(字段) self.name = name def func(self): pass obj1 = Foo('季红') obj2 = Foo('王晓东') print(obj1.name) #实例变量用对象访问 print(Foo.country) # 类变量用类直接访问
总结:
实例变量(字段) : 在构造函数中声明, 使用对象访问,即 : obj.name
类变量(静态字段) : 在类中(非方法中)声明, 建议使用类访问,即 : Foo.country
对象也可以访问,但只会改变自己的值,不会使类中值改变,不建议使用.
1. 什么时候使用类变量?
当所有对象中有共同的字段时且要改都改,要删都删时,可以将 实例变量(字段) 提取到 类变量(静态字段) 中.
2. 易错点 , 对于类变量访问:
# 对象访问类变量时, 只改变obj中的,不会改变类中类变量country的值
# 类访问类变量时, 会改变类变量country的值,创建的对象都会改变
obj1 = Foo('季红') obj2 = Foo('王晓东') # 练习1 # obj1.name = 'alex' # 只改变obj1中的内容 # print(obj1.name) # alex # print(obj2.name) # 王晓东 # 练习2 # obj1.country = '美国' # 对象访问类变量时, 只改变obj中的,不会改变类中类变量country的值 # print(obj1.country) # 美国 # print(obj2.country) # 中国 # 练习3 # Foo.country = '美国' # 类访问类变量时, 会改变类变量country的值,创建的对象都会改变 # print(obj1.country) # 美国 # print(obj2.country) # 美国
3. 字段成员修饰符 (公有和私有)
公有和私有的区别 :
公有变量, 在类的内部和外部都可以进行访问
私有变量, 只能在类的内部进行访问, 但是可以通过类中方法进行间接访问, 在变量前面加双下划线.
# ######################## 公有实例变量(字段) ######################## 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) # 内部调用 也可直接使用类名 obj = Foo() obj.func() # 通过方法间接调用 print(obj.country) # 对象直接访问类变量 不建议使用, print(Foo.country) # 外部直接调用 推荐使用
# ######################## 私有类变量(私有静态字段) ######################## 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 方法
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) # 执行实例方法, 通过对象来调用访问 obj = Foo('..') obj.func() # 执行静态方法, 建议使用类访问 Foo.display(1, 3) # 执行类方法, 直接使用类访问 Foo.show(1,8)
总结 : 实例方法/ 静态方法/ 类方法 有什么区别? (编写 执行 使用场景)
实例方法 :
1) 编写, 有 self 参数, self 传递的是对象
2) 执行, 创建对象,通过对象调用 对象.方法名()
3) 使用场景, 使用到对象封装在__init__中值变量时
静态方法 :
1) 编写, 方法上方有 @staticmethod , 没有self 参数, 其他参数可有可无
2) 执行, 建议使用类直接调用, 类.方法名() 对象.方法名()
3) 使用场景, 无需使用对象中已封装的值
类方法 :
1) 编写, 方法上方有 @classmethod , 至少有一个cls参数, 传递的是当前类, python会自动进行传递
2) 执行, 直接只用类来调用, 类.方法名() # 默认会将当前类传到参数中
3) 使用场景, 如果在方法中会使用到当前类,那么就可以使用类方法.
1. 方法成员修饰符 (公有和私有)
私有,同样是在方法名前面加双下划线,且私有的方法,只能在内部访问.
# ########################## 私有的实例方法 ####################### class Foo(object): def __init__(self): pass def __display(self,arg): # 双下划线 私有方法 print('私有方法',arg) def func(self): self.__display(123) obj = Foo() # obj.__display(123) # 无法直接访问私有方法 obj.func() # 通过方法 间接访问私有方法
# ########################## 私有的静态方法 ####################### class Foo(object): def __init__(self): pass @staticmethod def __display(arg): print('私有静态 方法',arg) def func(self): Foo.__display(123) @staticmethod def get_display(): Foo.__display(888) # Foo.__display(123) 报错 obj = Foo() obj.func() Foo.get_display()
类方法 也存在私有,这里不再举例.
1.3 属性
属性是通过方法改造的,调用类似于变量,调用时方法名不加括号, 如 obj.func
class Foo(object): def __init__(self): pass @property # 属性,只有self一个参数, 有返回值 def start(self): return 1 @property def end(self): return 10 obj = Foo() print(obj.start) # 使用对象调用,调用时方法名不加括号. print(obj.end)
总结 :
属性 :
1) 编写, 方法上方有 @property, 只有self一个参数, 有返回值
2) 执行, 调用时方法名无需加括号, 对象.方法名
3) 使用场景, 对于简单的方法,当无需传参且有返回值时,可以使用属性
练习题 : 将多条数据进行分页展示.
# 以前写法 data_list = [] for i in range(1, 901): data_list.append('alex-%s' % i) while True: # 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,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 True: # 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.__salary = 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) t1.school.speech()
组合, 类与类之间的嵌套, 选课小练习 (学校/课程/班级) 之间的嵌套 :
https://www.cnblogs.com/cyycyhcbw/articles/9554630.html
组合小补充 :
• 确定对象中封装了什么?
• self 到底是谁?
练习题 (10个) 重点
https://www.cnblogs.com/cyycyhcbw/articles/9555263.html

浙公网安备 33010602011771号