Day2 PythonWeb全栈课程课堂内容

1. 抽象基类(承接Day1 PythonWeb全栈课程课堂内容)

  • 抽象基类(abstract base class ABC)。抽象基类就是类里定义了纯虚成员函数的类。纯虚函数只提供了接口,并没有具体实现。抽象基类不能被实例化(不能创建对象),通常是作为基类供子类继承,子类中重写虚函数,实现具体的接口。
  • 抽象基类就是定义各种方法而不做具体实现的类,任何继承自抽象基类的类必须实现这些方法,否则无法实例化。

应用场景:

  • 检查某个类中是否还有某种方法。
  • 强调某个子类必须实现某些方法。

特点:

  • 抽象,不可以被实例化。
  • 继承,必须得重写指定的方法。
# 创建抽象基类
import abc # 调用抽象基类模块abc

class A(metaclass=abc.ABCMeta): # 创建抽象基类A。
    pass

class B(A): # 普通类继承抽象基类A
    def deme(self):
        pass

print(isinstance(B,A)) # False 原因A为抽象基类,B为实类,所以不属于同一类型,返回Falase
# -----------------------------
# 去掉B中的方法,测试B是否继承A。
import abc 

class A(metaclass=abc.ABCMeta):
    pass

class B(A): 
    pass

print(isinstance(B,A)) # False 原因A为抽象基类,B为实类,所以不属于同一类型,返回Falase。
# -----------------------------
import abc # 调用抽象基类模块abc

class A(metaclass=abc.ABCMeta): # 创建抽象基类A。
    pass

class B(A): # 普通类继承抽象基类A
    pass

# issubclass() 判断参数class 是否是类型参数classinfo 的子类
print(issubclass(B,A)) # True
# -----------------------------
# 使用register()方法,注册。 定义好的抽象基类,通过register()可以成为别的类的父类。(源文件使用较多)
import abc # 调用抽象基类模块abc

class A(metaclass=abc.ABCMeta): # 创建抽象基类A。
    pass

class B(object): # 普通类继承抽象基类A
    pass

A.register(B) # 将不是继承A类的B,强制变成A类的子类。
# issubclass() 判断参数class 是否是类型参数classinfo 的子类
print(issubclass(B,A)) # True

用途

'''*检查某个类中是否还有某种方法,应用场景。'''

class Demo():
	def __init__(self, li):
        self.li = li
        
    def d(self):
        pass
    
    def __len__(self):
        return len(self.li)

d = Demo(['Sam', 'Janice'])
print(len(d)) # 2
print(hasattr(d, '__len__')) # True 判断d 内是否有__len__这个魔术函数。
print(hasattr(d,'d')) # True 判断d 内是否有 d 这个方法。
 
    
from collection.abc import Sized, Iterable # Sized 和Iterable 是在其源码中是抽象基类。
print(isinstance(b, Sized)) # True 说明b 属于Sized 这个类型。原因Sized是一个抽象基类。
print(isinstance(b, Iterable)) # False 

'''
当类中添加 
def __iter__(self):
	pass
时
'''
print(isinstance(b, Iterable)) # True 用于判断b 中是否有迭代方法__iter__。
'''必须得重写指定的方法。'''
import abc
class CacheBase(metaclass=abc.ABCMeta):
    
    @abc.abstractmethod # 装饰器
    def get(self, key): # 纯虚函数
        pass
    
    @abc.abstractmethod 
    def set(self, key, value): # 纯虚函数
        pass
    
class RedisCache(CacheBase):
    pass

cb = CacheBase() 
'''
    cb = CacheBase()
TypeError: Can't instantiate abstract class CacheBase with abstract methods get, set
''' # 抽象基类不能实例化。

rc = RedisCache()
'''
rc = RedisCache()
TypeError: Can't instantiate abstract class RedisCache with abstract methods get, set
'''# 必须重写,子类内部的方法


# -------------------------
'''必须得重写指定的方法。'''
import abc
class CacheBase(metaclass=abc.ABCMeta):
    
    @abc.abstractmethod 
    def get(self, key):
        pass
    
    @abc.abstractmethod
    def set(self, key, value):
        pass
    
