zoukankan      html  css  js  c++  java
  • python 全栈开发,Day113(方法和函数的区别,yield,反射)

    一、方法和函数的区别

    面向对象

    初级

    class StarkConfig(object):
        def __init__(self,model_class):
            self.model_class = model_class
    
        def changelist_view(self,request):
            return 123
    
    class RoleConfig(StarkConfig):
        def changelist_view(self,request):
            return 666
    
    obj1 = StarkConfig('xiao')
    obj2 = RoleConfig('zhang')
    
    ret1 = obj1.changelist_view(1)
    ret2 = obj2.changelist_view(2)
    print(ret1)
    print(ret2)
    View Code

    执行输出:

    123
    666

    中级

    class StarkConfig(object):
        list_display = []
        def __init__(self,model_class):
            self.model_class = model_class
    
        def changelist_view(self,request):
            return self.list_display
    
    class RoleConfig(StarkConfig):
        list_display = ['id','name']
    
    obj1 = StarkConfig('xiao')
    obj2 = RoleConfig('zhang')
    
    ret1 = obj1.changelist_view(1)
    ret2 = obj2.changelist_view(2)
    print(ret1)
    print(ret2)
    View Code

    执行输出:

    []
    ['id', 'name']

    注意:obj2的self指的是RoleConfig。因为实例化哪个对象,那么self就是那个对象!

    所以ret2输出['id', 'name']

    在昨天用到的include,它的本质就是返回一个元组,元组包含了3个元素

    autodiscover_modules它干了啥?当程序启动时,去每个app目录下找stark.py,并加载!

    函数和方法

    函数

    def func():
        pass
    
    class Foo(object):
        def display(self):
            pass
    
    print(func)
    print(Foo.display)
    View Code

    执行输出:

    <function func at 0x0000025E24C98F28>
    <function Foo.display at 0x0000025E24FF52F0>

    输出function ,这2个都是函数

    方法

    class Foo(object):
        def display(self):
            pass
    
    obj = Foo()
    print(obj.display)
    View Code

    执行输出:

    <bound method Foo.display of <__main__.Foo object at 0x000001F2C6193A90>>

    输出bound method ,它是一个绑定方法。

    注意:在类中定义的def,它到底是方法还是函数呢?取决于它的调用方式。

    如果通过类名调用它,它就是函数。如果通过实例化对象,再调用,它就是方法。

    代码判断

    人为的判断,难免会出错。python提供了2个方法,专门用来做判断。

    具体请看下面的代码

    from types import MethodType,FunctionType
    def check(arg):
        """
        判断arg时函数则打印1,arg是方法打印2
        :param arg:
        :return:
        """
        if isinstance(arg,MethodType):
            print(2)
        elif isinstance(arg,FunctionType):
            print(1)
        else:
            print('错误!不支持该类型')
    
    def func():
        pass
    
    class Foo(object):
        def display(self):
            pass
    
    check(func)
    check(Foo.display)
    obj = Foo()
    check(obj.display)
    View Code

    执行输出:

    1
    1
    2

    练习题

    例1

    class RoleConfig(object):
        def f1(self,arg):
            print('f1',arg)
        def f2(self,arg):
            print('f2',arg)
    
        list_display = [f1,f2]
    
    for item in RoleConfig.list_display:
        # print(item)
        item(1,2)
    View Code

    执行输出:

    f1 2
    f2 2

    注意:这里的item是函数,它必须要传递2个参数。self也是一个参数!

    例2

    class RoleConfig(object):
        def f1(self,arg):
            print('f1',arg)
        def f2(self,arg):
            print('f2',arg)
    
        list_display = [f1,f2]
    
    obj = RoleConfig()
    for item in RoleConfig.list_display:
        # print(item)
        item(obj,2)
    View Code

    执行输出,效果同上!

    注意:item(obj,2),这里面的obj是一个对象,指的是self。那么它再传一个参数,就可以了!

    例3

    class RoleConfig(object):
        def f1(self,arg):
            print('f1',arg)
        def f2(self,arg):
            print('f2',arg)
        def f3(self,arg):
            print('f3',arg)
    
        list_display = [f1,f2]
    
        def get_list_display(self):
            # insert() 函数用于将指定对象插入列表的指定位置
            # 0表示第一个元素位置
            self.list_display.insert(0,self.f3)
            return self.list_display
    
    obj = RoleConfig()
    for item in obj.get_list_display():
        print(item)
        item(obj,2)
    View Code

    执行输出:

    <bound method RoleConfig.f3 of <__main__.RoleConfig object at 0x000001864A87C780>>
    Traceback (most recent call last):
      File "E:/python_script/django框架/day18/untitled/a.py", line 67, in <module>
        item(obj,2)
    TypeError: f3() takes 2 positional arguments but 3 were given

    明明只传了2个,为什么是3个呢?

    注意:f3是bound method

    定义了一个类RoleConfig,实例化RoleConfig得到了obj这个对象,然后调用这个对象方法obj.method(self,arg)

    这个过程中Python会自动转为RoleConfig.mehod(obj,self,arg),实际它传递了3个参数!

    为什么呢?f3是一个绑定方法,必须要将obj实例作为第一个参数!否则报错!

    既然它是一个绑定方法,那么给它绑定一下。插入到列表时,使用RoleConfig.f3

    class RoleConfig(object):
        def f1(self,arg):
            print('f1',arg)
        def f2(self,arg):
            print('f2',arg)
        def f3(self,arg):
            print('f3',arg)
    
        list_display = [f1,f2]
    
        def get_list_display(self):
            # insert() 函数用于将指定对象插入列表的指定位置
            # 0表示第一个元素位置
            self.list_display.insert(0,RoleConfig.f3)
            return self.list_display
    
    obj = RoleConfig()
    for item in obj.get_list_display():
        print(item)
        item(obj,2)
    View Code

    执行输出:

    <function RoleConfig.f3 at 0x0000021D6DB15400>
    f3 2
    <function RoleConfig.f1 at 0x0000021D6D8B68C8>
    f1 2
    <function RoleConfig.f2 at 0x0000021D6DB152F0>
    f2 2

    例4

    class RoleConfig(object):
        def f1(self,arg):
            print('f1',arg)
        def f2(self,arg):
            print('f2',arg)
        def f3(self,arg):
            print('f3',arg)
    
        list_display = [f1,f2]
    
        def get_list_display(self):
            # insert() 函数用于将指定对象插入列表的指定位置
            # 0表示第一个元素位置
            self.list_display.insert(0,RoleConfig.f3)
            return self.list_display
    
    obj1 = RoleConfig()
    for item in obj1.get_list_display():
        # print(item)
        item(obj1,2)
    
    obj2 = RoleConfig()
    for item in obj2.get_list_display():
        # print(item)
        item(obj1,6)
    View Code

    执行输出:

    f3 2
    f1 2
    f2 2
    f3 6
    f3 6
    f1 6
    f2 6

    为毛会输出7个呢?这不科学!

    统计一下列表的数量

    下面这段代码,详细解释了代码执行过程,以及list_display元素的变化

    class RoleConfig(object):
        def f1(self,arg):
            print('f1',arg)
        def f2(self,arg):
            print('f2',arg)
        def f3(self,arg):
            print('f3',arg)
    
        list_display = [f1,f2]
    
        def get_list_display(self):
            # insert() 函数用于将指定对象插入列表的指定位置
            # 0表示第一个元素位置
            self.list_display.insert(0,RoleConfig.f3)
            return self.list_display
    
    obj1 = RoleConfig()  # 此时list_display有2个元素
    for item in obj1.get_list_display():
        # 此时list_display有3个元素,因为执行了insert
        # 列表的值为f3,f1,f2
        item(obj1,2)  # 输出f3,f1,f2
    
    print('第一次统计数量:',len(RoleConfig.list_display))  # 3个
    
    obj2 = RoleConfig()  # list_display还是有3个,列表的值为f3,f1,f2
    for item in obj2.get_list_display():
        # 此时list_display有4个元素,因为再次执行了insert
        # 列表的值为f3,f3,f1,f2
        item(obj1,6)  #输出f3,f3,f1,f1,f2
    
    print('第二次统计数量:',len(RoleConfig.list_display))
    View Code

    执行输出:

    f3 2
    f1 2
    f2 2
    第一次统计数量: 3
    f3 6
    f3 6
    f1 6
    f2 6
    第二次统计数量: 4

    注意:最终list_display的元素数量为4个,并不是7个。只不过执行了2次for循环,所以才输出了7次。

    例5

    为了避免列表重复插入,定义一个空列表

    class RoleConfig(object):
    
        def f1(self, arg):
            print('f1', arg)
    
        def f2(self, arg):
            print('f2', arg)
    
        def f3(self, arg):
            print('f3', arg)
    
        list_display = [f1, f2]
    
        def get_list_display(self):
            v = []
            v.extend(self.list_display)
            v.insert(0,RoleConfig.f3)
            return v
    
    obj1 = RoleConfig()
    for item in obj1.get_list_display():
        item(obj1,2)
    
    obj2 = RoleConfig()
    for item in obj2.get_list_display():
        item(obj2,6)
    View Code

    执行输出:

    f3 2
    f1 2
    f2 2
    f3 6
    f1 6
    f2 6

    那么它是如何避免列表重复插入的呢?

    看下面的注释

    num = 0  # 全局变量,统计列表数量
    class RoleConfig(object):
        def f1(self,arg):
            print('f1',arg)
        def f2(self,arg):
            print('f2',arg)
        def f3(self,arg):
            print('f3',arg)
    
        list_display = [f1,f2]
    
        def get_list_display(self):
            global num  # 要使用全局变量,必须声明global
            num += 1  # 自增1
            v = []  # 定义空列表,每次执行时,列表重置为空列表
            v.extend(self.list_display)  # 列表扩展,此时v=[f1,f2]
            v.insert(0,RoleConfig.f3)  # 第一个位置插入f3,此时v=[f3,f1,f2]
            print('第%s次统计数量:'%num, len(v))
            return v
    
    obj1 = RoleConfig()  # 此时v有0个元素
    for item in obj1.get_list_display():
        # 此时v有3个元素
        item(obj1,2)
    
    obj2 = RoleConfig()  # 此时v有0个元素
    for item in obj2.get_list_display():
        # 此时v有3个元素
        item(obj1,6)
    View Code

    执行输出:

    第1次统计数量: 3
    f3 2
    f1 2
    f2 2
    第2次统计数量: 3
    f3 6
    f1 6
    f2 6
    View Code

    注意:虽然执行了2次for循环。但是每次执行get_list_display()方法时,v列表会被重置为空列表。

    所以每次for循环,都是3个值!

    二、yield

    python中有一个非常有用的语法叫做生成器,所利用到的关键字就是yield。有效利用生成器这个工具可以有效地节约系统资源,避免不必要的内存占用

    我们对一个生成器使用for循环时,它其实调用了__next__函数。也就是获取下一个元素!

    注意:对生成器使用__next__函数时,如果没有下一个值,会报错!但是使用for循环,它内部使用了异常处理,所以我们不需要担心,到底下一个,有没有值!

    Python的三大神器:装饰器.迭代器与生成器!可谓无人不知,无人不晓啊。以下省略一万字...

    应用场景

    例1

    假设有1000条数据,用户名和密码拼接成一个字符串,页面打印出来。
    要求前端页面不能拼接,只能后台拼接生成!

    以前的你

    def func(request):
        result = []
        data_list = models.Users.objects.all()
        for row in data_list:
            temp = "%s%s" %(row.name,row.pwd)
            result.append(temp)
        return render(result,'xxx.html',{'result':result})
    View Code

    xxx.html

    {% for row in result %}
    {{row}}
    {% endfor %}
    View Code

    它有一个问题,内存里面有2000条数据。占用内存太大了!

    现在的你

    def get_result(data_list):
        for row in data_list:
            temp = "%s%s" % (row.name, row.pwd)
            yield temp
    
    def func(request):
        data_list = models.Users.objects.all()
        result = get_result(data_list)
        return render(result, 'xxx.html', {'result': result})
    View Code

    xxx.html的代码,保持不变。还是用for循环!

    页面加载时,for循环一次只加载一条数据
    yeild取完之后,就消失了

    在内存中,只有一条数据!这样,就可以节省内存!

    三、反射

    getattr(object, name[,default])

    获取对象object的属性或者方法,如果存在打印出来,如果不存在,打印出默认值,默认值可选。
    需要注意的是,如果是返回的对象的方法,返回的是方法的内存地址,如果需要运行这个方法,
    可以在后面添加一对括号。

    举例

     新建一个项目untitled1,注意:django版本为1.11

     

    修改models.py,增加表

    from django.db import models
    
    # Create your models here.
    class UserInfo(models.Model):
        username = models.CharField(verbose_name="用户名",max_length=32)
    View Code

    使用2个命令,生成表

    python manage.py makemigrations
    python manage.py migrate

    使用navicat添加3条数据

    修改urls.py,增加路径

    from django.conf.urls import url
    from django.contrib import admin
    from app01 import views
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^test/', views.test),
    ]
    View Code

    修改views.py,增加视图函数

    from django.shortcuts import render,HttpResponse
    from app01 import models
    
    # Create your views here.
    def test(request):
        user_queryset = models.UserInfo.objects.all()
        for item in user_queryset:
            print(item.id,item.username)
    
        return HttpResponse('ok')
    View Code

    启动django项目,访问页面,效果如下:

     

    查看Pycharm控制台输出:

    1 韩雪
    2 唐嫣
    3 赵丽颖

    反射对象

    修改views.py,使用getattr

    from django.shortcuts import render,HttpResponse
    from app01 import models
    
    # Create your views here.
    def test(request):
        user_queryset = models.UserInfo.objects.all()
        for item in user_queryset:
            print(item.id,item.username,getattr(item,'username'))
    
        return HttpResponse('ok')
    View Code

    刷新网页,查看Pycharm控制台输出:

    1 韩雪 韩雪
    2 唐嫣 唐嫣
    3 赵丽颖 赵丽颖

    显示指定的列

    修改views.py,增加属性list_display

    def test(request):
        list_display = ['id','username']
        user_queryset = models.UserInfo.objects.all()
        for item in user_queryset:
            row = []
            for field in list_display:
                row.append(getattr(item,field))
            print(row)
    
        return HttpResponse('ok')
    View Code

    刷新网页,查看Pycharm控制台输出:

    [1, '韩雪']
    [2, '唐嫣']
    [3, '赵丽颖']

    只取id,修改list_display

    from django.shortcuts import render,HttpResponse
    from app01 import models
    
    # Create your views here.
    def test(request):
        list_display = ['id']
        user_queryset = models.UserInfo.objects.all()
        for item in user_queryset:
            row = []
            for field in list_display:
                row.append(getattr(item,field))
            print(row)
    
        return HttpResponse('ok')
    View Code

    刷新网页,查看Pycharm控制台输出:

    [1]
    [2]
    [3]

    获取verbose_name

    修改views.py

    from django.shortcuts import render,HttpResponse
    from app01 import models
    
    # Create your views here.
    def test(request):
        list_display = ['id','username']
        models_class = models.UserInfo
        verbose_name = models.UserInfo._meta.get_field('username').verbose_name
        print(verbose_name)
    
        return HttpResponse('ok')
    View Code

    刷新网页,查看Pycharm控制台输出:

    用户名

    使用for循环,获取指定列的verbose_name

    修改views.py

    from django.shortcuts import render,HttpResponse
    from app01 import models
    
    # Create your views here.
    def test(request):
        list_display = ['id','username']
        models_class = models.UserInfo
        for name in list_display:
            verbose_name = models.UserInfo._meta.get_field(name).verbose_name
            print(verbose_name)
    
        return HttpResponse('ok')
    View Code

    刷新网页,查看Pycharm控制台输出:

    ID
    用户名

    注意:在models.py中的UserInfo虽然没有定义id字段。但是它会默认创建id字段。它的verbose_name是大写的ID

    同时打印指定字段的verbose_name以及表记录

     修改views.py

    from django.shortcuts import render,HttpResponse
    from app01 import models
    
    # Create your views here.
    def test(request):
        list_display = ['id','username']
        header_list = []
        # models_class = models.UserInfo
        for name in list_display:
            verbose_name = models.UserInfo._meta.get_field(name).verbose_name
            header_list.append(verbose_name)
        print(header_list)
    
        user_queryset = models.UserInfo.objects.all()
        for item in user_queryset:
            row = []
            for field in list_display:
                row.append(getattr(item, field))
            print(row)
    
        return HttpResponse('ok')
    View Code

    刷新网页,查看Pycharm控制台输出:

    ['ID', '用户名']
    [1, '韩雪']
    [2, '唐嫣']
    [3, '赵丽颖']

    去掉id字段

    修改views.py

    from django.shortcuts import render,HttpResponse
    from app01 import models
    
    # Create your views here.
    def test(request):
        list_display = ['username']
        header_list = []
        # models_class = models.UserInfo
        for name in list_display:
            verbose_name = models.UserInfo._meta.get_field(name).verbose_name
            header_list.append(verbose_name)
        print(header_list)
    
        user_queryset = models.UserInfo.objects.all()
        for item in user_queryset:
            row = []
            for field in list_display:
                row.append(getattr(item, field))
            print(row)
    
        return HttpResponse('ok')
    View Code

    刷新网页,查看Pycharm控制台输出:

    ['用户名']
    ['韩雪']
    ['唐嫣']
    ['赵丽颖']

    通过这样,就可以自定义页面显示的列。为后续的stark组件做准备工作!

  • 相关阅读:
    无服务计算应用场景探讨及 FaaS 应用实战
    从零入门 Serverless | Serverless 应用如何管理日志 & 持久化数据
    实验楼流程
    go beego框架与python实现数据交互
    golang 并发运算时主线程先运行完,子线程运行没结束的问题记录
    滑动窗口解决最小子串问题 leetcode3. Longest Substring Without Repeating Characters
    golang 遍历树状结构
    golang 三维向量相关操作
    golang 矩阵乘法、行列式、求逆矩阵
    golang float32/64转string
  • 原文地址:https://www.cnblogs.com/xiao987334176/p/9556944.html
Copyright © 2011-2022 走看看