面向对象(进阶)
Posted rixian
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了面向对象(进阶)相关的知识,希望对你有一定的参考价值。
一.关于上篇面向对象(初识)总结:
1.面向对象是一种编程方式,此编程方式的实现是基于对类和对象的使用
2.类:是一个模板,模板中包装了多个"函数"供使用(可以讲多个函数中公用的变量封装到对象中)
3.对象,根据模板创建的实例(即:对象),实例用于调用被包装在类中的函数
4.面向对象三大特性:封装,继承和多态
(1).封装:
归类,将函数放置到一个类中
打包,将数据打包放到一个对象中
(2).继承:
在子类中调用父类中的方法
Python支持多继承
(3).多态:
Python原生支持多态,崇尚鸭子模型,由于Python函数传参时,无序指定类型:
def func(arg): # arg可以是多种类型,只要其中有send方法即可
arg.send
5.编写面向对象程序:归类+提取公共值
6.self到底是谁?
self参数是Python帮助我们自动传递
如果执行面向对象中的方法时,前面必须有一个对象:xxx.func()
class Foo: def f1(self): pass def f2(self): self.f1() obj = Foo() obj.f2()
class User: def __init__(self,name,pwd): self.name = name self.pwd = pwd class Account: def __init__(self): self.user_list = [] def login(self): name = input(‘请输入账号:‘) pwd = input(‘请输入密码:‘) flag = False for user in self.user_list: if name == user.name and pwd == user.pwd: flag = True break if flag: print(‘登录成功‘) else: print(‘登录失败‘) def register(self): i = 0 while i<3: i+=1 name = input(‘请输入用户名:‘) pwd = input(‘请设置密码:‘) usr = User(name,pwd) self.user_list.append(usr) def run(self): self.register() self.login() if __name__==‘__main__‘: obj = Account() obj.run()
二.类的成员
类的成员可以分为三大类:字段.方法和属性
注:所有成员中,只有普通字段的内容保存到对象中,即:根据此类创建了多少对象,在内
存中就有多少个普通字段,而其他的成员,则都是保存在类中,即:无论对象的多少,在内
存中只创建一份.
class User: def __init__(self, user, pwd, email): self.user = user self.pwd = pwd self.email = email user_list = [] # obj = User(‘wahaha‘,‘123‘,‘[email protected]‘) obj = {‘user‘:‘wahaha‘,‘pwd‘:123,‘email‘:‘[email protected]‘} # dict({‘user‘:‘wahaha‘,‘pwd‘:123,‘email‘:‘[email protected]‘}) user_list.append(obj) # obj = User(‘wahaha‘,‘123‘,‘[email protected]‘) obj = {‘user‘:‘wahaha‘,‘pwd‘:123,‘email‘:‘[email protected]‘} user_list.append(obj) # obj = User(‘wahaha‘,‘123‘,‘[email protected]‘) obj = {‘user‘:‘wahaha‘,‘pwd‘:123,‘email‘:‘[email protected]‘} user_list.append(obj) for row in user_list: # print(row.user,row.pwd,row.email) print(row[‘user‘],row[‘pwd‘],row[‘emailr‘])
class Foo: # 方法 def __init__(self,name): # 实例变量/字段 self.name = name # 方法 def func(self): pass # obj,Foo类的对象 # obj,Foo类的实例 obj = Foo(‘娃哈哈‘)
1.字段:
字段包括:普通字段和静态字段,他们在定义和使用中有所区别,而最本质的区别是内存
中保存的位置不同
(1).普通字段属于对象
(2).静态字段属于类
class Foo: # 类变量(静态字段) country = "中国" 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.country,直接访问静态字段 """ # 知识点一:易错点 """ obj1 = Foo(‘朴树‘) obj2 = Foo(‘高晓松‘) # 练习1 # obj1.name = ‘娃哈哈‘ # print(obj1.name) # 娃哈哈 # print(obj2.name) # 高晓松 # 练习2 # obj1.country = ‘美国‘ # print(obj1.country) # 美国 # print(obj2.country) # 中国 # 练习3 # Foo.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) # 推荐 # 外部调用 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() # 调用第三方
2.方法:
方法包括:普通方法,静态方法,和类方法,三种方法在内存中都归属于类,区别在于
调用的方式不同
(1).普通方法:由对象调用;至少一个self参数;执行普通方法时,自动将调用该方法
的对象赋值给self
(2).类方法:由类调用;至少一个cls参数;执行类方法时,自动将调用该方法的类复
制给cls
(3).静态方法:由类调用;无默认参数;
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 # 静态方法,如果方法无需使用对象中封装的值,那么就可以使用静态方法 @staticmethod def display(a1,a2): return a1 + a2 Foo.display(1,3)
class Foo(object): # 类方法,cls是类 @classmethod def show(cls,x1,x2): print(cls,x1,x2) # 执行类方法 Foo.show(1,8)
相同点:对于所有的方法而言,均属于类(非对象)中,所以,在内存中也只保存一份
不同点:方法调用者不同,调用方法时自动传入的参数不同
(4).示例:
# ######### 没必要写实例方法 ######### 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)
总结:
①.编写时:
方法上方写@staticmethod
方法参数可有可无
②.调用时:
类.方法名()
对象.方法名()
③.什么时写静态方法?
无需调用对象中已封装的值
# ######### 类方法 ######### 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(7,6)
总结: ①.定义时: 方法上方写:@classmethod 方法的参数:至少有一个cls参数 ②.执行时: 类名.方法名() # 默认会将当期类传到参数中 ③.什么时候使用? 如果在方法中会使用到当前类,那么就可以使用类方法
(5).方法成员的修饰符
# ######### 私有的实例方法 ######### 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()
3.属性(通过方法改造出来)
如果你已经了解了Python类中的方法,那么属性就非常简单了,因为python中的属性其
实是普通方法的变种
""" class Foo(object): def __init__(self): pass def start(self): return 1 def end(self): return 10 obj = Foo() obj.start() obj.end() """ 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)
总结:
①.编写时:
方法上方写:@property
方法参数:只有一个self
②.调用时:无需加括号 对象.方法
③.应用场景:对于简单的方法,当无需传参且有返回值时,可以使用@property
# 以前写法 # 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,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 True: # 1. 要查看的页面 page = int(input(‘请输入要查看的页码:‘)) obj = Pagenation(page) page_data_list = data_list[obj.start:obj.end] for item in page_data_list: print(item)
# 以前写法 # 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): 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()
三.嵌套
# 面向对象: """ 创建三个帮会且三个帮会的结构内容等都是一致. """ class Gang(object): def __init__(self, name, address): self.name = name self.address = address def speech(self): print(‘搬砖‘) obj1 = Gang(‘赛利亚我养你‘, ‘山东一区‘) obj2 = Gang(‘赛利亚我爱你‘, ‘上海一区‘) obj3 = Gang(‘赛利亚我想你‘, ‘北京一区‘) class Members(object): def __init__(self, name, age, salary): self.name = name self.age = age self.__salary = salary self.gang = None t1 = Members(‘鬼剑‘, 19, 188888) t2 = Members(‘格斗‘, 18, 60) t3 = Members(‘神枪‘,16, 900000) # ############## 成员分配大区 t1.gang = obj1 t2.gang = obj1 t3.gang = obj2 # ########################### # 查看t1成员,所在的帮会名称/地址 print(t1.gang.name) print(t1.gang.address) print(t1.name) print(t1.age) t1.gang.speech()
22
以上是关于面向对象(进阶)的主要内容,如果未能解决你的问题,请参考以下文章