第十二章面向对象

mac2022-06-30  85

一、面向对象 面向对象的三大特性: 封装、继承、多态

1. 函数式编程和面向对象的对比:

举例:开发一个消息提醒的功能(邮件/短信/微信)   函数: def email(em, text): """ 发送邮件 :return: """ print(em, text) def msg(tel, text): """ 发送短信 :return: """ print(tel, text) def wechat(num, text): """ 发送微信 :return: """ print(num, text) # 编写功能:向所有的联系方式发送天气 if True: msg('188888888', '今天有小雨') email('hao123@163.com.com', '今天有小雨') wechat('xxxx', '今天有小雨') 面向对象: class Message: def email(self, em, text): """ 发送邮件 :return: """ print(em,text) def msg(self, tel, text): """ 发送短信 :return: """ print(tel,text) def wechat(self, num, text): """ 发送微信 :return: """ print(num,text) # 编写功能:向所有的联系方式发送天气 if True: obj = Message() obj.email('hao123@163.com', '今天有小雨') obj.msg('188888888', '今天有小雨') obj.wechat('xxxx', '今天有小雨')

对比:

函数:定义简单、调用简单 面向对象:定义复杂、调用复杂 好处:归类,将某些类似的函数功能写在一起

总结:

  1 函数式编程可能会比面向对象好   2. Python中支持两种编程方式   3. 面向对象方式格式: 定义:   class 类名: # 定义了一个类      def 函数名(self): # 在类中编写一个“方法”       pass 调用:   x1 = 类名() # 创建了一个对象(实例化一个对象)   x1.函数名() # 通过对象调用其中一个方法 构造方法:   class Foo:      def __init__(self, name): # 构造方法,目的进行数据初始化       self.name = name       self.age = 18   obj = Foo("久末") # 给类名加括号,默认调用构造方法 通过构造方法,可以将数据进行打包,以后使用时,去其中获取即可 应用:   1、将数据封装到对象中,以供自己在方法中使用 class FileHandler: def __init__(self, file_path): self.file_path = file_path self.f = open(self.file_path, 'rb') def read_first(self): # self.f.read() # ... pass def read_last(self): # self.f.read() # ... pass def read_second(self): # self.f... # ... pass obj = FileHandler('C:/xx/xx.log') obj.read_first() obj.read_last() obj.read_second() obj.f.close()   2、将数据封装到对象中,供其他函数调用 class FileHandler: def __init__(self, file_path): self.file_path = file_path self.f = open(self.file_path, 'rb') def read_first(self): # self.f.read() # ... pass def read_last(self): # self.f.read() # ... pass def read_second(self): # self.f... # ... pass obj = FileHandler('C:/xx/xx.log') obj.read_first() obj.read_last() obj.read_second() obj.f.close()

2. 面向对象如何编写:

方式一:先归类,然后提取公共值 方式二:先在指定类中编写和当前类相关的所有代码,再提取公共值 三大特性: 封装: 将相关功能封装到一个类中 将数据封装到一个对象中 继承: 继承是为了复用,提高代码得重用性 先找子类(派生类),后找父类(基类)—— 子类和父类是相对存在的 先从子类中找,没有就从父类找   多继承(只存在python中的功能):左边更亲 多态: 多种形态或者多种状态 鸭子模型:只要可以嘎嘎嘎叫的就是鸭子 二、类成员 注:所有成员中,只有普通字段的内容保存对象中,即:根据此类创建了多少对象,在内存中就有多少个普通字段。而其他的成员,则都是保存在类中,即:无论对象的多少,在内存中只创建一份 class Foo: # 方法 def __init__(self, name): # 实例变量/字段 self.name = name # 方法 def func(self): pass # obj,Foo类的对象 # obj,Foo类的实例 obj = Foo('jiumo')

1. 变量(字段):

