Python Advanced notes-2 fangfu的技术博客

python中的变量 python的变量实质上是一个指针,包括int、str, 实质上是变量这个指针贴在对象上面:

a=[1,2,3]
b=a
b.append(4)
print(a is b)
print(a)
print(b)
print(id(a),id(b))

a和b同时指向了相同的list,先生成对象,再贴上变量。

“is”是判断两个对象的id是否相等,“==”判断值是否相等,eq 注意特例:python内部有一个优化机制:intern机制,当对象的值为小整数的时候,他们的id也是相等的。

python中的垃圾回收算法是采用 引用计数, 当一个变量指针指向一个对象,对象计数器+1,

a = object()
b = a
del a
print(b)
print(a)

对象在计数器减到0的时候,才会对对象进行回收 我们可以自定义对象的del方法,在python解释器调用del的时候,执行我们的自定义逻辑:

class A:
    def __del__(self):
        pass

当把list作为参数,注意没有传参数时的默认值:

class Company:
    def __init__(self, name, staffs=[]):
        self.name = name
        self.staffs = staffs

    def add(self, add_name):
        self.staffs.append(add_name)
    def remove(self, del_name):
        self.staffs.remove(del_name).

print(Company.__init__.__defaults__)

所以尽量不要把list作为参数进行传递,如果一定要用,注意它的默认值

@property会把一个函数变成一个属性描述符,它属于get方法,如果我们需要set,可以使用setter,如:

from datetime import date, datetime

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

    # def get_age(self):
    #     return datetime.now().year - self.birthday.year

    @property
    def age(self):
        return datetime.now().year - self.birthday.year

    @age.setter
    def age(self, value):
        self._age = value

if __name__ == "__main__":
    user = User("Tom", date(year=1990, month=1, day=1))
    # print(user.get_age())
    user.age = 30
    print("_age is:", user._age)
    print("age is:", user.age)

getattr:在查找不到类属性的时候会调用,免得抛出异常。 getattribute: 在任何情况下,都会无条件的调用这个函数,一般无需去自定义这个函数 如下示例:

from datetime import date, datetime

class User:
    def __init__(self, info={}):
        self.info = info

    def __getattr__(self, item):
        return self.info[item]

    # def __getattribute__(self, item):
    #     return

    def get_age(self):
        return datetime.now().year - self.birthday.year

if __name__ == "__main__":
    user = User({"company": "sina", "name": "Cattie", "birthday": datetime(year=1990, month=1, day=1)})
    print(user.info["company"])
    print(user.get_age())

关于属性描述符: 如果一个类中有__get__或__set__或__delete__,这个类就可以叫做属性描述符 如果user是某个类的实例,那么user.age等价于getattr(user,”age”),在执行user.age的时候,首先调用__getattribute__,如果类定义了__getattr__方法,那么在__getattribute__抛出AttributeError的时候,就会调用到__getattr__. 而对于属性描述符__get__的调用,则是发生在__getattribute__内部的。 user=User(),那么user.age执行顺序如下: 1、如果age是出现在User或其基类的__dict__中,且age是data descriptor,那么调用data descriptor的get方法,否则执行下一步。 2、如果age出现在user对象的__dict__中,那么直接返回obj.dict[‘age’],否则执行下一步。 3、如果age出现在类User或其基类的__dict__中,则: 3-1、如果age是non-data descriptor,那么调用non-data descriptor的__get__方法,否则执行下一步 3-2、返回__dict__[‘age’] 4、如果类User有定义__getattr__,调用__getattr__方法,否则执行下一步 5、抛出异常AttributeError

可以通过代码来理解:

import numbers

class Attr:
    #  data descriptor
    def __get__(self, instance, owner):
        return self.value
    def __set__(self, instance, value):
        if not isinstance(value, numbers.Integral):
            raise ValueError("we need some numbers")
        elif value<=0:
            raise ValueError("age can not less than 0")
        elif value>=150:
            raise ValueError("age can not too large")
        self.value = value
    def __delete__(self, instance):
        pass

class NonDataAttr:
    #  non-data descriptor
    def __get__(self, instance, owner):
        return "this is NonDataAttr"

class User:
    age = Attr()           #如果指向数据描述符,则优先返回
    #age = NonDataAttr()   #如果指向非数据描述符,则会在第三步返回

if __name__ == "__main__":
    user = User()
    user.age = 30
    print(user.age)

注意区分user.dict[‘age’]=30与user.age=30的区别 print(user.dict.[‘age’])与print(user.age)的区别

__new__在前面执行,传递类,可以自定义类的生成过程,在对象生成之前,控制对象的生成过程 __init__在后面执行,传递对象,对对象进行操作,也是用来完善对象的 如果new方法不返回对象,则不会调用init函数

class User:
    def __new__(cls, *args, **kwargs):
        print("new")
        return super().__new__(cls)

    def __init__(self, name):
        print("init")
        self.name = name

if __name__ == "__main__":
   # user = User(name="jack")
    user = User("jack")
    print(user.name)

type(object_or_name, bases, dict) type(类名称,基类,属性) User = type(“ddd”, (), {}) User = type(‘ddd’, (BaseClass,), {“name”: “dd”, “saddy”:say}) 元类是创建类的类,如type

python中类的实例化过程中,会首先寻找metaclass,通过metaclass去创建类,如果没有,则会去基类中寻找metaclass,如果还是没有,则会去模块中找,最后才会去调用type去创建类对象,实例 我们创建类就是为了创建类的实例,我们创建元类就是为了创建类 创建类我们需要定义__new__()函数,用来创建对象并返回方法`` 可以在类生成对象之前,通过__new__做检查

ORM就是使用元类的例子,把关系数据库的一行映射为一个对象,也就是一个类对应一个表,

关于元类及ORM相关,可以参考下面链接: 使用元类-廖雪峰的官方网站

FFwechat FFalipay