class RedisCache(CacheBase):
    def get(self, key):
        pass
    
    def set(self, key, value):
        pass

rc = RedisCache()

类与对象深度问题及解决技巧

1. 派生内置不可变类型

'''课堂内容推导'''
'''
案例:自定义一种新类型的元组,对于传入的可迭代对象,我们只保留其中int类型且值大于0的元素
'''
# 首先验证传输内容
class IntTuple(tuple):
    pass 
int_tuple = IntTuple([2, -2, 'Sam', ['x', 'y'], 4])

print(int_tuple) # (2, -2, 'Sam', ['x', 'y'], 4)
# -------------------------------
class IntTuple(tuple):
    def __init__(self, iterable):
        f = (i for i in iterable if isinstance(i, int) and i > 0)
        print(f)  
        # <generator object IntTuple.__init__.<locals>.<genexpr> at 0x0000000009F89F10>  generator是一个推导式
        super().__init__(self, iterable)
        '''
        	super().__init__(self, iterable)
		TypeError: object.__init__() takes no parameters
        ''' # 表示__init__里面没有参数。
        
        print(self) # (2, -2, 'Sam', ['x', 'y'], 4)
int_tuple = IntTuple([2, -2, 'Sam', ['x', 'y'], 4])
print(int_tuple) 
class A:
    def __new__(cls, *args, **kwargs):
        print("A.__new__", *args, **kwargs)

    def __init__(self):
        print("A.__init__")

a = A() 
'''
A.__new__
'''

class A:
    def __new__(cls, *args, **kwargs):
        print("A.__new__", *args, **kwargs)
        return object.__new__(cls) # return值给self

    def __init__(self):
        print("A.__init__")

a = A()
'''
A.__new__
A.__init__
'''


class A:
    def __new__(cls, *args, **kwargs):
        print("A.__new__", *args, **kwargs)
        return object.__new__(cls) # return值给self

    def __init__(self, *args):
        print("A.__init__", *args)

a = A(1, 2)
'''
A.__new__ 1 2
A.__init__ 1 2
'''
a = A.__new__(class, 1, 2)
A.__init__(a)
'''
A.__new__ 1 2
A.__init__ 1 2
'''

在这里插入图片描述

  • 所以原先得改成__new__方法
class IntTuple(tuple):
    def __new__(cls, iterable):
        f = (i for i in iterable if isinstance(i, int) and i > 0)
        return super().__new__(cls, f)
        
        
int_tuple = IntTuple([2, -2, 'Sam', ['x', 'y'], 4])
print(int_tuple) 
'''
(2, 4)
'''

  • __new__初始化魔法字符,在__init__之前。

2. 创建大量实例节省内存

  • __slots__可以关闭动态绑定属性。
  • __slots__不影响子类实例,不会继承,除非子类里面自己定义了 。
'''
在游戏开发中,有一个玩家类Player,每有一个在线玩家,在服务器内则有一个player的实例,当在线的人数很多时,将产生大量实例(百万级)
'''


class Player1(object):
    def __init__(self, uid, name, status=0, level=1):
        self.uid = uid
        self.name = name
        self.status = status
        self.level = level


class Player2(object):
    __slots__ = ('uid', 'name', 'status', 'level')

    def __init__(self, uid, name, status=0, level=1):
        self.uid = uid
        self.name = name
        self.status = status
        self.level = level


p1 = Player1('001', 'Sam')
p2 = Player2('002', 'Janice')

print(p1.__dict__)
# {'uid': '001', 'name': 'Sam', 'status': 0, 'level': 1}
# print(p2.__dict__)
'''
    print(p2.__dict__)
NameError: name 'p2' is not defined
''' # 说明p2中没有__dict__
# p2.gender = 1
'''
    p2.gender = 1
AttributeError: 'Player2' object has no attribute 'gender'
''' # 静止动态添加,

# 证明减少
print(dir(p1))
'''
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'level', 'name', 'status', 'uid']
'''
print(dir(p2))
'''
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__slots__', '__str__', '__subclasshook__', 'level', 'name', 'status', 'uid']
'''
print(set(dir(p1))-set(dir(p2)))
'''
{'__weakref__', '__dict__'}
''' # p1 比 p2 多 __weakref__ 和 __dict__