字段包括实例变量和静态变量,他们在定义和使用中有所区别,而最本质的区别是内存中保存的位置不同 由上图可是: 静态变量在内存中只保存一份实例变量在每个对象中都要保存一份 应用场景: 通过类创建对象时,如果每个对象都具有相同的变量,那么就使用静态变量 # 类变量/实例变量 class Foo: # 类变量/静态字段 country = '中国' # 方法 def __init__(self, name): # 实例变量/字段 self.name = name def func(self): pass obj1 = Foo('jiumo') obj2 = Foo('王XX') obj1.country = '美国' print(obj1.country) print(obj2.country) obj1 = Foo('jiumo') obj2 = Foo('王XX') Foo.country = '美国' print(obj1.country) print(obj2.country) ==>美国 中国 美国 美国   实例变量(字段)     - 公有实例变量(字段) # 公有实例变量(字段) class Foo: def __init__(self, name): self.name = name self.age = 123 # 内部调用 def func(self): print(self.name) obj = Foo("jiumo") # 外部调用 print(obj.name) # jiumo print(obj.age) # 123 obj.func() # jiumo     - 私有实例变量(字段) # 私有实例变量(字段) class Foo: def __init__(self, name): # 定义为私有 self.__name = name self.age = 123 # 内部调用 def func(self): print(self.__name) obj = Foo("jiumo") # 外部不可直接调用 # print(obj.name) # 报错AttributeError: 'Foo' object has no attribute 'name' print(obj.age) obj.func() # 间接访问:让func帮助执行内部私有的__name 就相当在类的内部有认识的”关系” 间接的得到想要的内容   类变量(静态字段)     - 公有类变量(静态字段) # 默认公有类变量(字段) class Foo: country = "中国" def __init__(self): pass def func(self): # 内部调用 print(self.country) print(Foo.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( 准则: 实例变量(字段)访问时,使用对象访问,即:obj1.name 类变量(静态字段)访问时,使用类访问,即:Foo.country(实在不方便时才使用对象) 易错点: obj1 = Foo('jiumo') obj2 = Foo('王XX') obj1.name = '老王' print(obj1.name) print(obj2.name) ==>老王 王XX 什么时候用类变量: 当所有对象中有共同的字段,并且值永远同步,那么可以使用类变量 父类中的私有字段子辈无法知道,但是可以通过调用父类得到 # 子类也不能直接调用父类的私有字段 class Bsae(object): __secret = "RMB" class Foo(Bsae): def func(self): # print(self.__secret) # AttributeError: 'Foo' object has no attribute '_Foo__secret' print(Foo.__secret) # AttributeError: type object 'Foo' has no attribute '_Foo__secret' obj = Foo() obj.func() # 同样可以利用间接调用的方法得到私有字段 class Bsae(object): __secret = "RMB" def money(self): print(Bsae.__secret) class Foo(Bsae): def func(self): pass obj = Foo() obj.money()

2. 方法

实例方法 静态方法 1. 定义时: - 方法上方写 @staticmethod - 方法参数可有可无 2. 调用时: - 类.方法名() # 推荐使用 - 对象.方法名() 3. 什么时候使用静态方法: - 无需调用对象中封装的值 - 类方法 1. 定义时: - 方法上方写:@classmethod - 方法的参数:至少有一个cls参数 2. 执行时: - 类名.方法名 # 默认会将当前类传到参数中 3. 什么时使用类方法: - 如果在方法中会使用到当前类,那么就可以使用类方法 # 没必要写实例方法 class Foo(object): def __init__(self, name): self.name = name def func(self): print('实例方法') # 没有用到构建方法中的值 obj = Foo('jiumo') obj.func() # 有意义的实例方法 class Foo(object): def __init__(self, name): self.name = name # 实例方法,最少有一个参数 def func(self): print(self.name) # wb # 静态方法,可以没有参数. 如果方法中无需使用对象中封装的值,那么就可以使用静态方法 # 可以通过类直接调用,不需要实例化类这部操作 @staticmethod def display(): print('静态方法') # 静态方法 # 类方法 @classmethod def train(cls, name): print(cls) # <class '__main__.Foo'> print(name) # 类方法 # 实例方法 obj = Foo('wb') obj.func() # 静态方法的调用 Foo.display() # 类方法的调用 Foo.train('类方法') ==>实例方法 wb 静态方法 <class '__main__.Foo'> 类方法   方法的成员修饰符:方法也有公有方法和私有方法之分 用法同变量的成员修饰符 # 私有的实例方法 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) # 私有静态 方法 123 def func(self): Foo.__display(123) @staticmethod def get_display(): Foo.__display(888) #私有静态 方法 888 # Foo.__display(123) 报错 obj = Foo() obj.func() Foo.get_display()

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 应运场景: - 对于简单的方法,当无需传参且有返回值时

