一、方法和函数的区别

面向对象

初级

  1. class StarkConfig(object):
  2. def __init__(self,model_class):
  3. self.model_class = model_class
  4.  
  5. def changelist_view(self,request):
  6. return 123
  7.  
  8. class RoleConfig(StarkConfig):
  9. def changelist_view(self,request):
  10. return 666
  11.  
  12. obj1 = StarkConfig('xiao')
  13. obj2 = RoleConfig('zhang')
  14.  
  15. ret1 = obj1.changelist_view(1)
  16. ret2 = obj2.changelist_view(2)
  17. print(ret1)
  18. print(ret2)

执行输出:

  1. 123
  2. 666

中级

  1. class StarkConfig(object):
  2. list_display = []
  3. def __init__(self,model_class):
  4. self.model_class = model_class
  5.  
  6. def changelist_view(self,request):
  7. return self.list_display
  8.  
  9. class RoleConfig(StarkConfig):
  10. list_display = ['id','name']
  11.  
  12. obj1 = StarkConfig('xiao')
  13. obj2 = RoleConfig('zhang')
  14.  
  15. ret1 = obj1.changelist_view(1)
  16. ret2 = obj2.changelist_view(2)
  17. print(ret1)
  18. print(ret2)

执行输出:

  1. []
  2. ['id', 'name']

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

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

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

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

函数和方法

函数

  1. def func():
  2. pass
  3.  
  4. class Foo(object):
  5. def display(self):
  6. pass
  7.  
  8. print(func)
  9. print(Foo.display)

执行输出:

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

输出function ,这2个都是函数

方法

  1. class Foo(object):
  2. def display(self):
  3. pass
  4.  
  5. obj = Foo()
  6. print(obj.display)

执行输出:

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

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

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

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

代码判断

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

具体请看下面的代码

  1. from types import MethodType,FunctionType
  2. def check(arg):
  3. """
  4. 判断arg时函数则打印1,arg是方法打印2
  5. :param arg:
  6. :return:
  7. """
  8. if isinstance(arg,MethodType):
  9. print(2)
  10. elif isinstance(arg,FunctionType):
  11. print(1)
  12. else:
  13. print('错误!不支持该类型')
  14.  
  15. def func():
  16. pass
  17.  
  18. class Foo(object):
  19. def display(self):
  20. pass
  21.  
  22. check(func)
  23. check(Foo.display)
  24. obj = Foo()
  25. check(obj.display)

执行输出:

  1. 1
  2. 1
  3. 2

练习题

例1

  1. class RoleConfig(object):
  2. def f1(self,arg):
  3. print('f1',arg)
  4. def f2(self,arg):
  5. print('f2',arg)
  6.  
  7. list_display = [f1,f2]
  8.  
  9. for item in RoleConfig.list_display:
  10. # print(item)
  11. item(1,2)

执行输出:

  1. f1 2
  2. f2 2

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

例2

  1. class RoleConfig(object):
  2. def f1(self,arg):
  3. print('f1',arg)
  4. def f2(self,arg):
  5. print('f2',arg)
  6.  
  7. list_display = [f1,f2]
  8.  
  9. obj = RoleConfig()
  10. for item in RoleConfig.list_display:
  11. # print(item)
  12. item(obj,2)

执行输出,效果同上!

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

例3

  1. class RoleConfig(object):
  2. def f1(self,arg):
  3. print('f1',arg)
  4. def f2(self,arg):
  5. print('f2',arg)
  6. def f3(self,arg):
  7. print('f3',arg)
  8.  
  9. list_display = [f1,f2]
  10.  
  11. def get_list_display(self):
  12. # insert() 函数用于将指定对象插入列表的指定位置
  13. # 0表示第一个元素位置
  14. self.list_display.insert(0,self.f3)
  15. return self.list_display
  16.  
  17. obj = RoleConfig()
  18. for item in obj.get_list_display():
  19. print(item)
  20. item(obj,2)

