python面向对象进阶和模块初识
本篇内容主要是面向对象的进阶和模块的初识,主要包括如下内容:接口类和抽象类、封装、类方法、静态方法、属性、反射、特殊方法、序列化模块、random模块。
1.接口类抽象类
''' 整体说明: 01 在python中的接口类和抽象类的含义是一样的,其他语言中接口类和抽象类的定义不同。 02 python中的接口类定义:制定一个规则,让其他人按照我的规则去写程序。(约定俗成,有些野蛮程序员可能不会遵循) 03 python接口类的形式:(约定俗成的规范,即如果在一个类中出现如下形式,则说明是python的接口类定义) # class payment: # 类名根据实际的需求进行定义 # def func(self): # 函数的参数根据实际的需求进行补充和完善;函数名根据实际的要求进行定义。 # pass 04 python接口类(强制规范)形式: # from abc import ABCMeta, abstractmethod # 该处引用是必须的,如果强制规范的接口类,必须进行引用。 # class payment(metaclass=ABCMeta): # 类名根据实际的需求进行定义 # @abstractmethod # def func(self): # 函数的参数根据实际的需求进行补充和完善;函数名根据实际的要求进行定义。 # pass 05 在编写代码的时候需要遵循“归一化”设计,即比如线上支付,支付的手段有QQ、微信、支付宝三种支付方式,最后统一的调用 支付接口的时候,尽量定义统计的调用方式进行(下面会有具体的示例展示)。 ''' # 1.支付方式不统一 class QQpay: def pay(self, money): print('QQ支付了%s钱' % money) class Alipay: def pay(self, money): print('支付宝支付了%s钱' % money) a1 = QQpay() a1.pay(100) b1 = Alipay() b1.pay(200) # 2.统一支付方式:归一化设计 class QQpay: def pay(self, money): print('QQ支付了%s钱' % money) class Alipay: def pay(self, money): print('支付宝支付了%s钱' % money) def pay(obj, money): # 归一化设计,设计统一的调用方式 obj.pay(money) a1 = QQpay() b1 = Alipay() pay(a1, 100) pay(b1, 200) # 3.接口类定义:制定一个规则,让其他人按照我的规则去写程序。 class payment: # 定义接口类,让所有人都遵循这个方式进行定义支付类。 def pay(self, money): pass class QQpay(payment): def pay(self, money): print('QQ支付了%s钱' % money) class Alipay(payment): def pay(self, money): print('支付宝支付了%s钱' % money) class Wechat(payment): def fuqian(self, money): print('微信支付了%s钱' % money) def pay(obj, money): # 归一化设计 obj.pay(money) # 4.接口类定义(强制规范): from abc import ABCMeta, abstractmethod # 通过引用实现强制规范的接口类 class payment(metaclass=ABCMeta): @abstractmethod # 引用装饰器,实现强制规范接口类。 def pay(self, money): pass class QQpay(payment): def pay(self, money): print('QQ支付了%s钱' % money) class Alipay(payment): def pay(self, money): print('支付宝支付了%s钱' % money) # 错误写法 class Wechat(payment): def fuqian(self, money): # 该处未按照标准的格式来,所以,在调用该类的时候会报错,应该讲方法fuqian修改为pay即可 print('微信支付了%s钱' % money) # 正确写法 class Wechat(payment): def pay(self, money): # 该处未按照标准的格式来,所以,在调用该类的时候会报错,应该讲方法fuqian修改为pay即可 print('微信支付了%s钱' % money) def pay(obj, money): # 归一化设计 obj.pay(money) w = Wechat() pay(w, 100)
2.封装
''' 01 封装的定义 (1)广义的封装:将一些内容放到一个‘容器’中。 (2)狭义的封装:私有 02 私有成员: (1)私有成员包括私有变量,私有对象属性,私有方法。 (2)私有成员类外面不能访问,派生类不可以访问,类内可以访问。 03 类的结构:静态变量(属性,字段)、私有静态变量、动态普通方法、私有方法、特殊方法(双下划下方法)、私有对象属性 属性、类方法、静态方法。 ''' # 01 类的结构 class B: country = 'China' # 静态变量(属性,字段) __name = 'alex' # 私有静态变量 def func(self): # 动态普通方法 pass def __func(self): # 私有方法 pass def __init__(self, name, age): # 特殊方法:双下方法 self.name = name self.__age = age # 私有对象属性 @property # 属性 def f1(self): pass @classmethod # 类方法 def func2(self): pass @staticmethod # 静态方法 def func3(self): pass # 02 私有成员:类外面不能访问,派生类不可以访问,类内可以访问。 class A: country = 'China' # 静态变量(属性,字段) __name = 'alex' # 私有静态变量 def __init__(self, name, age): self.name = name self.__age = age def func(self): # 动态普通方法 print(self.__name) def __func(self): # 私有方法 pass class B(A): def func2(self): print(self.__name) obj = A('二狗', 18) print(obj.country) # 类外面可以访问 # print(obj.__name) # 私有:类外面不可以访问 obj.func() # 私有:类内面可以访问 o1 = B('脸哥', 25) o1.func2() # 私有:派生类不可以访问 obj = A('二狗', 18) print(A.__dict__) # print(obj._A__name)
3.类方法
''' 整体说明: 01 必须通过类的调用,而且此方法的意义在于对类里面的变量或者方法进行修改添加。 02 类方法通过使用装饰器“@classmethod”来标记,同时装饰器下面的方法中的变量必须默认为“cls”。 ''' # 01 类方法说明: class B: country = 'China' # 静态变量(属性,字段) def func(self): # 动态普通方法 pass def __init__(self, name, age): # 特殊方法:双下方法 self.name = name @classmethod # 类方法 def func2(cls): # 对B类进行修改,封装了2个属性,即area和name cls.area = '东北' cls.name = '马玉刚' print(B) ''' 运行结果:<class '__main__.B'> ''' print(B.__dict__) ''' 运行结果: {'__module__': '__main__', 'country': 'China', 'func': <function B.func at 0x0000000001E9DF28>, '__init__': <function B.__init__ at 0x0000000001EA2048>, 'func2': <classmethod object at 0x0000000001E9E9E8>, '__dict__': <attribute '__dict__' of 'B' objects>, '__weakref__': <attribute '__weakref__' of 'B' objects>, '__doc__': None} ''' B.func2() print(B.__dict__) ''' 运行结果:' {'__module__': '__main__', 'country': 'China', 'func': <function B.func at 0x0000000001E9DF28>, '__init__': <function B.__init__ at 0x0000000001EA2048>, 'func2': <classmethod object at 0x0000000001E9E9E8>, '__dict__': <attribute '__dict__' of 'B' objects>, '__weakref__': <attribute '__weakref__' of 'B' objects>, '__doc__': None, 'area': '东北', 'name': '狗哥'} ''' # 02 类方法应用:统计类实例对象的个数 class C: count = 0 def __init__(self): # 实例化对象默认必须执行__init__函数 C.cou() @classmethod def cou(cls): cls.count += 1 obj = C() obj = C() obj = C() obj = C() obj = C() obj = C() obj = C() obj = C() obj = C() obj = C() obj = C() print(C.count) ''' 运行结果:11 '''
4.静态方法
''' 整体说明: 01 静态方法定义:在类中,一个不依赖类以及对象的一个普通函数。 02 静态方法作用:保证代码的一致性,可调控性,整洁性。 ''' # 1. 静态方法示例 class C: def __init__(self): pass @staticmethod def func(*args, **kwargs): # 该方法可以独立与类C存在,不依赖类和对象存在。 print(666) C.func() c1 = C() c1.func() # 2. 静态方法示例 import time class TimeTest(object): def __init__(self, hour, minute, second): self.hour = hour self.minute = minute self.second = second @staticmethod # 静态方法 def showTime(): return time.strftime("%H:%M:%S", time.localtime()) ''' 说明: 01 将以下方法移动至TimeTest仍可以正常执行,与类和对象无关。 def showTime(): return time.strftime("%H:%M:%S", time.localtime()) '''
5.属性
''' 整体说明: 01 property:是将方法伪装成为一个属性。 02 property引用形式:在方法前加上装饰器@property 进行伪装即可。 03 property的作用:代码层面上没有提升,但是他会让你的代码看起来更合理。在对象进行方法调用的时候,无需在方法名后加括号即可调用方法。 04 property的装饰器是成对出现的:@property 、@AAA.setter、 @AAA.deleter,其中@property最为常用和重要。 (1)@property:对象执行get的时候运行装饰器下的方法。 (2)@AAA.setter:对象执行set的时候运行该装饰器下的方法。 (3)@AAA.deleter:对象执行删除的时候运行该装饰器下的方法。 05 在进行setter和deleter的时候,方法名和调用装饰器的方法名必须保持一致。 ''' # 01 属性:为什么要进行伪装。 ''' 需求:测试人体的BMI值 ''' class B: def __init__(self, name, weight, height): self.name = name self.weight = weight self.height = height @property def bmi(self): return self.weight / self.height ** 2 gouge = B('马玉刚', 90, 1.78) print(gouge.bmi) # 说明:bmi看起来应该是一个名字,但是你用一个方法去实现,所以为了符合逻辑性,增加属性装饰器@property来进行。 # 由于伪装成为属性,所以在调用方法的时候无需在方法名后面加括号。 # 02 属性的说明 class Foo: def __init__(self,name): self.name = name @property # *** def AAA(self): print('get的时候运行我啊') @AAA.setter # * def AAA(self,value): print('set的时候运行我啊') @AAA.deleter # * def AAA(self): print('delete的时候运行我啊') obj = Foo('alex') obj.name = '太白' print(obj.name) # del obj.name # print(obj.name) obj.AAA = 666 # 对伪装的属性进行改值是就会调用 def AAA(self,value): del obj.AAA # 对伪装的属性进行detele的时候进行运行@AAA.deleter下的方法。 # 03 属性应用1: ''' 需求: 01 苹果的原始价位8元,折扣价格:0.8折,求苹果的售卖单价。 02 苹果的原始价格7元,折扣不变,求苹果的售卖店家。 03 原始价格和折扣都是私有变量。 ''' class Product: def __init__(self, name, origin_price, discount): self.name = name self.__origin_price = origin_price self.__discount = discount @property def price(self): return self.__origin_price * self.__discount @price.setter def price(self, new_price): self.__origin_price = new_price apple = Product('苹果', 8, 0.95) print(apple.price) apple.price = 7 print(apple.price)
6.反射
''' 整体说明: 01 反射的定义:通过字符串去操作对象(实例化对象,类,模块) 02 反射应用场景如下: (1)反射可以对实例化对象使用。 (2)反射可以对类使用。 (3)反射可以对当前模块使用。 (4)反射可以对其他模块使用。 03 反射的方法: (1)hasattr() :判断是否存在某个变量或者方法。 *** (2)getattr() :以字符串的形式获取某个变量或者方法。 *** (3)setattr() :对某个变量或者方法进行设置。 * (4)delattr() :对某个变量或者方法进行删除。* 04 isinstance:判断的是obj是否是此类或者此类的子孙类实例化出来的对象。 # isinstance(obj, B) 05 issubclass: 判断B是否是A的子类或者孙类。 # issubclass(B, A) ''' # # 01 isinstance:判断的是obj是否是此类或者此类的子孙类实例化出来的对象。 class A: pass class B(A): pass obj = B() print(isinstance(obj, B)) # True print(isinstance(obj, A)) # True # 02 issubclass:判断B是否是A的子类或者孙类。 # issubclass(B, A) class C: pass class A(C): pass class B(A): pass abj = B() print(issubclass(B, A)) # True print(issubclass(B, C)) # True # 03 反射对实例化对象应用的示例。 class A: def __init__(self, name, age): self.name = name self.age = age obj = A('脸哥', 27) ret = getattr(obj, 'name', None) # getattr获取对象中的name,如果没有返回None print(hasattr(obj, 'age')) # hasattr判断对象中是否有age,有返回True,没有返回False print(ret) if hasattr(obj, 'name'): ret = getattr(obj, 'name') setattr(obj, 'sex', '男') # 设置 print(getattr(obj, 'sex')) delattr(obj, 'name') # 删除 print(obj.__dict__) # 03 反射对类应用的示例。 class A: name = 'alex' def __init__(self): pass def func(self): print('IN func') ret = input('>>>>') # 输入func,并且将func赋值给ret f1 = getattr(A, ret)(1) # 通过getattr执行func方法,方法名+()调用方法执行方法,()中的1是需要给方法中传进入一个变量,变量任意。 ''' 说明: 通过类名调用类中的方法时其实是在执行函数func,并不是类中的方法,所以并不会自动赋值给self,所以需要是手动赋值,可以是任意值。 ''' # 04 反射在当前模块中的应用。 def func(): print('in func') import sys current_module = sys.modules[__name__] getattr(current_module, 'func')() # 05 反射在对其他模块(文件)应用的示例。 import fs # fs为自定义模块 print(getattr(fs, 'n1')) ret = getattr(fs, 'func') ret() # 方法一: clas = getattr(fs, 'A') print(clas.name) # 方法二: print(getattr(fs.A, 'name')) getattr(fs.A, 'func2')(1)
7.特殊方法
''' 整体说明: 01 单例设计模式:让一个类的实例化对象有且只有一个 *** 02 __init__和__new__的先后顺序。 (1)第一步:__new__先要new出一个对象(__new__方法在object类中默认的方法) (2)第二步:根据创建出的类,通过__init__进行属性的封装。 03 __call__方法。 04 __item__系列:对一个对象进行类似于字典的操作,就会触发__item__系列的某个方法。 *** (1)__getitem__ (2)__setitem__ (3)__delitem__ 05 __str__:遇到print()后即触发该方法执行。 06 __repr__:遇到print()后即触发该方法执行。 07 __call__:对象+(),触发该方法。 ''' # 01 __str__:遇到print()后即触发该方法执行。 class A: def __init__(self): pass def __str__(self): print(666) return '马玉刚' a = A() ret = '姓名:%s' % a print(ret) ''' 运行结果: 666 姓名:马玉刚 ''' # 02 __repr__:遇到print()后即触发该方法执行。 class A: def __init__(self): pass def __repr__(self): return '马玉刚' a = A() print('%r' % a) # 马玉刚 # 03 __call__:对象+(),触发该方法。 class Foo: def __init__(self): pass def __call__(self, *args, **kwargs): print(args) print('__call__') obj = Foo() obj('WuSir', 'alex') # 对象() 触发 __call__()方法 ''' 运行结果: ('WuSir', 'alex') __call__ ''' # 04 单例设计模式 '''未采用单例设计模式''' class A: pass ret = A() ret1 = A() print(ret, ret1) ''' 运行结果:两个不同的地址 <__main__.A object at 0x00000000021DE908> <__main__.A object at 0x00000000021DE940> ''' '''采用单例设计模式,单例设计模式有7种方式,以下是一种常用的单例设计模式''' class A: __instance = None def __new__(cls, *args, **kwargs): if cls.__instance is None: obj = object.__new__(cls) cls.__instance = obj return cls.__instance ret1 = A() ret2 = A() ret3 = A() print(ret1, ret2, ret3) ''' 运行结果:同一地址 <__main__.A object at 0x00000000021DE978> <__main__.A object at 0x00000000021DE978> <__main__.A object at 0x00000000021DE978> ''' # 05 __item__系列 __getitem__ __setitem__ __delitem__ *** # 对一个对象进行类似于字典的操作,就会触发__item__系列的某个方法。 class Foo: def __init__(self, name): self.name = name def __getitem__(self, item): print('__getitem__此方法执行了') return self.__dict__[item] def __setitem__(self, key, value): print('__setitem__此方法执行了') self.key = value def __delitem__(self, key): print('del obj[key]时,我执行') self.__dict__.pop(key) def __delattr__(self, item): print('del obj.key时,我执行') self.__dict__.pop(item) f = Foo('alex') print(f['name']) # f[name]属于查的方式,所以触发了__getitem__方法。 f['age'] = 25 # 触发了__setitem__的方法。 del f['name'] # 触发了__delitem__方法 print(f.__dict__)
8.序列化模块
''' 整体说明: 01 模块定义:一个py文件就是一个模块。 02 模块的分类: (1)内置模块: time os random shelve re 等等。 (2)拓展模块:beautifulsoup iteat等大神写的模块。 (3)自定义模块:自己整理的模块。 03 序列化模块: (1)JSON:适用于所有语言。 (1)网络传输:dumps loads (2)文件写入:dump load (2) pickle 只用于Python语言之间的传输,包含所有的python支持的数据类型。 (3)shelve :直接对文件句柄操作,就可以存入数据。 04 python和JSON的转换 # +-------------------+---------------+ # | Python | JSON | # += == == == == == == == == == += == == == == == == == + # | dict | object | # +-------------------+---------------+ # | list, tuple | array | # +-------------------+---------------+ # | str | string | # +-------------------+---------------+ # | int, float | number | # +-------------------+---------------+ # | True | true | # +-------------------+---------------+ # | False | false | # +-------------------+---------------+ # | None | null | # +-------------------+---------------+ ''' import json import pickle # 01 JSON序列化 # dumps loads # 网络传输 dic = {'name': '二狗', 'age': 25, 'sex': '男'} ret = json.dumps(dic, ensure_ascii=False) # 序列化过程 : 就是变成一个特殊的字符串 respon = json.loads(ret) # 反序列化:将序列化的特殊字符串反解成原来的类型。 print(ret, type(ret)) print(dic) print(respon, type(respon)) # dump load 写入常规文件 dic = {1: {'username': '二狗1', 'password': 123}, 2: {'username': '二狗2', 'password': 123}, 3: {'username': '二狗3', 'password': 123}, } f = open('json_file', 'w') json.dump(dic, f) # dump方法接收一个文件句柄,直接将字典转换成json字符串写入文件 f.close() f = open('json_file') dic2 = json.load(f) # load方法接收一个文件句柄,直接将文件中的json字符串转换成数据结构返回 print(dic2, type(dic2)) f.close() print(type(dic2), dic2) # 02 pickle 只用于Python语言之间的传输,包含所有的python支持的数据类型。 dic = {'name': '二狗', 'age': 25, 'sex': '男'} ret = pickle.dumps(dic) respon = pickle.loads(ret) print(ret) print(respon) # dump load # 写入文件 (这个不仅可以写常规的数据,还可以将对象写入) class A: name = 'alex' def func(self): print(666) obj = A() f = open('pickle_file', 'wb') pickle.dump(obj, f) f.close() f = open('pickle_file', 'rb') ret = pickle.load(f) print(ret.name) ret.func() f.close() # 03 shelve import shelve f = shelve.open('shelve_file') f['key'] = {'int': 10, 'float': 9.5, 'string': 'Sample data'} # 直接对文件句柄操作,就可以存入数据 f.close() import shelve f1 = shelve.open('shelve_file') existing = f1['key'] # 取出数据的时候也只需要直接用key获取即可,但是如果key不存在会报错 f1.close() print(existing)
9.random模块