《python笔记》property、__new__、__init__、元类、getattr、属性描述符和属性查找过程

私有属性(property)

#python的私有属性(property)
#coding:utf-8
from datetime import date,datetime
class User:
    def __init__(self,name,birthday):
        self.name = name
        self.birthday = birthday
        self._age = 0 #前面加一个下划线_是python类编程中的一种规范,不想让属性age对外暴露,
                      # 是想通过方法或者属性描述符的方式来访问


    # 这样写代码只能通过调用实例的gat_age()方法获得age:user.get_age()
    # def get_age(self):
    #     return datetime.now().year-self.birthday.year

    #@property把一个getter方法变成属性,@score.setter把一个setter方法变成属性赋值

    # 动态属性获取的方式加入自己的逻辑
    #可以通过实例属性获得年龄:user.age
    @property
    def age(self):
        return datetime.now().year - self.birthday.year

    # 可以通过实例属性赋值,
    @age.setter
    def age(self,value):
        self._age=value  #在setter里,赋值的属性一定要是以一个下划线开始的,
                        # 这个属性可以在__init__函数中定义,也可以在property中定义返回值:return self._age


if __name__ == "__main__":
    user = User("Tom",date(year=1973,month=12,day=23))
    #print(user.get_age())
    print(user.age)
    user.age=20  #
    print(user._age)

__new__方法、__init__方法

#__new__方法可以自定义类的生成过程,cls传递进来的是类User
#__init__方法是对对象进行处理,self传递进来的是对象
class User():
    def __new__(cls,*args,**kwargs):
        print("in new")
        return super().__new__(cls)
    def __init__(self,name):
        print("in init")
        pass

#new用来控制对象的生成过程,在对象生成之前,也即在__init__之前
#init是用来完善对象的
#如果new方法不返回对象,则不会调用init方法
if __name__=="__main__":
    user=User(name='bobby')
    #user = User('bobby')

元类(metaclasss)

#元类
#有3种方式创建类(1)通过函数创建类(2)通过type创建类(3)通过metaclass创建类
#类也是对象,type是创建类的类
def create_class(name):
    if name=="user":
        class User:
            def __str__(self):
                return "user"
        return User
    if name=="company":
        class Company:
            def __str__(self):
                return "company"
        return Company
#以上语句可以动态创建类,但还是不够灵活,仍需要我们自己在函数中创建类,写class语法
#改进方法:用type动态创建类
#type("User",(),{})
#()这个空tuple表示默认继承的基类是object
#{}这个dict用来添加属性和方法

#定义一个方法
def say(self):#必须要有一个self参数
    return "i am user"

class Baseclass(object):
    def answer(self):
        return "i am baseclass!"
#____________________________________________
class MetaClass(type):
    def __new__(typ,*args,**kwargs):
        return super().__new__(typ,*args,**kwargs)

#什么是元类:元类是创建类的类,对象由class(对象)生成,class由type生成
class User(metaclass=MetaClass):
    def __init__(self,name):
        self.name=name
    def __str__(self):
        return "i am str"

#python中类的实例化过程:首先会寻找metaclass,通过metaclass创建user类
#去创建类对象,实例

if __name__ == "__main__":
    # MyClass=create_class('user')
    # my_obj=MyClass()
    # print(my_obj)#user
    #----------------------------------
    # User=type("User",(Baseclass,),{"name":"Tom","say":say})#后面的say不要加()
    # my_obj=User()
    # print(my_obj.name)#Tom
    # print(my_obj.say())#i am user  这里的say要加(),因为调用的是方法
    # print(my_obj.answer())#i am baseclass!
    #-------------------------------------------------------
    my_obj=User(name="Tony")
    print(my_obj)

getattr

#coding:utf-8
#__getattr__,__getattribute__
#__getattr__是在查找不到属性的时候调用
#__getattribute__是无条件的调用,一般不建议使用,一旦使用不好就会使属性的访问错乱

class User1:
    def __init__(self,name):
        self.name=name

    def __getattr__(self,item):
        return self.name

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

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

class User3:
    def __init__(self, name):
        self.name = name

    def __getattr__(self, item):
        return self.name

    def __getattribute__(self, item):
        return "bobby"

if __name__=="__main__":
    user1=User1("company")
    print(user1.Name)
    # 没用getattr函数时,报错,因为没有Name这个属性:'User' object has no attribute 'Name'
    # 使用getattr函数后,不会报错,会直接打印出user的name属性:company

    user2=User2(info={"name":"Tom","company2":"www.yy.com"})
    print(user2.name)  #Tom
    print(user2.company2)#通过getattr函数可以通过访问字典里的key获得key对应的value

    user3=User3("company")
    print(user3.name)#bobby
    print(user3.test)#bobby

python属性描述符和属性查找过程

#coding:utf-8
#属性描述符和属性查找过程
#属性描述符分为两种:1,数据属性描述符。2,非数据属性描述符
import numbers
#只要实现下面3个方法中的任何一个,IntField就是属性描述符
class IntField:
    #数据属性描述符
    def __get__(self,instance,owner):
        return self.value #这个value就是下面自己定义的
    #在__set__做参数类型的检查
    def __set__(self,instance,value):
        if not isinstance(value,numbers.Integral):
            raise ValueError("int value need")
        if value<0:
            raise ValueError("positive value need")
        #instance.age=value 不能这么存放值,因为这种属性赋值的方法会循环调用__set__方法
        self.value=value#将值放在了IntField类里面,前面一个value是自己命名的,随便叫什么都可以
    def __delete__(self,instance):
        pass

class NonDataIntField:
    #非数据属性描述符
    def __get__(self,instance,owner):
        return self.value

class User:
    #age=IntField()#age是一个数据属性描述符的对象
    age=NonDataIntField()
"""
属性查找过程:
如果user是某个类的实例,那么user.age(以及等价的getattr(user,'age'))首先调用__getattribute__。
如果类定义了__getattr__方法,那么在__getattribute__抛出AttributeError的时候就会调用到__getattr__,
而对于描述符(__get__)的调用,则发生在__getattribute__内部的。
user=User(),那么user.age顺序如下:
(1)如果“age”出现在User或其基类(父类)的__dict__中,且age是data descriptor,那么调用其__get__方法,否则
(2)如果“age”出现在user的__dict__中,那么直接返回obj.__dict__['age'],否则
(3)如果“age”出现在User或其基类(父类)的__dict__中,
(3.1)如果age是non-data descriptor,那么调用其__get__方法,否则
 (3.2)返回__dict__['age']
(4)如果User有一个__getattr__方法,调用__getattr__方法,否则
(5)抛出AttributeError
"""
if __name__ == "__main__":
    user=User()
    user.age=20  #当age是数据属性描述符时,对其赋值的时候,会调用IntField中的__set__方法,该值进入IntField的value中,而不会进入user的__dict__中
    user.__dict__['age']='abc'
    print(user.__dict__)#__dict__方法用来查询属性,当age是非数据属性描述符时,age就会进入user的属性中:{'age': 20}
    print(user.__dict__['age'])# abc
    print(user.age)# 因为age是数据属性描述符,使用user.age的时候还是会调用IntField中的value值,而不会调用user的属性值abc
    print(getattr(user,'age'))

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值