执行输出:

  1. <bound method RoleConfig.f3 of <__main__.RoleConfig object at 0x000001864A87C780>>
  2. Traceback (most recent call last):
  3. File "E:/python_script/django框架/day18/untitled/a.py", line 67, in <module>
  4. item(obj,2)
  5. 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

  1. class RoleConfig(object):
  2. def f1(self,arg):
  3. print('f1',arg)
  4. def f2(self,arg):
  5. print('f2',arg)
  6. def f3(self,arg):
  7. print('f3',arg)
  8.  
  9. list_display = [f1,f2]
  10.  
  11. def get_list_display(self):
  12. # insert() 函数用于将指定对象插入列表的指定位置
  13. # 0表示第一个元素位置
  14. self.list_display.insert(0,RoleConfig.f3)
  15. return self.list_display
  16.  
  17. obj = RoleConfig()
  18. for item in obj.get_list_display():
  19. print(item)
  20. item(obj,2)

执行输出:

  1. <function RoleConfig.f3 at 0x0000021D6DB15400>
  2. f3 2
  3. <function RoleConfig.f1 at 0x0000021D6D8B68C8>
  4. f1 2
  5. <function RoleConfig.f2 at 0x0000021D6DB152F0>
  6. f2 2

例4

  1. class RoleConfig(object):
  2. def f1(self,arg):
  3. print('f1',arg)
  4. def f2(self,arg):
  5. print('f2',arg)
  6. def f3(self,arg):
  7. print('f3',arg)
  8.  
  9. list_display = [f1,f2]
  10.  
  11. def get_list_display(self):
  12. # insert() 函数用于将指定对象插入列表的指定位置
  13. # 0表示第一个元素位置
  14. self.list_display.insert(0,RoleConfig.f3)
  15. return self.list_display
  16.  
  17. obj1 = RoleConfig()
  18. for item in obj1.get_list_display():
  19. # print(item)
  20. item(obj1,2)
  21.  
  22. obj2 = RoleConfig()
  23. for item in obj2.get_list_display():
  24. # print(item)
  25. item(obj1,6)

执行输出:

  1. f3 2
  2. f1 2
  3. f2 2
  4. f3 6
  5. f3 6
  6. f1 6
  7. f2 6

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

统计一下列表的数量

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

  1. class RoleConfig(object):
  2. def f1(self,arg):
  3. print('f1',arg)
  4. def f2(self,arg):
  5. print('f2',arg)
  6. def f3(self,arg):
  7. print('f3',arg)
  8.  
  9. list_display = [f1,f2]
  10.  
  11. def get_list_display(self):
  12. # insert() 函数用于将指定对象插入列表的指定位置
  13. # 0表示第一个元素位置
  14. self.list_display.insert(0,RoleConfig.f3)
  15. return self.list_display
  16.  
  17. obj1 = RoleConfig() # 此时list_display有2个元素
  18. for item in obj1.get_list_display():
  19. # 此时list_display有3个元素,因为执行了insert
  20. # 列表的值为f3,f1,f2
  21. item(obj1,2) # 输出f3,f1,f2
  22.  
  23. print('第一次统计数量:',len(RoleConfig.list_display)) # 3个
  24.  
  25. obj2 = RoleConfig() # list_display还是有3个,列表的值为f3,f1,f2
  26. for item in obj2.get_list_display():
  27. # 此时list_display有4个元素,因为再次执行了insert
  28. # 列表的值为f3,f3,f1,f2
  29. item(obj1,6) #输出f3,f3,f1,f1,f2
  30.  
  31. print('第二次统计数量:',len(RoleConfig.list_display))

执行输出:

  1. f3 2
  2. f1 2
  3. f2 2
  4. 第一次统计数量: 3
  5. f3 6
  6. f3 6
  7. f1 6
  8. f2 6
  9. 第二次统计数量: 4

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

例5

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

  1. class RoleConfig(object):
  2.  
  3. def f1(self, arg):
  4. print('f1', arg)
  5.  
  6. def f2(self, arg):
  7. print('f2', arg)
  8.  
  9. def f3(self, arg):
  10. print('f3', arg)
  11.  
  12. list_display = [f1, f2]
  13.  
  14. def get_list_display(self):
  15. v = []
  16. v.extend(self.list_display)
  17. v.insert(0,RoleConfig.f3)
  18. return v
  19.  
  20. obj1 = RoleConfig()
  21. for item in obj1.get_list_display():
  22. item(obj1,2)
  23.  
  24. obj2 = RoleConfig()
  25. for item in obj2.get_list_display():
  26. item(obj2,6)