import sys

print(sys.getsizeof(p1)) # 56
print(sys.getsizeof(p1.__dict__)) # 112
print(sys.getsizeof(p2)) # 72


3. 上下文管理协议

  • with调用类
class Sam(object):
    def demo(self):
        return 'Hellp Python'


with Sam() as sam:
    sam.demo()
    
'''
    with Sam() as sam:
AttributeError: __enter__
''' # 属性错误 缺少__enter__
class Sam(object):
    def __enter__(self):
        # 获取资源
        print('start')

    def demo(self):
        return 'Hellp Python'

    def __exit__(self, exc_type, exc_val, exc_tb):
        # 释放资源
        self.exc_type = exc_type
        self.exc_val = exc_val
        self.exc_tb = exc_tb


with Sam() as sam:
    sam.demo()
'''
    sam.demo()
AttributeError: 'NoneType' object has no attribute 'demo'
'''
class Sam(object):
    def __enter__(self):
        print('start')
        return self # 返回self

    def demo(self):
        return 'Hellp Python'

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.exc_type = exc_type 	
        self.exc_val = exc_val		
        self.exc_tb = exc_tb		 
        print('end')


with Sam() as sam:
    print(sam.demo())
    
'''
start
Hellp Python
end
'''
class Sam(object):
    def __enter__(self):
        print('start')
        return self

    def demo(self):
        return 'Hellp Python'

    def __exit__(self, exc_type, exc_val, exc_tb):
        # self.exc_type = exc_type
        # self.exc_val = exc_val
        # self.exc_tb = exc_tb
        print(exc_type) # <class 'AttributeError'> 异常类
        print(exc_val) # 'Sam' object has no attribute 'demo1' 异常值
        print(exc_tb) # <traceback object at 0x000000000A019708> 追踪信息
        print('end')

with Sam() as sam:
    print(sam.demo1()) 
  • 简化 - contextlib
def file_open(filename):
    pass

with file_open('demo.txt') as f:
    f.read()
    
'''
    with file_open('demo.txt') as f:
AttributeError: __enter__
'''
import contextlib

@contextlib.contextmanager
def file_open(filename):

    # __enter__
    print("file open")
    file_handler = open(filename, 'r', encoding='utf-8')
    yield file_handler
    # __exit__
    print("file end")
    file_handler.close()

with file_open('demo.txt') as f:
    print(f.read())
'''
file open
sam
janice
mike
jerry
file end
'''

4. 让类支持比较操作

魔法方法说明
__gt__大于
__lt__小于
__gte__大于等于
__lte__小于等于
  • 使用方法

    在这里插入图片描述

# 常规类是不能比较的
class A:
    pass


class B:
    pass


print(A > B)
'''
    print(A > B)
TypeError: '>' not supported between instances of 'type' and 'type'
'''
# 实现类的比较
class Rect:
    def __init__(self, w, h):
        self.w = w
        self.h = h

    def area(self):
        return self.w * self.h


rect1 = Rect(1, 2)
rect2 = Rect(3, 4)
print(rect1 > rect2)
'''
    print(rect1 > rect2)
TypeError: '>' not supported between instances of 'Rect' and 'Rect'
'''
class Rect:
    def __init__(self, w, h):
        self.w = w
        self.h = h

    def area(self):
        return self.w * self.h

    def __gt__(self, other): # 其中self是rect1,other是rect2
        print(other) # <__main__.Rect object at 0x000000000295A748>
        return self.area() > other.area() # False 不大于

rect1 = Rect(1, 2)
rect2 = Rect(3, 4)
print(rect1 > rect2) # False 不大于
print(rect1 < rect2) # True 小于 
'''
其中类中只包含了 __gt__ 魔法函数,但是依旧可以比较小于。其实就是rect1 < rect2交换位置
实则是print(rect2 > rect1)
'''
from functools import total_ordering


@total_ordering
class Rect:
    def __init__(self, w, h):
        self.w = w
        self.h = h

    def area(self):
        return self.w * self.h

    def __gt__(self, other):  
        return self.area() > other.area()

    def __eq__(self, other):
        return self.area() == other.area()


