getatter&属性描述符&迭代器&生成器&元类编程

__ getatter __ 魔法方法

  • 首先会在对象的实例属性中寻找,找不到执行第二步

  • 来到对象所在类中查找类属性,如果还找不到执行第三步

  • 来到对象的继承链上寻找,如果还找不到执行第四步

  • 调用obj.__getattr__方法,如果用户没有定义或者还是找不到,抛出AttributeError异常,属性查找失败!

# -*- coding: utf-8 -*-
# @Author: Small-J
# @Date  : 2020/12/18
# 该文件对应着视频-__getattr__和__getattribute__魔法函数


"""
总结如下:
__getatter__:该魔术方法什么时候执行呢,是当一个类中没有该属性的时候调用该魔法方法执行
"""
from datetime import date


class User(object):
    def __init__(self, name, birthday):
        self.name = name
        self.birthday = birthday

    def __getattr__(self, item):
        # print('attr not find')
        return None


if __name__ == '__main__':
    user = User('small-j', date(year=2020, month=12, day=18))
    print(user.name)  # small-j
    # 当如果打印一个不存在的值的时候
    # 字面意思:没有该属性值
    # print(user.age)  # AttributeError: 'User' object has no attribute 'age'
    #
    print(user.age)

属性描述符

  • __set__: 该魔法方法是设置属性时生效
  • __get__: 该魔法方法是在读取属性值时生效
  • __delete__: 该魔法方法是进行对应删除时调用
# -*- coding: utf-8 -*-
# @Author: Small-J
# @Date  : 2020/12/18
# 该文件对应着视频-属性描述符


"""
总结如下:
__set__:该魔术方法的作用:就是在设置值的时候,会进入这个方法,但是这个方法只是设置的时候进入的,
    instance : 该参数是object对象
    value: 就是我们想要的值

__get__ : 该魔法方法作用:就是在读取属性的时候会触发该魔法方法
"""


class IntField(object):
    def __get__(self, instance, owner):     # 在属性获取的时候会进入这个方法
        return self.age

    def __set__(self, instance, value):     # 在属性设置的时候会进入这个方法
        if not isinstance(value, int):
            raise ValueError
        # 因为设置的时候我们会进入这个方法,所以我们得在这使用值,在通过调用的形式,让__get__来读取出来
        self.age = value

    def __getattr__(self, item):    # 当没有属性的时候将会报错,我们要捕获这个异常,让他返回None
        return None


class User(IntField):
    age = IntField()


user = User()
user.age = 20

print(user.age)
print(user.aaa)

Python-迭代器

  • 迭代器和可迭代对象是两个不同的概念,可迭代对象不一定是迭代器。如list
  • 什么是可迭代对象:可迭代对象是含有__iter__这个魔法方法,这个魔法方法就是用来定义可迭代对象
  • 什么是迭代器:迭代器是含有__next____iter__这两个魔法方法
  • 迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。
  • 为什么list不是迭代器,因为list含有__iter__这个魔法方法,但是并不含有__next__该方法,那怎么把list变成迭代器呢?通过iter这个方法
# -*- coding: utf-8 -*-
# @Author: Small-J
# @Date  : 2020/12/19
# 该文件对应着视频-python迭代器

"""
总结如下:
可迭代对象和迭代器是不同的内容
什么是可迭代对象:可迭代对象是内部含有__iter__这个魔法方法的是可迭代对象,
为什么list不是迭代器,因为内部没有__next__这个魔术方法,但内部有__iter__这个魔法方法
什么是迭代器:迭代器是通过可以通过next来获取到下一位的是可迭代器
可迭代对象不一定是迭代器


"""

from collections import Iterable, Iterator

# 可迭代对象Iterable,定义__iter__

# True : 说明list也是一个可迭代的对象
# print(isinstance(list(), Iterable))

# False : 说明list不是迭代器,
# print(isinstance(list(), Iterator))

li = [1, 2, 3, 4]