执行输出:

  1. f3 2
  2. f1 2
  3. f2 2
  4. f3 6
  5. f1 6
  6. f2 6

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

看下面的注释

  1. num = 0 # 全局变量,统计列表数量
  2. class RoleConfig(object):
  3. def f1(self,arg):
  4. print('f1',arg)
  5. def f2(self,arg):
  6. print('f2',arg)
  7. def f3(self,arg):
  8. print('f3',arg)
  9.  
  10. list_display = [f1,f2]
  11.  
  12. def get_list_display(self):
  13. global num # 要使用全局变量,必须声明global
  14. num += 1 # 自增1
  15. v = [] # 定义空列表,每次执行时,列表重置为空列表
  16. v.extend(self.list_display) # 列表扩展,此时v=[f1,f2]
  17. v.insert(0,RoleConfig.f3) # 第一个位置插入f3,此时v=[f3,f1,f2]
  18. print('第%s次统计数量:'%num, len(v))
  19. return v
  20.  
  21. obj1 = RoleConfig() # 此时v有0个元素
  22. for item in obj1.get_list_display():
  23. # 此时v有3个元素
  24. item(obj1,2)
  25.  
  26. obj2 = RoleConfig() # 此时v有0个元素
  27. for item in obj2.get_list_display():
  28. # 此时v有3个元素
  29. item(obj1,6)

执行输出:

  1. 1次统计数量: 3
  2. f3 2
  3. f1 2
  4. f2 2
  5. 2次统计数量: 3
  6. f3 6
  7. f1 6
  8. f2 6

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

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

二、yield

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

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

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

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

应用场景

例1

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

以前的你

  1. def func(request):
  2. result = []
  3. data_list = models.Users.objects.all()
  4. for row in data_list:
  5. temp = "%s%s" %(row.name,row.pwd)
  6. result.append(temp)
  7. return render(result,'xxx.html',{'result':result})

xxx.html

  1. {% for row in result %}
  2. {{row}}
  3. {% endfor %}

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

现在的你

  1. def get_result(data_list):
  2. for row in data_list:
  3. temp = "%s%s" % (row.name, row.pwd)
  4. yield temp
  5.  
  6. def func(request):
  7. data_list = models.Users.objects.all()
  8. result = get_result(data_list)
  9. return render(result, 'xxx.html', {'result': result})

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

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

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

三、反射

getattr(object, name[,default])

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

举例

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

修改models.py,增加表

  1. from django.db import models
  2.  
  3. # Create your models here.
  4. class UserInfo(models.Model):
  5. username = models.CharField(verbose_name="用户名",max_length=32)

使用2个命令,生成表

  1. python manage.py makemigrations
  2. python manage.py migrate

使用navicat添加3条数据

修改urls.py,增加路径

  1. from django.conf.urls import url
  2. from django.contrib import admin
  3. from app01 import views
  4. urlpatterns = [
  5. url(r'^admin/', admin.site.urls),
  6. url(r'^test/', views.test),
  7. ]

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

  1. from django.shortcuts import render,HttpResponse
  2. from app01 import models
  3.  
  4. # Create your views here.
  5. def test(request):
  6. user_queryset = models.UserInfo.objects.all()
  7. for item in user_queryset:
  8. print(item.id,item.username)
  9.  
  10. return HttpResponse('ok')

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

查看Pycharm控制台输出:

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

反射对象

修改views.py,使用getattr

  1. from django.shortcuts import render,HttpResponse
  2. from app01 import models
  3.  
  4. # Create your views here.
  5. def test(request):
  6. user_queryset = models.UserInfo.objects.all()
  7. for item in user_queryset:
  8. print(item.id,item.username,getattr(item,'username'))
  9.  
  10. return HttpResponse('ok')

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

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

显示指定的列

