可變對象與不可變對象
在python中,可變對象有數值類型(int,float),字符串(str),元組(tuple),可變對象有列表(list),字典(dict),集合(set)。在賦值操做中 可變對象是複製的對象自己,至關於複製了對象的指針,對賦值後的修改會修改原來的對象 例如:python
In [1]: b = [1,2,3,4] In [2]: _b = b In [3]: id(_b) Out[3]: 4519417736 In [4]: id(b) Out[4]: 4519417736 In [5]: _b.append(6) # 修改_b,b也會跟着一塊兒變化,由於_b和b指向的是同一個地址 In [6]: b Out[6]: [1, 2, 3, 4, 6]
能夠看出修改了_b的值,也修改了b的值,若是想僅僅修改_b的值,須要使用 _b = copy.copy(b)
而不是簡單的_b = b
。
對於不可變對象,對象自己的值是不能修改的,每次對其的操做都會生成一個新的對象,保存新的值。以下:sql
In [1]: a = "sss" In [2]: id(a) Out[2]: 4338243040 In [3]: a += "c" # 不可變對象的賦值並不會使用同一個地址,因此id會發生變化 In [4]: id(a) Out[4]: 4338242704
因此在函數中傳入可變對象的時候,要當心,由於可能修改原有的對象。數據庫
元編程(metaclass)
在正常業務開發時不多使用,但在一些庫中常常遇到,例如Django的ORM,其主要功能是在類初始化(不是實例化)的時候,定義一些行爲和操做,代碼以下django
import os import numpy import random class MetaClass(type): def __init__(self, *args, **kwargs): print('Meta Init') def __new__(cls, name, base, attr): print('class_name is :' , name) print(base,' is the Base *****') print(cls.v, getattr(cls, 'b', 99 )) print('==========') del cls.v return super(MetaClass, cls).__new__(cls, name, base, attr) class Model(metaclass=MetaClass): # python3中指定metaclass指定方式 __metaclass__ = MetaClass # python2中指定方式 MetaClass.v = 100 MetaClass.b = '-------------' c = 9 def __new__(cls, name, base, attrs): print('Model New---') return super(Model, cls).__new__(cls, name, base, attrs) def __init__(self, *args, **kwargs): self.arg = args self.kwargs = kwargs def __str__(self): return "test Models ----->>>>>>" class Test(metaclass=MetaClass): __metaclass__ = MetaClass MetaClass.v = 888 class Serial(Model): MetaClass.v = 777 class test(Serial): MetaClass.v = 666
在import 或者直接運行的時候,咱們沒有作任何類的實例化操做,但仍是會有下面的打印信息,會發現,繼承的每一個類都運行了metaclass中的__new__
和__init__
方法編程
class_name is : Model () is the Base ***** 100 ------------- ========== Meta Init class_name is : Test () is the Base ***** 888 ------------- ========== Meta Init class_name is : Serial (<class '__main__.Model'>,) is the Base ***** 777 ------------- ========== Meta Init class_name is : test (<class '__main__.Serial'>,) is the Base ***** 666 ------------- ========== Meta Init
slots
在python中,通常咱們能夠自由的給類,實例添加屬性,然而有時候咱們並不但願這樣,咱們須要指定的類只能有咱們要求的這些屬性,在這種狀況下,咱們引入了__slots__
例如:緩存
class R(object): """在這個類中,咱們只能添加prev,next等的屬性, 當嘗試添加別的的時候,會報AttributeError""" __slots__ = 'prev', 'next', 'key', '__weakref__' class Link(R): 「」「__slots__ 不會被繼承,因此在這個類中可添加指定以外的屬性」「」 pass class Node(R): """添加了 __slots__ 以後,父類的 __slots__也會生效,此時, 限制的屬性爲 value, prev, next 等 """ __slots__ = "value",
Django Queryset 切片
咱們知道Django 的queryset是lazy的,只有當真正使用的時候纔會去數據庫取數據,而且緩存取出來的數據。
因此對於沒有執行的queryset,切片操做以後仍然是queryset,執行sql以後的queryset,切片會變成list。app
In [2]: qs = Order.objects.all() In [3]: qs_1 = qs[10:20] In [4]: type(qs_1) Out[4]: django.db.models.query.QuerySet In [5]: _qs = list(qs) # 會查詢數據 In [6]: qs_2 = qs[10:20] In [7]: type(qs_2) Out[7]: list