面向对象的魔法方法
class C1:
name = '张三丰'
age = 18
def __init__(self, name):
# 对象添加数据或改变数据时自动触发
print('__init__')
def __str__(self):
print('__str__')
return f'{self.name}'
# 当对象被执行打印操作时执行,并必须要有返回值
def __call__(self, *args, **kwargs):
print('__call__')
return f'{self.name}'
# 当对象加括号调用的时候会自动触发
def __getattr__(self, item):
print(f'{item},不存在')
# 对象在调用没有的数据值时会自动触发
# def __getattribute__(self, item):
# print('__getattribute__')
# # 当对象获取数据的时候自动触发
# # 缺点 即使 对象有该数据 也无法拿到
def __setattr__(self, key, value):
print('__setattr__')
# 当对象 添加值 或者更改值的时候都会自动触发
# obj.name = '111' 当有对象名称赋值时就会触发
def __enter__(self):
print('__enter__')
# 当对象跟with语法一起使用时 会自动触发,并且该方法返回什么,as后面就可以接收到什么
return '333'
def __exit__(self, exc_type, exc_val, exc_tb):
print('__exit__')
# 当对象参与with语法结束后 自动触发
ojb1 = C1('moon')
with ojb1 as f:
print(f)
'''
ojb1 = C1('moon')
# 给对象添加或更改 独有的数据时,会自动执行__init__里面的代码
print(ojb1)
# 当执行打印对象的操作时,会自动触发__str__函数
a1 = ojb1()
# 对象加括号为自动触发_call__里面的代码,如果有返回值,则可以用变量接收
print(a1)
# a1 接收到了__call__返回的值
# ojb1.hhh
# 当对象.一个不存在的名字是 自动触发 __getattr__函数
ojb1.age = '周芷若'
# 有赋值符号时 触发 __setattr__函数
'''
魔法方法小练习
# 补全下列代码使的运行不报错
# class Context:
# pass
# with Context() as f:
# f.do_something()
# 当对象遇到with方法是需要用到__enter__和__exit__才可以
class Context:
def do_something(self):
print('123')
def __enter__(self):
return self
#需要返回给 f 赋值
def __exit__(self, exc_type, exc_val, exc_tb):
pass
with Context() as f:
f.do_something()
# f 是什么 f是 __enter__返回的内容
# 对象调用一个方法,对象本身没有 就需要产生对象的类中有
2.自定义字典类型并让字典能够通过句点符的方式操作键值对
class Mydict(dict):
def __setattr__(self, key, value):
# 当使用 obj.name = 'moon' 语法时自动触发
self[key] = value
# 给对象添加 键值对
def __getattr__(self, item):
# 当使用 obj.name 语法时触发,因为对象是自动,没有自己的名称空间所以你.什么都会触发这个
return self.get(item)
# 手动 获取 字典内的 值
obj = Mydict()
obj.name = 'moon'
obj.age = 17
print(obj)
print(obj.name)
'''
思路:首先想到要用类去继承这个字典,然后添加额外的操作
'''
元类简介
''' 推导步骤1:如何查看数据的数据类型 '''
# s1 = 'hello world' # str()
# l1 = [11, 22, 33, 44] # list()
# d1 = {'name': 'jason', 'pwd': 123} # dict()
# t1 = (11, 22, 33, 44) # tuple()
# print(type(s1)) # <class 'str'>
# print(type(l1)) # <class 'list'>
# print(type(d1)) # <class 'dict'>
# print(type(t1)) # <class 'tuple'>
"""推导步骤2:其实type方法是用来查看产生对象的类名"""
# class Student:
# pass
# obj = Student()
# print(type(obj)) # <class '__main__.Student'>
"""推导步骤3:python中一切皆对象 我们好奇type查看类名显示的是什么"""
class Student:
pass
obj = Student()
print(type(obj)) # <class '__main__.Student'>
print(type(Student)) # <class 'type'>
class A:pass
class B:pass
print(type(A), type(B))
"""结论:我们定义的类其实都是由type类产生的>>>:元类(产生类的类)"""
产生类的两种方式
1. 关键词 class 创建
class C1:
name = 'moon'
2. 利用元类 type 来创建类
type(类名,(是否有父类),{名称空间})
type('C1',(),{'name':'moon'})
a1 = C1()
# 生成一个对象
a2 = type('C1',(),{'name':'moon'})()
# 也是生成一个对象
print(a1.name)
print(a2.name)
print(type(a1)) # <class '__main__.C1'>
print(type(a2)) # <class '__main__.C1'>
# 类型也都是一样的
'''
所以得出结论,利用class 创建 类 或者 type(类名,(是否有父类),{名称空间})
都是一样的 2种创建类的方法
'''
元类定制类的方法
1.首先我们得到 类是由元类 产生的, 元类是 type
2.如果我们想控制类的产生,那就要想办法 重新 产生类的过程
3.类是通过元类里面的__init__方法产生的
4.那么我们只需要改变元类的这个方法就可以了
class Mytype(type):
# 重新定义一个元类
def __init__(self, what, bases=None, dict=None):
# 重新__init__方法,添加需求,当what参数满足要求后,才执行__init__
if not what.istitle():
raise TypeError('命名错误,首字母需要大写')
super().__init__(what, bases, dict)
class V1(metaclass=Mytype):
# 用关键词 metaclass= 来更改产生类的元类
pass
'''
这样就达到了我们的需求
元类定制类的方法:就是重写元类中产生类的方法,然后增加控制
在创建新的类时,更改类的元类
'''
元类定制对象的方法
"""
推导
对象加括号会执行产生该对象类里面的 __call__
类加括号会执行产生该类的类里面的 __call__
"""
"""给对象添加独有数据的时候 必须采用关键字参数传参"""
class Mytype(type):
def __call__(self, *args, **kwargs):
# 通过__call__方法来生成对象的,所以重写此方法
# 1.产生一个空对象(骨架)
# 2.调用__init__给对象添加独有的数据(血肉)
# 3.返回创建好的对象
# print(args) # ('jason', 18, 'male')
# print(kwargs) # {}
if args:
raise TypeError('必须按照关键词传参')
return super().__call__(*args, **kwargs)
# 通过条件后,在原封不动的调用__call__方法
class C1(metaclass=Mytype):
def __init__(self,name,age):
self.name = name
self.age = age
res = C1(name = 'moon',age = 18)
# 这里的数据 是先交给了元类里面的__call__执行了一遍,才能到__init__
魔法方法之双下new
class Mytype(type):
def __call__(self, *args, **kwargs):
res = self.__new__(self)
# __call__方法是创建对象的
# __new__产生一个空对象
self.__init__(res, *args, **kwargs)
# 调用__init__给空对象添加独有属性
return res
# 然后把这个对象返还 这就是产生对象的流程
class C1(metaclass=Mytype):
def __init__(self,name,age):
# __init__只是定义对象独有数据,并不产生对象
self.name = name
self.age = age
res = C1('moon', 18)
print(res.age)
# 这里的数据 是先交给了元类里面的__call__执行了一遍,才能到__init__
设计模式简介
1.设计模式
前人通过大量的验证创建出来解决一些问题的固定高效方法
2.IT行业
23种
创建型
结构型
行为型
ps:课下感兴趣可以简单看看
3.单例模式
类加括号无论执行多少次永远只会产生一个对象
目的:
当类中有很多非常强大的方法 我们在程序中很多地方都需要使用
如果不做单例 会产生很多无用的对象浪费存储空间
我们想着使用单例模式 整个程序就用一个对象
标签:__,name,对象,self,魔法,元类,面向对象,print,type
From: https://www.cnblogs.com/moongodnnn/p/16870991.html