面向对象
一、函数式编程举例和特点:程序变得简洁、可读性差、只能通过递归实现、没有for循环
# def test(x):
# return 2 * x
# a = test(5)
# print(a)
二、类是描述共同的特征和动作、是特征和动作的结合
def dog(name,gender,type):
# 狗的动作
def jiao(dog):
print("一条狗[%s],汪汪汪" %dog["name"])
def chi_shi(dog):
print("一条[%s]正在吃屎" %dog["type"])
def init(name,gender,type):
dog1 = {
"name": name,
"gender": gender,
"type":type,
"jiao": jiao,
"chi_shi":chi_shi,
}
return dog1
return init(name,gender,type)
三、d1就是对象传的参数会触发类当中的init函数初始化的运行这就是面向对象设计
d1 = dog("元昊","母","中华田园犬")
d2 = dog("alex","母","藏獒")
print(d1,d2)
d1["jiao"](d1)
d2["chi_shi"](d2)
四、类和对象的定义?
五、类的属性有哪些?
六、类定义:1、关键字class、
2、首字母一般大写、
3、标明文档字符串、
4、类加括号代表执行、类的运行过程是实例化、
class Chinese:
"这是一个中国人的类"
pass
# print(Chinese) #<class '__main__.Chinese'>、__main__代表声明的模块名
p1 = Chinese()
print(p1)
七、函数和类的相同点和不同点?
相同点:都是加括号运行
不同点:1、函数的运行代表的是一段逻辑,类的运行是实例化,产生一个实例,
2、类的返回值是具体的实例,函数的返回值是return。
#8、这是经典类
def test():
pass
print(test)
#9、新式类是传入的是对象,代表类名继承括号里面的对象
class Chinese(object):
pass
#10、
class Chinese:
"这是一个中国人的类"
dang = "gcd"
def sui_di_tu_tan():
print("朝着墙上就是一口痰")
def cha_dui(self):
print("插到了前面")
print(Chinese.dang) #用点来访问
Chinese.sui_di_tu_tan()
Chinese.cha_dui("元昊")
print(dir(Chinese))#11、查看类的属性、不是杠杠开头的都是函数属性(例如def sui_di_tu_tan)和数据属性dang,dir查看属性生成的是列表,里面包含的是名称
八、查看类的属性字典
print(Chinese.__dict__)#生成的是字典,__杠杠开头都是系统内置的方法、得到的是函数的内存地址信息
#13、根据类的属性字典取出值
print(Chinese.__dict__["dang"])#取出数据属性对应字典里面的值
Chinese.__dict__["sui_di_tu_tan"]()#取出函数属性对应字典里面的值
Chinese.__dict__["cha_dui"](1)#取出函数属性对应字典里面的值加参数
在Python中所有的类都有一个共同的object
#1、定义类不用加参数不用return
class ChinessPeople:
"我们都是中国人,我们骄傲的活着,我们不服任何事和物"
government = "***"
# def __init__(name,age,gender):
# dic = {
# "name":name,
# "age":age,
# "gender":gender
# }
# return dic
def __init__(self,name,age,gender): #self就是实例自己、定义mingzi给name并封装到self里面、最后class默认自动return了、返回的就是字典、字典中封装的是
print("我是初始化函数,我开始运行了")
self.mingzi = name #self就是实例自己,点代表给mingzi定义成传入的参数name
self.nianji = age
self.xingbie = gender
print("我结束啦")
def sui_di_tu_tan(self):
print("%s 朝着墙上就是一口痰" %self.mingzi)
def cha_dui(self):
print(self)
print("%s 插到了前面" %self.mingzi)
def eat_food(self,food):
print("%s 正在吃%s" %(self.mingzi,food))
九、实例化的过程本质就是调用的__init__函数,实例本身也有一个__dict__,用这个__dict__就可以看到实例的字典形式。类和函数的作用域是一样的。
#2、取类的名字字符串__name__
print(ChinessPeople.__name__)
#3、取文档__doc__
print(ChinessPeople.__doc__)
#4、取继承__base__
print(ChinessPeople.__base__)
#5、取元组的形式出来__bases__
print(ChinessPeople.__bases__)
#6、取这个类在哪个模块
print(ChinessPeople.__module__)
#7、类运行加括号、有个返回值定义下就是实例化
p1 = ChinessPeople("元昊",18,"female")
print(p1.__dict__)
#8、调字典里面的值
print(p1.__dict__["xingbie"])
#9、调名字
print(p1.mingzi)
#10、调党
print(p1.government)
#11、打印函数属性
# ChinessPeople.__dict__["sui_di_tu_tan"]()
#12、类调的方法和实例无关系这是在无参的情况
# ChinessPeople.sui_di_tu_tan()
#13、类调的方法和实例有关系在有参的情况下
ChinessPeople.cha_dui(p1)
十、类的数据属性增删查改
class chinesePeple:
country = "China"
def __init__(self,name):
self.name = name
def play_ball(self,ball):
print("%s 正在打 %s" %(self.name))
def say_word(self,word):
print("%s 说 %s" %(self.name,word))
#1、查看类属性
print(chinesePeple.country)
#2、修改类属性
chinesePeple.country = "CHINA"
print(chinesePeple.country)
#3、删除类属性
# del chinesePeple.country
print(chinesePeple.country)
#4、增加类属性
chinesePeple.country = "china"
chinesePeple.country = "Asia"
print(chinesePeple.country)
#5、生成实例要传值
p1 = chinesePeple("alex")
print(p1.__dict__)
print(p1.country)
十一、类的函数属性增删查改
增加:
def eat_food(self,food):
print("%s 正在吃%s" %(self.name,food))
Chinese.eat_food = eat_food
print(Chinese.__dict__)
p1.eat("饭")#这步是传值
改:
def test(self):
print("test")
Chinese.play_ball = test
p1.play_ball()
十二、实例的增删查改:
增:
p1.age = 18
print(p1.__dict__)
print(p1.age)
p1.test(p1)#可以自己调自己,
实例只有数据属性
删除;
del p1.age
print(p1.__dict__)
十二.1、生成实例之前增加输入和输出功能?
class Chinese:
def __init__(self,name):
self.name = name
def play_ball(self,ball):
print("%s 正在打 %s" %(self.name,ball))
def shi_li_hua():
name = input(">>:")
p1 = Chinese(name)
print(p1.name)
shi_li_hua()
十三、点的调用只能是调用类和实例,逗号后面跟的是变量。
十四、实例调用类的数据属性,实例修改实例的属性,实例往类的数据属性append
class Chinese:
country = "China"
l = ["a","b"]
def __init__(self,name):
self.name = name
def play_ball(self,ball):
print("%s 正在打 %s" %(self.name,ball))
#实例调用类的数据属性
p1 = Chinese("zd")
print(p1.country)
#实例修改实例的属性
p1.country = "Japan"
print(Chinese.country)
#实例往类的数据属性append
p1.l.append("c")
print(Chinese.l)
十五、静态属性property的用法是把函数封装成数据属性的形式,让外部在调的时候看不到内部的逻辑,self代表的是实例本身,既可以访问自己的也可以访问类的,
class Room:
def __init__(self,name,owner,width,length,heigh):
self.name = name
self.owner = owner
self.width = width
self.length = length
self.heigh = heigh
#定义计算面积
#定义类提供的装饰器
@property #(property是属性的意思)property的作用就是把函数属性变成了数据属性调用的时候看起来是调用了数据属性
def cal_area(self):
# print("%s 住的 %s 总面积是%s" % (self.owner, self.name, self.width * self.length))
#这个可以定义下return返回的宽度*长度的面积
return self.width * self.length
#2、生成实例
r1 = Room("厕所","alex",100,100,10000)
r2 = Room("公共厕所","yuanhao",1,1,1)
#3、求面积:长乘宽乘高
# print("%s 住的 %s 总面积是%s" %(r2.owner,r2.name,r2.width*r2.length))
#实例化产生对象、加括号的原因是拿到属性以后判断是函数属性加小括号运行一下
# r1.cal_area()
# r2.cal_area()
#实例化产生对象不加小括号
r1.cal_area
r2.cal_area
#类产生对象
# Room.cal_area(r1)
#调r1的数据属性
# print(r1.name)
# r1.name
#打印下r1.cal_area执行的函数
print(r1.cal_area)
print(r2.cal_area)
十六、类方法classmethod,用类调用类里面的数据属性,可以访问到函数属性,不能访问到实例里面的属性。
class Room:
tag = 1
def __init__(self,name,owner,width,length,heigh):
self.name = name
self.owner = owner
self.width = width
self.length = length
self.heigh = heigh
#定义计算面积
#定义类提供的装饰器
@property #(property是属性的意思)property的作用就是把函数属性变成了数据属性调用的时候看起来是调用了数据属性
def cal_area(self):
# print("%s 住的 %s 总面积是%s" % (self.owner, self.name, self.width * self.length))
#这个可以定义下return返回的宽度*长度的面积
return self.width * self.length
def test(self):
print("from test",self.name)
@classmethod
def tell_info(cls,x):
print(cls)
print("--》",cls.tag,x)
#打印类的详细信息
# def tell_info(self):
# print("----->",self.tag)
#2、生成实例
r1 = Room("厕所","alex",100,100,10000)
r2 = Room("公共厕所","yuanhao",1,1,1)
#3、求面积:长乘宽乘高
# print("%s 住的 %s 总面积是%s" %(r2.owner,r2.name,r2.width*r2.length))
#实例化产生对象、加括号的原因是拿到属性以后判断是函数属性加小括号运行一下
# r1.cal_area()
# r2.cal_area()
#实例化产生对象不加小括号
# r1.cal_area
# r2.cal_area
#类产生对象
# Room.cal_area(r1)
#调r1的数据属性
# print(r1.name)
# r1.name
#打印下r1.cal_area执行的函数
print(r1.cal_area)
print(r2.cal_area)
#调数据属性
print("这是数据属性",Room.tag)
#调函数属性self要求传具体的实例
# Room.test(1)
#制作类方法
# r1 = Room("厕所","alex",11,22,33)
# print("下面是执行的类方法")
# Room.tell_info(r1)
#调用类方法
print("下面是打印的类方法")
Room.tell_info(10)
十七、静态方法staticmethod不能类属性和实例属性
class Room:
tag = 1
def __init__(self,name,owner,width,length,heigh):
self.name = name
self.owner = owner
self.width = width
self.length = length
self.heigh = heigh
#定义计算面积
#定义类提供的装饰器
@property #(property是属性的意思)property的作用就是把函数属性变成了数据属性调用的时候看起来是调用了数据属性
def cal_area(self):
# print("%s 住的 %s 总面积是%s" % (self.owner, self.name, self.width * self.length))
#这个可以定义下return返回的宽度*长度的面积
return self.width * self.length
def test(self):
print("from test",self.name)
@classmethod
def tell_info(cls,x):
print(cls)
print("--》",cls.tag,x)
@staticmethod #(staticmethod意思是静态)是类的工具包
def wash_body(a,b,c):
print("%s %s %s 正在洗澡" %(a,b,c))
Room.wash_body("alex","yuanhao","wupeiqi")
r1 = Room("厕所","alex",100,100,10000)
r1.wash_body("alex","yuanhao","wupeiqi")
十八、property跟实例绑定需要传入参数classmethod跟类绑定staticmethod不跟任何绑定(叫做类的工具包)
十九、组合就是拼接
二十、选课系统
class School:
def __init__(self,name,addr):
self.name = name
self.addr = addr
def zhao_sheng(self):
print("%s 正在招生" %(self.name))
class Course:
def __init__(self,name,price,period,school): #period周期
self.name = name
self.price = price
self.period = period
self.school = school
s1 = School("oldboy","北京")
s2 = School("oldboy","南京")
s3 = School("oldboy","东京")
c1 = Course("linux",10,"1h",s1)
print(s1.__dict__)#产生实例字典
print(c1.__dict__)
print(c1.school.name)
msg = """
1 老男孩 北京校区
2 老男孩 南京校区
3 老男孩 东京校区
"""
while True:
print(msg)
memu = {
"1":s1,
"2":s2,
"3":s3,
}
choice = input("选择学校>>:")
school_obj = memu[choice]
name = input("课程名》》:")
price = input("课程费用》》:")
period = input("课程周期》》:")
new_course = Course(name,price,period,school_obj)
print("课程【%s】属于【%s】学校" %(new_course.name,new_course.school.name))
二十一、面向对象编程三大特性继承、多态、封装
class Dad:
"这个是爸爸类"
money = 10
def __init__(self,name):
print("爸爸")
self.name = name
def hit_son(self):
print("%s 正在打儿子" %self.name)
class Son(Dad):#单继承
money = 10000000009
def __init__(self,name,age):
self.name = name
self.age = age
print(Son.money)#继承钱
#打儿子
# Son.hit_son()
#儿子的属性字典
print(Son.__dict__)
#爸爸属性字典
print(Dad.__dict__)
print("嘿嘿嘿")
s1 = Son("alex",18)
print(s1.name)
print(s1.money)
print(s1.__dict__)
什么时候用继承?
#1、当两个类之间没有共性用组合比较好(例如机器人组合)、有共性的用继承比较好(例如猫和狗都有吃喝拉撒特征只是一个是汪汪叫另外一个是喵喵叫)
2、继承查找的方式是先在自己的区域找若没有再去父类找,自己区域有的不会覆盖父类里面的。
派生?
描述了子类衍生出新的特性,新类保留已存在类类型中所有需要的数据和行为,但允许修改或者其他的自定义操作,都不会修改原类的定义。
什么是接口继承?
接口就是一个函数,定义一个基/父类,基类当中把自己的方法定义成接口函数,利用装饰器的方式,如果有子类调用接口,子类就必须实现基/父类中的方法,若不实现的话子类就不能实例化,这也是
归一化设计。目的是规范子类
举例如下
import abc
class All_file(metaclass=abc.ABCMeta):
@abc.abstractmethod#abc模块下面抽象的方法
def read(self):
pass
@abc.abstractmethod
def write(self):
pass
class Disk(All_file):
def read(self):
print("disk read")
def write(self):
print("disk write")
class Cdrom(All_file):
def read(self):
print("cdrm read")
def write(self):
print("cdrm write")
class Mem(All_file):
def read(self):
print("mem read")
def write(self):
print("mem write")
m1 = Mem()
m1.read()
m1.write()
继承顺序?
深度优先?
广度优先?
继承顺序内部是如何实现的?定义的每一个类,Python会计算出一个方法解析顺序(MRO)列表,这个列表的构造是通过一个C3线性化算法实现的,遵循三条准则:1、子类会优先于父类被检查,2、多个
父类会根据他们在列表中的顺序被检查,3、如果对下一个类存在两个合法的选择会先选择第一个父类。
举例如下
class A:
def test(self):
print("A")
class B(A):
def test(self):
print("B")
class C(A):
def test(self):
print("C")
class D(B):
def test(self):
print("D")
class E(C):
def test(self):
print("E")
class F(D,E):
def test(self):
print("F")
f1 = F()
print(F.__mro__)
(<class '__main__.F'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
子类中用点的方式调用父类举例如下:
class Vehicle:#1、定义交通工具类
Courty = "China" #2、定义数据属性
def __init__(self,name,speed,load,power):#3、定义初始化函数、名字name、速度speed、容量load、能源power
self.name = name #4、name参数传入实例里面
self.speed = speed #5、speed参数出入实例里面
self.load = load #6、load参数传入实例里面
self.power = power #7、power参数出入实例里面
def run(self): #8、定义火车开动啦的函数属性
print("开动啦")
class Subway(Vehicle): #9、定义地铁类
def __init__(self,name,speed,load,power,line): #10、定义初始化函数、名字name、速度speed、容量load、能源power、几号线line
Vehicle.__init__(self,name,speed,load,power) #11、地铁子类调用父类交通工具
self.line = line
def subinfo(self):
print("%s %s 号线地铁开动了" %(self.name,self.line))
def subrun(self): #12、定义地铁的运行函数
Vehicle.run(self)#13、子类调用父类
s1 = Subway("北京","10km/s",1000000000000,"电",13)#14、生成实例
s1.subinfo() #15、运行地铁信息
s1.subrun() #16、
#在子类中调用父类的方法之super()的用法和作用?
1、例如父类名称发生变更
2、不用再写父类名称
3、不用再写self
举例如下class Vehicle: #1、定义交通工具类
Courty = "China" #7、定义数据属性
def __init__(self,name,speed,load,power): #2、初始化函数、名字name、速度speed、容量load、能源power
self.name = name #3、name参数传给实例
self.speed = speed #4、speed参数传给实例
self.load = load #5、load参数传给实例
self.power = power #6、power参数传给实例
def run(self): #8、定义函数属性
print("开动啦")
class Subway(Vehicle): #9、定义地铁类并传入父类交通工具
def __init__(self,name,speed,load,power,line): #10、在子类中重新写下构造方法
super().__init__(name,speed,load,power) #11、运行super()函数调用__init__方法,通过super就可以调到父类的构造方法
self.line = line
def show_info(self): #12、定义展示信息的函数属性
print(self.name,self.speed,self.load,self.power,self.line) #13、输出打印
def subrun(self): #14、定义运行的函数属性
super().run()
print("%s %s 号线地铁开动了" %(self.name,self.line))
s1 = Subway("北京","10km/s",10000000000000000,"电",13) #15、生成实例
s1.show_info() #16、运行展示实例
s1.subrun() #17、
二十二、多态:由不同的类实例化得到的不同对象,调用同一个方法,执行的逻辑不同,得到的结果也不同。
class H2o: #1、定义水的类
def __init__(self,name,temperature): #2、初始化构造函数传入参数name和temperature温度参数
self.name = name
self.temperature = temperature
def turn_ice(self): #3、定义运行逻辑函数
if self.temperature < 0: #4、if判断温度小于的情况下
print("[%s]温度太低结冰了" %self.name)
elif self.temperature > 0 and self.temperature < 100: #5、判断温度居于中间
print("[%s]液化成水" %self.name)
elif self.temperature > 100: #6、判断温度大于100
print("[%s]温度太高变成了水蒸气" %self.name)
class Ice(H2o): #7、定义冰的类
pass
class Water(H2o): #8、定义水的类
pass
class Steam(H2o): #9、定义水蒸气的类
pass
i1 = Ice("冰",-25) #10、生成冰的实例
w1 = Water("水",20) #11、生成水的实例
s1 = Steam("水蒸气",200) #12、生成水蒸气的实例
def func(obj): #13、定义传入对象的函数
obj.turn_ice()
func(i1) #14、运行冰的结果
func(w1) #15、运行水的结果
func(s1) #16、运行水蒸气的结果
二十三、封装代表隐藏,通过遵循一定的数据属性和函数属性的命名约定来达到封的效果。
1、任何以单下划线开头的名字都应该是内部的,私有的。
2、可以隐藏数据属性和函数属性。
3、以单下划线开头的都是被隐藏起来的外部不可以使用。
4、内部指的是类里面的,外部指的是被外部调用者来说。
5、封装的本质是要明确区的分内外。
6、双下划线开头的类里面的属性Python会自动单下划线加类名加双下滑线属性名(例如类名是People,数据属性名是__star,Python的内部实现是_People__star)
7、非公共名称以单下划线开头,如果代码会涉及到子类,并且有些内部属性应该在子类中隐藏起来才考虑用双下滑线,无论是单下划线还是双下划线都没有从根本上限制访问。
8、外部访问的时候可以通过曲线救国的方式调用类里面的函数属性,然后类里面的函数属性去访问双下划线开头的数据属性。
举例如下
源码如下:
class People: #1、定义人的类
_star = "earth" #2、定义数据属性来自的星球是地球
def __init__(self,id,name,age,salary): #3、定义初始化函数身份证号id、名字name、年龄age、收入salary
self.id = id
self.name = name
self.age = age
self.salary = salary
def get_id(self): #4、定义获取ID的函数
print("我是私有方法,我找到的ID是[%s]" %self.id)
p1 = People("1323123","zd","25",8000) #5、生成实例
p1.get_id() #6、生成实例后执行类里面的get_方法
外部调用内部的函数属性,然后内部的函数方法调用内部双下划线开头的数据属性举例如下?
class People: #1、定义人的类
__star = "earth" #2、定义数据属性来自的星球是地球
def __init__(self,id,name,age,salary): #3、定义初始化函数身份证号id、名字name、年龄age、收入salary
print("--------->",self.__star) #7、用实例化后去访问双下滑线开头的
self.id = id
self.name = name
self.age = age
self.salary = salary
def get_id(self): #4、定义获取ID的函数
print("我是私有方法,我找到的ID是[%s]" %self.id)
def get_star(self): #8、定义访问函数/接口函数
print(self.__star) #9、获取内部的数据属性
p1 = People("1323123","zd","25",8000) #5、生成实例
p1.get_id() #6、生成实例后执行类里面的get_方法
p1.get_star()
二十四、反射/自省指的是程序可以访问、检测和修改它本身状态或行为的一种能力。
1、可以事先定义接口,接口只有在被完成后才会真正执行,
2、可插拔式设计
hasattr(object,name)指的是判断object中有没有一个name字符串对应的方法或属性
举例如下:
class BlackMedium: #1、定义黑中介类
feture = "Ugly" #2、定义数据属性特征feture、颜色是ugly黑色的
def __init__(self,name,addr): #3、初始化函数名字参数name、地址addr
self.name = name
self.addr = addr
def sell_hourse(self): #4、定义正在卖房子函数属性
print("【%s】 正在卖房子,傻子才买的" %self.name)
def rent_hourse(self): #5、定义正在租房子函数属性
print("【%s】 正在租房子,傻子才租呢" %self.name)
b1 = BlackMedium("万成置地","天露园") #6、生成实例
print(hasattr(b1,"name")) #7、判断字符串name是否在生成的实例里面
print(hasattr(b1,"sell_hourse"))#8、判断函数属性是否在实例里面
getattr(object,name,default = None指的是获取对象里面的字符串值
举例如下:
class BlackMedium: #1、定义黑中介类
feture = "Ugly" #2、定义数据属性特征feture、颜色是ugly黑色的
def __init__(self,name,addr): #3、初始化函数名字参数name、地址addr
self.name = name
self.addr = addr
def sell_hourse(self): #4、定义正在卖房子函数属性
print("【%s】 正在卖房子,傻子才买的" %self.name)
def rent_hourse(self): #5、定义正在租房子函数属性
print("【%s】 正在租房子,傻子才租呢" %self.name)
b1 = BlackMedium("万成置地","天露园") #6、生成实例
print(getattr(b1,"rent_hourse")) #11、判断接收到的是一个内存地址
func = getattr(b1,"rent_hourse") #9、获取实例里面租房子的函数属性
func() #10、获取后并运行
setattr(x,y,z)指的是往实例里面设置
举例如下:
class BlackMedium: #1、定义黑中介类
feture = "Ugly" #2、定义数据属性特征feture、颜色是ugly黑色的
def __init__(self,name,addr): #3、初始化函数名字参数name、地址addr
self.name = name
self.addr = addr
def sell_hourse(self): #4、定义正在卖房子函数属性
print("【%s】 正在卖房子,傻子才买的" %self.name)
def rent_hourse(self): #5、定义正在租房子函数属性
print("【%s】 正在租房子,傻子才租呢" %self.name)
b1 = BlackMedium("万成置地","天露园") #6、生成实例
setattr(b1,"zd","True") #12、往实例里面设置
print(b1.__dict__)
delattr(x,y)指的是删除实例里面的值
举例如下:
class BlackMedium: #1、定义黑中介类
feture = "Ugly" #2、定义数据属性特征feture、颜色是ugly黑色的
def __init__(self,name,addr): #3、初始化函数名字参数name、地址addr
self.name = name
self.addr = addr
def sell_hourse(self): #4、定义正在卖房子函数属性
print("【%s】 正在卖房子,傻子才买的" %self.name)
def rent_hourse(self): #5、定义正在租房子函数属性
print("【%s】 正在租房子,傻子才租呢" %self.name)
b1 = BlackMedium("万成置地","天露园") #6、生成实例
delattr(b1,"zd") #13、删除实例里面的zd
print(b1.__dict__)
hasattr和getattr的运用举例如下?
class FtpClient: #1、定义客户端类
def __init__(self,addr): #2、定义初始化函数
print("正在连接服务器[%s]" %addr)
self.addr = addr
def get(self): #6、定义get函数属性
print("已经成功登陆")
f1 = FtpClient("192.168.1.1") #3、生成实例
if hasattr(f1,"get"): #4、if判断
func_get = getattr(f1,"get") #7、得到内存地址
func_get() #8、得到后的内存地址加括号运行下
else: #5、否则结果
print("---->不存在此方法")
print("处理其他的逻辑")
反射的动态导入模块功能之importlib模块?
类的内置__setattr__属性作用是设定数据属性和函数属性,举例如下
class Foo: #1、定义foo类
x = 1 #2、定义数据属性
def __init__(self,y): #3、定义初始化函数
self.y = y
def __setattr__(self, key, value): #4、定义类的内置__setattr__属性作用是设定数据属性和函数属性
print("__setattr__执行")
self.__dict__[key] = value #6、设置到实例里面key等于value
def xcd(self):
print("xcvxvcx")
f1 = Foo(10) #5、生成实例
print(f1.__dict__) #7、打印实例里面的字典属性
f1.z = 2 #8、往实例里面增加键值对
print(f1.__dict__) #9、打印
类的内置__delattr__属性作用是删除类里面的数据属性和函数属性,举例如下
class Foo: #1、定义foo类
x = 1 #2、定义数据属性
def __init__(self,y): #3、定义初始化函数
self.y = y
def __delattr__(self, item): #4、定义类的内置__delattr__属性作用是删除类里面的数据属性和函数属性
print("删除__delattr__")
def xcd(self):
print("xcvxvcx")
f1 = Foo(10) #5、生成实例
del f1.y
del f1.x #6、删除数据属性
del f1.xcd #7、删除函数属性
类的内置__getattr__属性作用是外部调用一个对象的属性不存在时就触发下面的程序,举例如下
class Foo: #1、定义foo类
x = 1 #2、定义数据属性
def __init__(self,y): #3、定义初始化函数
self.y = y
def __getattr__(self, item): #4、定义类的内置__getattr__属性作用是外部调用一个对象的属性不存在时就触发下面的程序
print("执行__getattr__")
def xcd(self):
print("xcvxvcx")
f1 = Foo(10) #5、生成实例
print(f1.y) #6、调用数据属性
print(getattr(f1,"y")) #7、获取实例里面字符串y的值
f1.ssssssssssssssssss #8、调用内部不存在的函数
继承的方式完成包装定制自己的数据类型:
1、可以自定义控制属性的增加删除
举例如下:
class Foo: #1、定义foo类
def __init__(self,name): #2、初始化构造函数
self.name = name
def __getattr__(self, item): #4、自定义找不到的逻辑函数
print("你找的属性【%s】不存在" %item)
def __setattr__(self, k, v): #7、设置__setattr__函数属性作用是自定义改变系统自带设置的属性
print("执行setattr",k,v)
if type(v) is str: #9、if判断字符串类型
print("开始设置")
self.__dict__[k] = v.upper() #10、改变系统内置的键值对设置
else:
print("必须是字符串类型")
def __delattr__(self, item): #11、设置删除的函数属性
print("执行delattr",item)
f1 = Foo("zd") #3、生成实例
# f1.age = 25
# print(f1.__dict__) #8、查看实例的字典属性
# print(f1.name) #5、找数据属性name
# print(f1.age) #6、找数据属性age会触发__getattr__方法
del f1.name
二次加工标准类型(包装):Python提供了标准数据类型以及丰富的内置方法,但是在很多场景下都需要基于标准数据类型定制自己的数据类型新增或改写
授权是包装的一个特性,包装一个类型通常是对已存在的类型的一些定制,这种做法可以新建,修改或删除原有产品的功能,其他的则保持原样。授权的过程即是所有更新的功能都是由新类的某部分来处理,
但已存在的功能就授权给对象的默认属性。
1、实现授权的关键点就是覆盖__getattr__方法
组合的方式完成授权:
举例如下:
import time
class FileHandle: #1、定义打开文件类
def __init__(self,filename,mode = "r",encoding = "utf-8"): #2、定义初始化函数、参数filename文件名、读取方式mode、编码encoding
self.file = open(filename,mode = "r",encoding = encoding) #4、定义实例文件的描述符是打开后的文件名字、读取方式、默认的编码
self.mode = mode
self.encoding = encoding
def write(self,line):
print("-------------",line)
t = time.strftime("%Y-%m-%d %X") #15、打印当前时间
self.file.write("%s %s ",line)
def __getattr__(self, item): #3、定义控制外部调用不到后的解决办法
return getattr(self.file,item) #7、返回getattr方法里面字符串的read代表的
f1 = FileHandle("a.txt","w+") #5、生成实例的打开文件、w的意思是写读
# print(f1.file) #打开实例获取到文件的描述符
# f1.read #6、调用实例里面读的函数属性找不到的话会触发后端__getattr__方法
# print(f1.__dict__) #11、查看实例里面的字典属性有哪些
# print("-----",f1.read) #8、获取实例里面读
# sys_f = open("b.txt","w+") #9、打开新的文件
# print("=====",getattr(sys_f,"read")) #10、用getattr方法找到sys_f对象里面的read方法
# print("//////////////////",f1.write) #12、查看实例里面写的回调的方法
f1.write("111111111\n") #13、往a.qtxt文件里面写入1111111111111并换行
f1.seek(0) #14、
print("--------->",f1.read())
二十五:isinstance判断一个对象是否是一个类的实例
class Foo: #1、定义foo类
pass
f1 = Foo() #2、进行f1实例化得到f1对象
print(isinstance(f1,Foo)) #3、判断对象f1是否是类foo的实例,第一个参数是对象名,第二个参数是类名
二十六:issubclass判断是否子类
class Foo: #1、定义Foo类
pass
class Bar(Foo): #2、定义Bar类继承Foo类
pass
print(issubclass(Bar,Foo)) #3、判断Bar类是否是Foo的子类,第一个参数是子类名,第二个参数是父类名
二十七:__getattr__外部找不到类里面的数据时触发这个方法
class Foo: #1、定义Foo类
def __init__(self,x): #2、初始化函数并传入第一个参数x
self.x = x
def __getattr__(self, item): #3、定义_getattr__属性如果找不到类里面的数据时执行
print("执行的是我")
f1 = Foo(10) #4、Foo类的实例化生成对象f1
print(f1.x) #5、打印f1对象里面的数据属性x
f1.xxxxxxxxxxxxxxxx #6、如果找不到的话触发__getattr__
二十八:__getattribute__有或没有都执行
class Foo: #1、定义Foo类
def __init__(self,x): #2、初始化函数并传入第一个参数x
self.x = x
def __getattr__(self, item): #3、定义_getattr__属性如果找不到类里面的数据时执行
print("执行的是getattr")
def __getattribute__(self, item): #7、定义_getattribute__如果有的话就执行
print("执行的是getattribute")
raise AttributeError("抛出异常了") # 8、定义raise抛出/升起调用系统里面AttributeError类并加括号调用,括号里面可以自定义提示,抛出后给了_getattr__
f1 = Foo(10) #4、Foo类的实例化生成对象f1
# print(f1.x) #5、打印f1对象里面的数据属性x
# f1.x
f1.xxxxxxxxxxxxxxxx #6、如果找不到的话触发__getattr__
二十九:__getitem__、__setitem__、__delitem__
class Foo: #1、定义Foo类
def __getitem__(self, item): #2、定义__getitem__
print("getitem",item)
return self.__dict__[item] #11、返回接收到的自己字典里面的key
def __setitem__(self, key, value): #3、定义__setitem__
print("setitem")
self.__dict__[key] = value #8、调用自己属性字典里面key等于value
def __delitem__(self, key): #4、定义__delitem__
print("delitem")
self.__dict__.pop(key) #10、删除自己字典里的key
f1 = Foo() #5、生成实例
print(f1.__dict__) #6、打印生成实例里面的字典属性
f1["name"] = "egon" #7、往实例里面增加字典属性触发__setitem__
f1["age"] = 18
print(f1.__dict__) #9、打印实例里面的字典属性
del f1.name #12、删除实例里面的键key=name
print(f1.__dict__) #13、打印删除后的实例里面的字典属性
print(f1.age)#14、调用实例里面的键
f1["age"] #15、调用实例里面的键
print("------",f1["age"]) #16、打印__getitem__返回的值
#17、点的方式操作属性跟attr的思路有关
#18、中括号的方式操作属性跟item相关
三十、__str__和__repr__
# l = list("hello") #1、定义list类产生的对象l
# print(l)
# file = open("test.txt","w") #4、定义打开文件
# print(file)
class Foo: #2、定义Foo类
def __init__(self,name,age): #7、定义初始化函数
self.name = name
self.age = age
def __str__(self): #5、定制__str__在类里面一些方法控制类实例化出的对象
return "名字是%s 年龄是%s" %(self.name,self.age) #6、定义此处必须return
def __repr__(self): #8、定义repr如果没有str的话就会执行repr
return "这是repr"
f1 = Foo("egon",18) #3、Foo类生成f1实例
print(f1)
#9、str和repr的返回值必须是字符串、否则抛出异常
三十一:自定制format方法
format_dict = { #8、定义format字典
"ymd":"{0.year} {0.mon} {0.day}",
"m-d-y":"{0.mon}-{0.day}-{0.year}",
"y:m:d":"{0.year}:{0.mon}:{0.day}"
}
class Date: #1、定义Date类
def __init__(self,year,mon,day): #2、初始化函数
self.year = year
self.mon = mon
self.day = day
def __format__(self, format_spec): #4、自定制__format__方法、默认参数自带format_spec
print("我执行了")
print("----------",format_spec) #9、根据上面字典里面的值取到格式
if not format_spec or format_spec not in format_dict:#11、加if判断format_spec如果不是空或者format_spec不在字典里面的话、format_spec自带布尔值
format_spec = "ymd" #12、传的参数format_spec等于ymd
fm = format_dict[format_spec] #10、根据字典里面的key取值
return fm.format(self) #6、返回年月日d1自己
d1 = Date(2016,12,26) #3、生成实例对象
format(d1) #5、format对象d1
print(format(d1,"ymd")) #7、打印format对象d1,参数是ymd的结果
print(format(d1,"y:m:d")) #13、打印format对象d1,参数是y:m:d的结果
print(format(d1,"m-d-y")) #14、打印format对象d1,参数是m-d-y的结果
print("这是没有的情况",format(d1,"cxzczxcxzc")) #15、打印format对象d1,参数不在字典里面的情况就是默认的
三十二:__slots__
1、是一个类变量、变量值可以是列表、元组、可迭代对象、字符串、
2、使用点访问属性本质是在访问类或对象的__dict__属性字典(类的字典是共享的作用是节省内存和优化策略、而每个实例是独立的)
3、字典会占用大量内存、如果有一个属性很少的类、但是有很多实例、为了节省内存可以使用__slots__取代实例的__dict__
4、由类产生的__slots__实例不再产生__dict__属性
class Foo: #1、定义Foo类
__slots__ = "name" #2、定义数据属性
f1 = Foo() #3、生成实例
f1.name = "egon" #4、实例里面增加键值对
print(f1.name) #5、查询键name对应的值value
print(f1.__slots__) #6、打印实例里面的__slots__
print(Foo.__slots__) #7、打印实例里面的__slots__
三十三:__doc__描述方法
class Foo: #1、定义Foo类
"我是描述信息"
pass
class Bar(Foo): #3、定义Bar子类继承父类Foo
pass
print(Bar.__doc__)
#2、属性无法被继承
三十四:__module__和__class__
1、__module__表示当前操作的对象在哪个模块?
2、__class__表示当前操作的对象的类是什么
三十五:__del__析构方法当对象在内存中被释放时,自动触发执行、
class Foo: #1、定义Foo类
def __init__(self,name): #2、初始化构造h函数
self.name = name
def __del__(self): #3、定义__del__方法
print("我执行了")
f1 = Foo("zd") #4、生成实例
del f1.name #5、删除实例里面的name后会垃圾回收就触发了__del__方法
print("-------------------")
三十六:__call__是一个对象后面加括号触发执行,原因是执行了类里面的__call__方法
class Foo: #1、定义Foo类
def __call__(self, *args, **kwargs): #2、定义__call__方法
print("实例执行啦 obj()")
f1 = Foo() #3、生成实例
f1() #4、对象执行
三十七:使用迭代器协议实现斐波那契数列
class Fib: #1、定义斐波类
def __init__(self): #2、定义初始化函数起始值
self._a = 1 #3、定义初始第一个值1
self._b = 1 #4、定义初始值1
def __iter__(self): #5、定义__iter__函数
return self
def __next__(self): #6、定义__next__函数
if self._a > 100: #11、加if判断
raise StopIteration("终止了") #12、抛出异常
self._a,self._b = self._b,self._a + self._b #7、分别定义两个数之和
return self._a #8、任意返回一个值就行
f1 = Fib() #9、生成实例
print(next(f1)) #10、执行__next__方法
print(next(f1))
print(next(f1))
print(next(f1))
print(next(f1))
print(next(f1))
print(next(f1))
for i in f1:
print(i)
三十八:描述符__get__、__set__、__delete__
class Foo: #1、定义Foo类
def __get__(self, instance, owner): #2、定义__get__方法函数
print("===>get方法")
def __set__(self, instance, value): #3、定义__set__方法函数
print("===>set方法")
def __delete__(self, instance): #4、定义__delete__方法函数
print("===>delete方法")
class Bar(): #5、定义Bar类
x = Foo() #6、定义描述符
def __init__(self,n): #7、初始化构造函数
self.x = n
b1 = Bar(10) #8、生成实例
# print(b1.__dict__) #9、打印实例触发__set__方法的结果
1、描述符本身应该定义成新式类、这个类至少要实现上述三个方法的一个、被代理的类也应该是新式类
2、描述符的作用是用来代理另外一个类的属性、必须把描述符定义成这个类的类属性、不能为定义到构造函数中(构造函数是实例的)
3、严格遵循优先级:类属性>数据描述符>实例属性>非数据描述符>找不到的属性触发__getattr__()
4、描述符可以实现大部分Python类特性中的底层魔法,包括@classmethod@staticmethd@propety和__slots__
5、描述符是很多高级库和框架的重要工具之一,通常是使用到装饰器或元类的大型框架中的一个组件
6、利用描述符原理完成一个自制@propety,实现延迟计算(本质就是把一个函数属性利用装饰器原理做成一个描述符,类的属性字典中函数名为key,value为描述符类产生的对象)
数据描述符:至少实现了__get__和__set__方法
非数据描述符:没有__set__方法
数据描述符和非数据描述符区别是优先级不同
Python是弱类型语言、参数的赋值没有类型限制、如何通过描述符机制实现类型限制功能?
class Typed: #7、定义描述符Typed
def __init__(self,key): #28、定义instance传的值的方法、参数key
self.key = key #29、把参数key传值给自己并定义成key
def __get__(self, instance, owner): #8、定义__get__方法调用
print("get方法") #9、打印出get方法
# print("instance参数【%s】" %instance) #10、打印instance实际就是p1对象、
# print("owner参数【%s】" %owner) #11、打印owner实际就是触发实例的拥有者
return instance.__dict___[self.key] #31、取出字典里面的值
def __set__(self, instance, value): #14、定义__set__方法调用
print("set方法") # 15、打印出get方法
# print("instance参数【%s】" % instance) # 16、打印instance实际就是p1对象、
# print("value参数【%s】" % value) # 17、打印value实际就是触发赋的值
print("===>",self) #26、打印描述符自己
if not isinstance(value,str): #31、加if判断
raise TabError("你传入的类型不是字符串") #32、加抛出异常
instance.__dict___[self.key] = value #27、设置instance字典值
def __delete__(self, instance): #18、定义__delete__方法
print("delete方法") #19、打印delete方法
# print("instance参数【%s】" %instance) #20、打印instance参数接收的值
instance.__dict___.pop(self.key) #32、删除字典里面的key
class People: #1、定义人的类
name = Typed("name") #6、定义描述符Typed代理属性name-------(注:严格遵循优先级:类属性>数据描述符至少实现__get__和__set__方法>实例属性>非数据描述符没有__set__方法>找不到的属性触发__getattr__())
# age = Typed("age") #30、定义描述符Typed代理属性age
def __init__(self,name,age,salary): #2、初始化构造函数传入三个参数姓名name、年龄age、薪水salary
self.name = name #3、把姓名name的参数传给实例自己并且再定义name、触发描述符里面的__set__方法、触发的是代理
self.age = age #4、把年龄age的参数传给实例自己再定义age
self.salary = salary #5、把薪水salary的参数传给实例自己再定义salary
p1 = People("alex",13,13.3) #12、定义类People生成对象p1
print(p1.__dict__)
# p1.name #13、p1对象调用字符串属性
# p1.name #21、p1对象调用字符串触发描述符里面的__get__方法
# print(p1.name) #24、打印对象p1的name结果触发__get__方法
# p1.name = "egon" #22、再次触发描述符里面的__set__方法
# print(p1.name) #25、打印对象p1的name结果触发__get__方法
# print(p1.__dict__) #23、打印对象p1、name被数据描述符代理了
利用描述符自定制property静态属性:
class Lazyproperty: #12、定义Lazyproperty描述符
def __init__(self,func): #13、初始化构造函数、参数是func
print("========>",func) #14、打印出下面area函数的内存地址
self.func = func #15、参数func传给自己并赋值给func
def __get__(self, instance, owner): #17、定义__get__方法数据描述符>下方的实例属性
print("get") #18、打印get
print(instance) #20、打印类本身
print(owner) #21、打印产生的类
res = self.func(instance) #22、运行函数加参数instance
return res #23、return返回结果
class Room: #1、定义room类
# area = Lazyproperty() #19、定义类属性
def __init__(self,name,width,length): #2、初始化构造函数出入参数名字name、宽度width、长度length
self.name = name #3、参数name传给自己并赋值name
self.width = width #4、参数width传给自己并赋值width
self.length = length #6、参数length传给自己并赋值length
@Lazyproperty #7、定义求面积的静态属性property、所有的@都是下面函数名=@后面的名字(下面函数名)
def area(self): #8、定义面积函数area
return self.width * self.length #9、返回面积宽度乘长度
def test(self): #24、定义test函数
print("------------")
r1 = Room("厕所",1,1) #10、生成r1对象
print(r1.area) #11、打印出厕所的面积
# print(r1.area.func(r1)) #16、运行厕所下面的func方法加括号运行加入参数r1实例自己
print(Room.__dict__) #25、打印类里面的字典属性
r1.test() #26、运行实例里面的test 函数
自定制property实现延迟计算功能?
1、装饰器本身就是函数
2、装饰器也可以是一个类
get、set、del集成?
class Foo: #1、定义Foo类
@property #2、定义系统内置的property描述符
def get_AAA(self): #3、定义get方法
print("get的时候运行")
def set_AAA(self): #4、定义set方法
print("set的时候运行")
def del_AAA(self): #5、定义del方法
print("del的时候运行")
AAA = property(get_AAA,set_AAA,del_AAA) #6、集成
三十九:上下文管理协议__enter__和__exit__方法:
class Foo: #1、定义Foo类
def __init__(self,name): #2、初始化构造函数、name是with可以传进来的字符串、文件编码
self.name = name
def __enter__(self): #3、声明__enter__方法
print("出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量")
return self #5、return self的意思就是__enter__返回的值赋值给了f
def __exit__(self, exc_type, exc_val, exc_tb): #5、声明__exit__方法
print("with中代码块执行完毕时执行我") #10、with里面执行完毕后执行这个__exit__
with Foo("a.txt") as f: #4、Open("a.txt")实例化得到一个对象赋值给f然后触发Foo类里面的__enter__方法
print(f) #6、打印下f看下情况就是Foo产生的对象
print(f.name)#7、调用下对象字符串属性name
print("=====>执行代码块") #8、执行一遍
print("=====>执行代码块") #9、再执行一遍
print("hello") #11、最后Open类里面的__exit__方法执行完毕后触发这行
1、为了让一个对象兼容with语句,必须在这个对象的类中声明__enter__和__exit__方法
四十:上下文管理协议__enter__和__exit__方法加参数exc_type, exc_val, exc_tb
class Foo: #1、定义Foo类
def __init__(self,name): #2、初始化构造函数、name是with可以传进来的字符串、文件编码
self.name = name
def __enter__(self): #3、声明__enter__方法
print("出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量")#6、打印
return self #7、return self的意思就是__enter__返回的值赋值给了f
def __exit__(self, exc_type, exc_val, exc_tb): #4、声明__exit__方法
print("with中代码块执行完毕时执行我") #13、with里面执行完毕后执行这个__exit__
print(exc_type) #14、打印异常类名
print(exc_val) #15、打印异常值
print(exc_tb) #16、打印异常提示信息
return True #17、定义返回异常提示里面的真值、假值不返回
with Foo("a.txt") as f: #5、Open("a.txt")实例化得到一个对象赋值给f然后触发Foo类里面的__enter__方法
print(f) #8、打印下f看下情况就是Foo产生的对象
print(dasdsadasdasdasdsad) #9、打印不存在的变量名直接出发__exit__
print(f.name)#10、调用下对象字符串属性name
print("=====>执行代码块") #11、执行一遍
print("=====>执行代码块") #12、再执行一遍
print("hello") #18、最后Open类里面的__exit__方法执行完毕后触发这行
总结1:with obj as f:
"代码块"
1、with obj ----》 触发obj.__enter__(),拿到返回值
2、as f----》 f = 返回值
3、with obj as f 执行的实际就是f = obj.__enter__()
4、执行代码块没有异常时整个代码块运行完毕后去触发__exit__、三个参数都为None、
有异常的情况下从异常出现的位置直接触发__exit__、如果__exit__的返回值为True、代表吞掉了异常、
如果__exit__的返回值不为True、代表吐出了异常、exit的运行完毕就代表了整个with语句的执行完毕。
使用with语句的好处是把代码块放入with中执行、with结束后、自动完成清理工作、无需手动干预、在需要管理一些资源比如文件、网络连接和锁的编程环境中、可以在__exit__中定制自动释放资源的机制,
四十一:异常的构成
Traceback (most recent call last): #Traceback 指的是追踪信息
File "C:/Users/zd/Desktop/python_s3/day10/3.py", line 3, in <module>
print(sadsads)
NameError: name 'sadsads' is not defined #NameError指的是异常类名、name sadsads is not defined指的是异常值
四十二:类的装饰器及应用控制参数传入的类型限制
class Typed: #1、定义Typed描述符
def __init__(self,key,expected_type): #2、初始化构造函数传入参数key、预期的类型参数是expected_type
self.key = key #3、参数key传给自己并赋值key
self.expected_type = expected_type #4、参数expected_type传给自己并赋值expected_type
def __get__(self, instance, owner): #5、定义__get__方法
print("get方法") #6、打印名称get方法
return instance.__dict__[self.key] #7、返回参数instance并传进去字典里面
def __set__(self, instance, value): #8、定义__set__方法
print("set方法") #9、打印名称set
if not instance(value,self.expected_type): #10、加if判断传进去的类型不是字符串
raise TypeError("%s 传进去的类型不是%s" %(self.key,self.expected_type)) #11、抛出异常传进去的类型不是字符串
instance.__dict__[self.key] = value #12、字典里面增加键值对
def __delete__(self, instance): #13、定义__delete__方法
print("delete方法") #14、打印__delete__方法
instance.__dict__.pop(self.key) #34、删除字典里面的键
def deco(**kwargs): #24、定义deco函数
def wrapper(obj): #25、定义内置函数wrapper
for key,val in kwargs.items(): #26、for循环键值对
print("====打印键值对信息",key,val) #33、打印键值对信息、把值变成描述符
setattr(obj,key,Typed(key,val)) #27、往元组里面增加键值对实际就是(people,name,str)并产生描述符
return obj #28、返回元组
return wrapper #29、返回wrapper函数
@deco(name= str) #30、定义装饰器deco传进去参数按键值对形式
class People: #15、定义People类
# name = Typed("name",int) #16、定义属性name让Typed代理并且传进去的name参数必须是整数
# name = Typed("name",int) #16、定义属性name让Typed代理并且传进去的name参数必须是整数
def __init__(self,name,age,salary,gender,height): #17、初始化构造函数、姓名参数name、年龄age、薪水salary、性别gender、兴趣height
self.name = name #18、参数name传给自己并赋值name
self.age = age #19、参数age传给自己并赋值age
self.salary = salary #20、参数salary传给自己并赋值给salary
# self.gender = gender #21、参数gender传给自己并赋值给gender
# self.height = height #22、参数height传给自己你并赋值给height
p1 = People("213",13,13.3,"x","y") #23、生成对象p1
# print(p1.__dict__) #31、打印对象p1的字典属性
print(People.__dict__) #32、打印类名里面的字典属性
四十三:元类
前引:
class Foo:
pass
f1 = Foo()#f1是通过Foo类实例化的对象
python中一切皆是对象、类本身也是一个对象、当使用关键字class的时候、Python解释器在加载class的时候就会创建一个对象、这里
的对象指的是类而非类的实例、f1是由Foo类产生的对象、而Foo本身也是对象、
定义:
元类是类的类、是类的模板、元类是用来控制如何创建类的、正如类是创建对象的模板一样、元类的实例为类、正如类的实例为对象、f1对象是Foo类的实例、Foo类
是type类的一个实例、type是Python的一个内建元类、用来直接控制生成类、Python中任何class定义的类其实都是type类实例化的对象
class Foo: #1、定义Foo类
pass
print(Foo) #2、打印Foo类的结果、FOO类是由type产生的
def __init__(self,name,age): #9、顶级初始化构造函数
self.name = name #10、定义name的参数传给自己并定义成name
self.age = age #11、定义age的参数传给自己并定义成age
def test(self): #12、定义test函数
print("---------------")
FFO = type("FFo",(object,),{"x":1,"__init__":__init__,"test":test}) #3、FFo类实例化传参数、第一个是类名字符串形式、继承的父类要写成元组的形式、默认是object、加逗号是元组的形式、类有属性、放在属性字典里面、定义数据属性x是1
print(FFO) #4、打印type类产生FFO类的结果
print(Foo.__dict__) #5、打印FOO的字典属性
print(FFO.__dict__) #6、打印FFO的字典属性
f1 = FFO("alex",18) #7、FFO产生实例
print(f1.name) #8、打印f1实例的数据属性
f1.test() #13、直接运行f1实例test函数
自定义元类:
class MyType(type): #4、自定制mytype元类
def __init__(self,a,b,c): #5、初始化构造函数、传入参数self代表实例自己、a代表类名字符串、b代表元组形式、c代表
print("元类的构造函数执行") #6、打印
print(a) #7、打印类名
print(b) #8、打印空元组
print(c) #9、打印字典的形式
class Foo(metaclass=MyType): #1、定义Foo类声明元类是mytype
def __init__(self,name): #2、初始化构造函数定义参数name
self.name = name #3、定义name参数传给自己并定义成name
实例调用方法和类调用方法的区别是:实例会自动传进去构造函数里面、类调用方法必须穿送相对应的参数。