4. 特殊方法

class Foo(): # 1. def __init__(self,a1, a2): self.a1 = a1 self.a2 = a2 # 2. def __call__(self, *args, **kwargs): print('wb', args, kwargs) return 123 # 3. def __getitem__(self, item): print(item) return 123 # 4. def __setitem__(self, key, value): # 无返回值 print(key, value, 123) # 5. def __delitem__(self, key): # 无返回值 print(key) # 6. def __add__(self, other): return self.a1 + other.a1 # 7. def __enter__(self): print('开始代码') return 999 # 8. def __exit__(self, exc_type, exc_val, exc_tb): print("结束代码") 1.类名() 自动执行 __init__ obj = Foo(1, 2) 2.对象() 自动执行 __call__ ret = obj(2018, 9, time = 2) print(ret) 3.对象[] 自动执行 __getitem__ ret = obj['wang'] print(ret) 4.对象['xx'] = 11 自动执行 __setitem__ obj['k1'] = 123 5.del 对象['xx'] = 11 自动执行 __delitem__ del obj['wang'] 6.对象+对象 自动执行 __add__ 9. with 对象 自动执行__enter__ 和 __exit__ obj = Foo(1, 2) with obj as f: print(f) print('内部代码') 10.真正的构造方法 __new__ class Foo(object): def __init__(self,a1, a2): print(1) self.a1 = a1 self.a2 = a2 def __new__(cls, *args, **kwargs): print(2) # 执行到此处中断了 Foo(1, 2) 三、反射 python中的反射功能是由以下四个内置函数提供的:   - getattr(): 根据字符串为参数(第二个参数),去对象(第一个参数)中去寻找与之同名的成员   - hasattr():根据字符串的形式,去判断对象中是否有成员   - setattr():根据字符串的形式,动态的设置一个成员(内存)   - delattr():根据字符串的形式,动态的删除一个成员(内存) class Foo(object): def __init__(self): self.name = 'jiumo' def func(self): return 'func' obj = Foo() # 检查是否含成员变量 print(hasattr(obj, 'name')) # True print(hasattr(obj, 'func')) # True # 获取成员 print(getattr(obj, 'name')) # jiumo print(getattr(obj, 'func')) # <bound method Foo.func of <__main__.Foo object at 0x0000016810C9C908>> # 设置成员 setattr(obj, 'age', 18) print(getattr(obj, 'age')) # 18 setattr(obj, 'show', lambda num: num + 1) # print(getattr(obj, 'show')) # <function <lambda> at 0x0000016811EA47B8> # 删除成员 delattr(obj, 'name') print(hasattr(obj, 'name')) # Fals delattr(obj, 'show') print(hasattr(obj, 'show')) # False # 反射实例说明: class Foo(object): func_lst = ['f1', 'f2', 'f3'] def f1(self): print('注册成功') def f2(self): print('登陆成功') def f3(self): print('注销成功') obj = Foo() while True: print(""" 选择需要的功能: 1. 注册 2. 登陆 3. 注销 """) val = int(input("请输入要选择的功能:")) try: func_name = obj.func_lst[val-1] if hasattr(obj, func_name): func = getattr(obj, func_name) func() break except Exception: print("请输入正确的序号!")

转载于:https://www.cnblogs.com/jiumo/p/9545056.html

相关资源:面向对象软件工程
最新回复(0)