面向对象进阶和模块初识

本篇内容主要是面向对象的进阶和模块的初识,主要包括如下内容:接口类和抽象类、封装、类方法、静态方法、属性、反射、特殊方法、序列化模块、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模块

'''
整体说明:
01 print(random.random())  # 随机在0~1之间的float
02 print(random.uniform(1,10)) # 1 ~10 浮点型
03 print(random.randint(1,10)) # 1~10 之间的整数  ***
04 print(random.randrange(1,10,2)) # 大于等于1且小于10之间的奇数(2是步长)
05 print(random.choice([1, '23', [4,5]]))  # 多选择一  ***
06 print(random.sample([1,'23',[4,5], 'alex'],2)) #  列表元素 任意2个组合
07  random.shuffle(item) # 打乱次序  ***
'''

'''
需求:生成5位随机验证码
开发思路:
0~9 随机选一个
a~z 随机选一个
两个选一个
'''
import random


def code():
    codes = ''
    for i in range(5):
        num = str(random.randint(0, 9))
        char1 = chr(random.randint(97, 122))
        char2 = chr(random.randint(65, 96))
        c1 = random.choice([num, char1, char2])
        codes += c1  # 字符串拼接
    return codes


print(code())

# 说明:chr(code)是根据asscall值获得对应的字符。
原文地址:https://www.cnblogs.com/mayugang/p/9980394.html