python 元类以及练习

时间:2022-06-15 21:40:34
'''
# 知识储备exec()
# 参数1:字符串形式的命令
# 参数2:全局作用域(字典形式),如果不指定默认就使用globals()
# 参数3:局部作用域(字典形式),如果不指定默认就使用locals()
'''
# g = {
# 'x': 2,
# 'y': 4
# }
# l = {}
# exec('''
# global x, m
# x = 10
# m = 100
#
# z = 3
# ''', g, l)
# print(g)
# print(l)
'''一切皆对象,元类(产生类的类叫元类,默认用class定义的类,他们的元类是type)'''
# 一切皆对象,对象可以怎么用?
# 1.都可以被引用,x = obj
# 2.都可以当做函数的参数传入
# 3.都可以当作函数的返回值
# 4.都可以当做容器类型的元素,l = [func, time, obj, l] # # 类也是对象,Foo = type(...)
# class Foo:
# pass
# obj = Foo()
# print(type(obj))
# print(type(Foo))
# #产生类的类叫元类,默认用class定义的类,他们的元类是type
'''定义类'''
# 方式一class
# class Chinese:
# country = 'china'
# def __init__(self, name):
# self.name = name
# def talk(self):
# print('%s is talking' % self.name)
# print(Chinese)
# 方式二type
#定义类三要素 类名,类的基类, 类的名称空间
# class_name = 'Chinese'
# class_bases = (object,)
# class_body = '''
# country = 'china'
# def __init__(self, name):
# self.name = name
# def talk(self):
# print('%s is talking' % self.name)
# '''
# class_dic = {}
# exec(class_body, globals(), class_dic)
# # print(class_dic)
#
# Chinese1 = type(class_name, class_bases, class_dic)
# print(Chinese1)
'''自定义元类控制类的创建'''
# class Mymeta(type):
# def __init__(self, class_name, class_bases, class_dic):
# if not class_name.istitle():
# raise TypeError('类名首字母必须大写')
# if '__doc__' not in class_dic or not class_dic['__doc__'].strip():
# raise TypeError('必须有注释,且注释不能为空')
# super(Mymeta, self).__init__(class_name, class_bases, class_dic)
# class Chinese(object, metaclass = Mymeta):
# '''
# 国人
# '''
# country = 'china'
# def __init__(self, name):
# self.name = name
# def talk(self):
# print('%s is talking' % self.name)
# c = Chinese('name')
# # Chinese = type(class_name, class_bases, class_dic)
'''知识储备__call__方法'''
# class Foo:
# def __call__(self, *args, **kwargs):
# print(self)
# print(args)
# print(kwargs)
# obj = Foo()
# obj(1, 2, 3, a=1, b=2, c=3) # 元类内部也应该有一个__call__方法,会在调用Foo时触发执行
'''自定义元类控制类的实例化行为'''
# class Mymeta(type):
# def __init__(self, class_name, class_bases, class_dic):
# if not class_name.istitle():
# raise TypeError('类名首字母必须大写')
# if '__doc__' not in class_dic or not class_dic['__doc__'].strip():
# raise TypeError('必须有注释,且注释不能为空')
# super(Mymeta, self).__init__(class_name, class_bases, class_dic)
# def __call__(self, *args, **kwargs):
# # print(self)
# # print(args)
# # print(kwargs)
# # 第一件事,造一个空对象
# obj = object.__new__(self)
# # 第二件事,初始化
# self.__init__(obj, *args, **kwargs)
# # 第三件事,返回obj
# return obj
# class Chinese(object, metaclass = Mymeta):
# '''
# 国人
# '''
# country = 'china'
# def __init__(self, name):
# self.name = name
# def talk(self):
# print('%s is talking' % self.name)
# obj = Chinese('xander') # Chinese.__call__(Chinese, 'xander')
# print(obj.__dict__)
'''自定义元类控制类的实例化行为的应用'''
# 单例模式 # 实现方式一:
# class MySQL:
# __instance = None
#
# def __init__(self):
# self.host = '127.0.0.1'
# self.port = 3306
# @classmethod
# def singleton(cls):
# if not cls.__instance:
# obj = cls()
# cls.__instance = obj
# return cls.__instance
# # obj1 = MySQL()
# # obj2 = MySQL()
# # print(obj1)
# # print(obj2)
# obj1 = MySQL.singleton()
# obj2 = MySQL.singleton()
# print(obj1 is obj2) # 实现方式二:元类的方式
class Mymeta(type):
def __init__(self, class_name, class_bases, class_dic):
if not class_name.istitle():
raise TypeError('类名首字母必须大写')
if '__doc__' not in class_dic or not class_dic['__doc__'].strip():
raise TypeError('必须有注释,且注释不能为空')
super(Mymeta, self).__init__(class_name, class_bases, class_dic)
self.__instance = None
def __call__(self, *args, **kwargs):
if not self.__instance:
obj = object.__new__(self)
self.__init__(obj)
self.__instance = obj
return self.__instance
class Mysql(object, metaclass=Mymeta):
'''单例模式'''
def __init__(self):
self.host = '127.0.0.1'
self.port = 3306
@classmethod
def singleton(cls):
if not cls.__instance:
obj = cls()
cls.__instance = obj
return cls.__instance
obj1 = Mysql()
obj2 = Mysql()
print(obj1 is obj2)

练习

# 练习一:在元类中控制把自定义类的数据属性都变成大写
class Mymate(type):
def __new__(cls, name, args, kwargs):
obj = {}
print(name)
print(args)
print(kwargs)
for a, b in kwargs.items():
if not a.startswith('__'):
obj[a.upper()] = b
else:
obj[a] = b
return type.__new__(cls, name, args, obj)
class Chinese(object, metaclass=Mymate):
country = 'chinese'
def talk(self):
print('is talking')
print(Chinese.__dict__) # 练习二:在元类中控制自定义的类无需init方法
# 1.元类帮其完成创建对象,以及初始化操作;
# 2.要求实例化时传参必须为关键字形式,否则抛出异常TypeError: must use keyword argument
# 3.key作为用户自定义类产生对象的属性,且所有属性变成大写
class Mymate(type):
def __call__(self, *args, **kwargs):
if args:
raise TypeError(':must use keyword argument')
obj = object.__new__(self) #创建对象,self为类Chinese for k, v in kwargs.items():
obj.__dict__[k.upper()] = v
return obj class Chinese(object, metaclass=Mymate):
country = 'chinese'
def talk(self):
print('is talking')
p = Chinese(name='egon', age=18, sex='male')
print(p.__dict__)