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组件做准备工作!

  • 相关阅读:
    Swift3 重写一个带占位符的textView
    Swift3 使用系统UIAlertView方法做吐司效果
    Swift3 页面顶部实现拉伸效果代码
    Swift3 倒计时按钮扩展
    iOS 获取当前对象所在的VC
    SpringBoot在IDEA下使用JPA
    hibernate 异常a different object with the same identifier value was already associated with the session
    SpringCloud IDEA 教学 番外篇 后台运行Eureka服务注册中心
    SpringCloud IDEA 教学 (五) 断路器控制台(HystrixDashboard)
    SpringCloud IDEA 教学 (四) 断路器(Hystrix)
  • 原文地址:https://www.cnblogs.com/xiao987334176/p/9556944.html
Copyright © 2011-2022 走看看