rect1 = Rect(1, 2)
rect2 = Rect(3, 4)
print(rect1 >= rect2)
# 实现两个不同类之间的比较
from functools import total_ordering
import math


@total_ordering
class Rect:
    def __init__(self, w, h):
        self.w = w
        self.h = h

    def area(self):
        return self.w * self.h

    def __gt__(self, other):
        return self.area() > other.area()

    def __eq__(self, other):
        return self.area() == other.area()

    
@total_ordering
class Circle():
    def __init__(self, r):
        self.r = r

    def area(self):
        return self.r ** 2 * math.pi

    def __gt__(self, other):
        return self.area() > other.area()

    def __eq__(self, other):
        return self.area() == other.area()


rect1 = Rect(1, 2)
rect2 = Rect(3, 4)
c = Circle(8)
print(c > rect1) # True
print(c >= rect2)

  • 改写完善文件,使用抽象基类
from functools import total_ordering
from abc import ABCMeta, abstractclassmethod
import math

@total_ordering
class shape(metaclass=ABCMeta):
    @abstractclassmethod
    def area(self):
        pass

    def __gt__(self, other):
        return self.area() > other.area()

    def __eq__(self, other):
        return self.area() == other.area()


class Rect(shape):
    def __init__(self, w, h):
        self.w = w
        self.h = h

    def area(self):
        return self.w * self.h


class Circle(shape):
    def __init__(self, r):
        self.r = r

    def area(self):
        return self.r ** 2 * math.pi


rect1 = Rect(1, 2)
rect2 = Rect(3, 4)
c = Circle(8)
print(c > rect1) # True
print(c >= rect1) # True

5. 通过实例方法名字的字符串调用方法

'''
我们有三个图形类 Circle,Triangle,Rectangle
他们都有一个获取图形面积的方法,但是方法名字不同,我们可以实现一个统一的获取面积的函数,使用每种方法名进行尝试,调用相应类的接口
'''


class Triangle:
    def __init__(self, a, b, c):
        self.a, self.b, self.c = a, b, c

    def get_area(self):
        a, b, c = self.a, self.b, self.c
        p = (a + b + c) / 2
        return (p * (p - a) * (p - b) * (p - c)) ** 0.5


class Rectangle:
    def __init__(self, a, b):
        self.a, self.b = a, b

    def getArea(self):
        return self.a * self.b


class Circle:
    def __init__(self, r):
        self.r = r

    def area(self):
        return self.r ** 2 * 3.14159


def get_area_from_shape(shape):
    method_name = ['get_area', 'getArea', 'area']
    for name in method_name:
        f = getattr(shape, name, None)
        if f:
            return f()


shape1 = Triangle(2, 2, 3)
shape2 = Rectangle(2, 3)
shape3 = Circle(4)
print(get_area_from_shape(shape1))
print(get_area_from_shape(shape2))
print(get_area_from_shape(shape3))
class Triangle:
    def __init__(self, a, b, c):
        self.a, self.b, self.c = a, b, c

    def get_area(self):
        a, b, c = self.a, self.b, self.c
        p = (a + b + c) / 2
        return (p * (p - a) * (p - b) * (p - c)) ** 0.5


class Rectangle:
    def __init__(self, a, b):
        self.a, self.b = a, b

    def getArea(self):
        return self.a * self.b


class Circle:
    def __init__(self, r):
        self.r = r

    def area(self):
        return self.r ** 2 * 3.14159


def get_area_from_shape(shape):
    method_name = ['get_area', 'getArea', 'area']
    for name in method_name:
        f = getattr(shape, name, None)
        if f:
            return f()


shape1 = Triangle(2, 2, 3)
shape2 = Rectangle(2, 3)
shape3 = Circle(4)
shape_list = [shape1, shape2, shape3]
area_list = list(map(get_area_from_shape, shape_list))

print(area_list)


  • getattr(x,“y”,None) --> 等同于 x.y 当x中不含有y时,返回None。

  • map(func,iterable) --> 将iterable中的元素一一映射到func函数中处理,并且返回新的map对象。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值