私有属性(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'))