修改views.py,增加属性list_display

  1. def test(request):
  2. list_display = ['id','username']
  3. user_queryset = models.UserInfo.objects.all()
  4. for item in user_queryset:
  5. row = []
  6. for field in list_display:
  7. row.append(getattr(item,field))
  8. print(row)
  9.  
  10. return HttpResponse('ok')

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

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

只取id,修改list_display

  1. from django.shortcuts import render,HttpResponse
  2. from app01 import models
  3.  
  4. # Create your views here.
  5. def test(request):
  6. list_display = ['id']
  7. user_queryset = models.UserInfo.objects.all()
  8. for item in user_queryset:
  9. row = []
  10. for field in list_display:
  11. row.append(getattr(item,field))
  12. print(row)
  13.  
  14. return HttpResponse('ok')

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

  1. [1]
  2. [2]
  3. [3]

获取verbose_name

修改views.py

  1. from django.shortcuts import render,HttpResponse
  2. from app01 import models
  3.  
  4. # Create your views here.
  5. def test(request):
  6. list_display = ['id','username']
  7. models_class = models.UserInfo
  8. verbose_name = models.UserInfo._meta.get_field('username').verbose_name
  9. print(verbose_name)
  10.  
  11. return HttpResponse('ok')

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

  1. 用户名

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

修改views.py

  1. from django.shortcuts import render,HttpResponse
  2. from app01 import models
  3.  
  4. # Create your views here.
  5. def test(request):
  6. list_display = ['id','username']
  7. models_class = models.UserInfo
  8. for name in list_display:
  9. verbose_name = models.UserInfo._meta.get_field(name).verbose_name
  10. print(verbose_name)
  11.  
  12. return HttpResponse('ok')

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

  1. ID
  2. 用户名

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

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

修改views.py

  1. from django.shortcuts import render,HttpResponse
  2. from app01 import models
  3.  
  4. # Create your views here.
  5. def test(request):
  6. list_display = ['id','username']
  7. header_list = []
  8. # models_class = models.UserInfo
  9. for name in list_display:
  10. verbose_name = models.UserInfo._meta.get_field(name).verbose_name
  11. header_list.append(verbose_name)
  12. print(header_list)
  13.  
  14. user_queryset = models.UserInfo.objects.all()
  15. for item in user_queryset:
  16. row = []
  17. for field in list_display:
  18. row.append(getattr(item, field))
  19. print(row)
  20.  
  21. return HttpResponse('ok')

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

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

去掉id字段

修改views.py

  1. from django.shortcuts import render,HttpResponse
  2. from app01 import models
  3.  
  4. # Create your views here.
  5. def test(request):
  6. list_display = ['username']
  7. header_list = []
  8. # models_class = models.UserInfo
  9. for name in list_display:
  10. verbose_name = models.UserInfo._meta.get_field(name).verbose_name
  11. header_list.append(verbose_name)
  12. print(header_list)
  13.  
  14. user_queryset = models.UserInfo.objects.all()
  15. for item in user_queryset:
  16. row = []
  17. for field in list_display:
  18. row.append(getattr(item, field))
  19. print(row)
  20.  
  21. return HttpResponse('ok')

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

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

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