# 从是一个列表转换成一个列表迭代器
# print(iter(li))    # <list_iterator object at 0x7fda40194390>

li = iter(li)

# 当想从一个迭代器中获取值的话只能next
# print(next(li))
# print(next(li))
# print(next(li))
# print(next(li))
# print(next(li))  # 当超过取值时会报出StopIteration这么一个错误

# 当如果数据特别多时,我们需要使用另外一种方法来解决现状
while True:
    try:
        print(next(li))
    except StopIteration:
        break

Python-生成器

  • 在Python中没有元祖推导式?->这是为什么?
  • 因为元祖最终的效果是属于生成器
  • 一般生成器对象可以使用next方法来获取数据
  • 当使用yield关键字的时候,如果数据没有了则不会报错,因为在内部yield做了一定的处理
  • 如果不使用yield的关键字,当next无的时候将会报错
  • 跟普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器
  • 调用一个生成器函数,返回的是一个迭代器对象。
# -*- coding: utf-8 -*-
# @Author: Small-J
# @Date  : 2020/12/20

# 该文件对应着视频-Python生成器
"""
总结如下:
在Python中没有元祖推导式,元祖是生成器
一般生成器对象可以使用next方法来获取数据
当使用yield关键字的时候,如果数据没有了则不会报错,因为在内部yield做了一定的处理
如果不使用yield的关键字,当next无的时候将会报错
"""

# 我们Python中有列表推导式,有字典推导式,但是就是没有元祖推导式,这是为什么,原因如下
a = [i for i in range(1, 10)]  # type: # list
b = (i for i in range(1, 10))  # type: # generator
d = {'name': 'Small-J', 'a': 10, 'b': 20}
c = {value: key for key, value in d.items()}


# 斐波那契数列
# 1,1,2,3,5,8,13
def data(n):
    a = 0
    b = 1
    count = 0
    while True:
        if count > n:
            return
        a, b = b, a+b
        count += 1
        print(a)


#
def demo():
    a = [i for i in range(3)]
    yield a

# 打印的结果是为生成器所使用
# print(demo())  # <generator object demo at 0x7fc8902a6550>

# 当使用yield关键字的时候,如果数据没有了则不会报错,因为在内部yield做了一定的处理
# 如果不使用yield的关键字,当next无的时候将会报错
# print(next(demo()))
# print(next(demo()))
# print(next(demo()))
# print(next(demo()))
# print(next(demo()))
# print(next(demo()))
# print(next(demo()))
# print(next(demo()))
# print(next(demo()))

type自定义元类编程

  • 创建类的方法有很多,除了可以通过class关键字来创建之外,也可以通过 type来创建,type既可以创建类也可以查询数据类型
  • type(name, bases, dict) -> a new type
    • name: 创建类的名字
    • bases:继承的类,父类,以元祖的形式
    • dict: 以字典的形式,接受各种魔法方法和相对应的类方法,当创建类方法时,必须要加self,否则无效
# 当我想以元类编程的形式创建出一个类方法的话,可以如下操作
# 要遵守元类编程和创建类方法的写法,需要加self


def info(self):
    return self.age


class BaseData(object):
    def demo(self):
        return 'Small-J'


def __init__(self):
    self.height = 180
    self.width = 100


def __getattr__(self, name):
    return None


# 对应的这是一个类
# "age": 18 ->相当于类方法

User = type('User', (BaseData, ), {"age": 18, 'info': info, '__init__': __init__, '__getattr__': __getattr__})    # <class '__main__.User'>

# 实例化这个类
user = User()
print(user.age)
print(user.info())      # 相当于调用方法
# print(user.age)   # 18

# 通过实例化方式来调用父类中的方法
print(user.demo())  # 也是可以调用的

# 当定义了魔法方法也是可以通过直接调用的
# init魔法方法也可以被调用
print(user.height)

# 当没有该属性时也会触发__getattr__这个魔法方法来进行,注意:必须要加上self,默认是没有加上self的
print(user.dddd)
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值