python 全栈开发,Day113(方法和函数的区别,yield,反射)的更多相关文章

  1. python全栈开发-Day13 内置函数

    一.内置函数 注意:内置函数id()可以返回一个对象的身份,返回值为整数. 这个整数通常对应与该对象在内存中的位置,但这与python的具体实现有关,不应该作为对身份的定义,即不够精准,最精准的还是以 ...

  2. 巨蟒python全栈开发-第10天 函数进阶

    一.今日主要内容总览(重点) 1.动态传参(重点) *,** *: 形参:聚合 位置参数*=>元组 关键字**=>字典 实参:打散 列表,字符串,元组=>* 字典=>** 形参 ...

  3. python全栈开发-前方高能-内置函数2

    python_day_15 一.今日主要内容 1. lambda 匿名函数 语法: lambda 参数:返回值 不能完成复杂的操作 2. sorted() 函数 排序. 1. 可迭代对象 2. key ...

  4. python全栈开发_day11_作用域,函数嵌套和闭包

    一:作用域 1)什么是作用域 作用域是规定一个变量可以作用的范围,运行和销毁的范围 2)作用域的分类 1.内置作用域built_in:随着解释器的运行而产生,解释器运行的终止而销毁. 2.全局作用域g ...

  5. python全栈开发学习_内容目录及链接

    python全栈开发学习_day1_计算机五大组成部分及操作系统 python全栈开发学习_day2_语言种类及变量 python全栈开发_day3_数据类型,输入输出及运算符 python全栈开发_ ...

  6. python全栈开发 生成器 :生成器函数,推导式及生成器表达式

    python 全栈开发 1.生成器函数 2.推导式 3.生成器表达式 一.生成器函数 1.生成器: 生成器的本质就是迭代器 (1)生成器的特点和迭代器一样.取值方式和迭代器一样(__next__(), ...

  7. python全栈开发之匿名函数和递归函数

    python 匿名函数和递归函数 python全栈开发,匿名函数,递归函数 匿名函数 lambda函数也叫匿名函数,即函数没有具体的名称.是为了解决一些功能很简单需求而设计的一句话函数.如下: #这段 ...

  8. Python全栈开发【面向对象进阶】

    Python全栈开发[面向对象进阶] 本节内容: isinstance(obj,cls)和issubclass(sub,super) 反射 __setattr__,__delattr__,__geta ...

  9. Python全栈开发【面向对象】

    Python全栈开发[面向对象] 本节内容: 三大编程范式 面向对象设计与面向对象编程 类和对象 静态属性.类方法.静态方法 类组合 继承 多态 封装 三大编程范式 三大编程范式: 1.面向过程编程 ...

随机推荐

  1. ajax跨域原理和cors跨域资源共享

    不需要设置前端太多,只需要在服务端是在请求头,使服务端的回复数据可以正常通过浏览器的限制,进入网站 首先说下简单请求和非简单请求: 简单请求:必须满足下列条件 1.请求方式:head,get,post ...

  2. Hive记录-Hive常用命令操作

    1.hive支持四种数据模型 • external table ---外部表:Hive中的外部表和表很类似,但是其数据不是放在自己表所属的目录中,而是存放到别处,这样的好处是如果你要删除这个外部表,该 ...

  3. ELF格式探析之三:sections

    前文链接: ELF格式探析之一:Segment和Section ELF格式探析之二:文件头ELF Header详解 今天我们讲对目标文件(可重定位文件)和可执行文件都很重要的section. 我们在讲 ...

  4. u-boot移植(十二)---代码修改---支持DM9000网卡

    一.准备工作 1.1 原理图 CONFIG_DM9000_BASE 片选信号是接在nGCS4引脚,若要确定网卡的基地址,则要根据片选信号的接口去确定. 在三星2440的DATASHEET中memory ...

  5. Bleve代码阅读(二)——Index Mapping

    引言 Bleve是Golang实现的一个全文检索库,类似Lucene之于Java.在这里通过阅读其代码,来学习如何使用及定制检索功能.也是为了通过阅读代码,学习在具体环境下Golang的一些使用方式. ...

  6. php 利用root 权限执行shell脚本

    http://blog.csdn.net/lxwxiao/article/details/8513355 也可以指定某个shell文件不需要密码 www-data ALL=(ALL) NOPASSWD ...

  7. mysql架构解读~mysql的多源复制

    一 场景需求 多源复制版本 5.7,目标主机5.6.21 4个DB机器的某些数据库需要数据汇总进行连表查询 二 进行搭建  1 导出相应的目的库     mysqldump -uuser -ppass ...

  8. java读取视频文件时长

    1.下载jar包:http://www.sauronsoftware.it/projects/jave/index.php 2.上代码 @RequestMapping(value = "am ...

  9. vmware添加磁盘后linux无需重启识别的方法

    cd /sys/class/scsi_host/ [root@centos4 scsi_host]# ls host0 host1 host2 有几个host就刷几次 [root@centos4 sc ...

  10. jvm系列五、jvm垃圾回收机制、jvm各种参数及调优

    转载自:http://yufenfei.iteye.com/blog/1746914 尊重原创. 一.GC有两种类型:Scavenge GC 和Full GC 1.Scavenge GC 一般情况下, ...