类的方法
classmethod
一个类的绑定方法
classmethod是一个装饰器,可以装饰给类内部的方法,使该方法绑定给类使用
一般来说,要使用某个类的方法,需要先实例化一个对象再调用方法。而使用@classmethod,就可以不需要实例化,直接类名.方法名()来调用。
不需要self参数,但第一个参数需要是表示自身类的cls参数。
对象的绑定方法特殊之处:
由对象调用,会将对象当做第一个参数传给该方法
类的绑定方法特殊之处:
由类调用,会将类当做第一个参数传给该方法
class A(object):
bar = 1
def foo(self):
print ('foo')
@classmethod
def class_foo(cls): # cls是调用的类的本身
print('class_foo')
'''可以在方法中 cls.属性 cls是调用的类本身'''
print(cls.bar)
# cls() 调用类 .方法 使用
cls().foo()
###执行可以直接类名.方法没有实例化对象
A.class_foo()
'''
class_foo
1
foo
'''
课堂代码
import setting
class teacher:
def __init__(self,user,password):
self.user = user
self.pwd = password
def index(self):
# 判断传进来的类的user pwd是都相等
if self.user == 'aaa' and self.pwd == '123':
print('验证通过...')
@classmethod
def login_tell(cls):
'''将setting文件中的用户密码传入cls的类函数中,并得到返回值
cls() == teacher()'''
res = cls(setting.user,setting.pwd)
return res
'''返回得到的'''
'''res接受'''
res = teacher.login_tell()
'''使用res 调用index方法'''
res.index()
staticmethod
类的非绑定方法
是一个装饰器,可以装饰给类内部的方法,使该方法既不绑定给对象,也不绑定给类.
@staticmethod不需要表示自身对象的self和自身类的cls参数,就跟使用函数一样。
在@staticmethod中要调用到这个类的一些属性方法,只能直接类名.属性名或类名.方法名方式。
UUID模块
可以通过.uuid4
获取一个唯一的时间戳字符串
用法
@staticmethod
class teacher:
def creat_id():
# 生成特定的字符串id
uuid_s = uuid.uuid4()
md5 = hashlib.md5()
md5.update(str(uuid_s).encode('utf-8'))
return md5.hexdigest()
print(teacher.creat_id())
# 由类调用不需要传值
t = teacher('ntank','123')
print(t.creat_id())
# 由对象调用也不需要传值
面向对象高阶
isinstance(参数1,参数2)
python内置的函数,可以传入两个参数,用来判断参数1是否是参数2的一个实例
判断一个对象是否是一个类的实例
class Foo:
pass
class Goo(Foo):
pass
obj = Foo()
print(isinstance(Goo(),Foo))
print(isinstance(obj,Foo))
issubclass
python内置函数,可以传入两个参数,用来判断参数1是否是参数2的子类
判断一个类是否是另一个类的子类
class Foo:
pass
class Goo(Foo):
pass
class aa:
pass
print(issubclass(Goo,Foo)) # True
print(isinstance(Foo,Goo)) # False
print(isinstance(aa,Goo)) # False
反射
通过字符串
对对象或类的属性进行操作
'''反射本质就是在使用内置函数,其中反射有以下四个内置函数:'''
通过字符串
-hasattr: 判断该字符串是否是对象或类的属性
-getattr: 获取对象或类的属性
-setattr: 设置对象或类的属性
-delattr: 删除对象或类的属性
class People:
country = 'China'
def __init__(self,name,age):
self.name = name
self.age = name
hasattr
# hasattr 判断是否在
p = People('tank',18)
print (hasattr(p,'name')) # True
print (hasattr(p,'uzi')) # False
getattr
# getattr
print(getattr(p,'name')) # tank
print(getattr(p,'uzi')) # 'People' object has no attribute 'uzi'
setattr
# setattr
setattr(p,'level','SSS')
print(getattr(p,'level')) # SSS
delattr
# delattr
delattr(p,'level')
print (hasattr(p,'level')) # False
反射方法的练习,用户输入字符串反射至类中方法
class D:
def inpu(self):
print('请输入')
while True:
inp = input('请输入模块名').strip()
if hasattr(self,inp):
func = getattr(self,inp)
func()
break
else:
print('命令错误,请重新输入')
def p(self):
print('即将打印pppp')
def s(self):
print('即将打印sss')
d = D()
d.inpu()
魔法方法
凡是在类内部定义,以__开头,以__
结尾的方法都称之为魔法方法,又称'类的内置方法'
魔法方法会在某些条件成立时触发
'''__init__ : 在调用类时触发
__str__ : 会在打印对象时触发
__del__ :对象被销毁前执行该方法,且总是在最后被执行
__getattr__:会在对象.属性,''属性''没有的情况下才会触发
__setattr__:会在 ''对象.属性 = 属性值'' 时触发
__call__
__new__
'''
class Foo:
def __init__(self):
print('在调用类时触发')
def __str__(self):
print('会在打印对象时触发')
# 必须有一个返回值,该返回值必须是字符串类型
return '返回的值'
def __del__(self):
print('对象被销毁前执行该方法,且总是在最后被执行')
def
def __setattr__(self,key,val):
print('会在 ''对象.属性 = 属性值'' 时触发')
f = Foo()
1.__init__
对象实例化的时候自动触发
2.__str__
class Foo:
def __init__(self,name,age):
'''实例化时自动触发'''
self.name = name
self.age = age
def __str__(self):
# print('打印时自动触发,不需要print即可打印')
return f'{self.name}:{self.age}'# return出的就是最后打印的值.可以随意返回
# 如果不返回字符串类型,则会报错
obj = Foo('nick',18)
print(obj) # obj.__str__() # 打印的时候就是在打印返回值
3.__del__
'''__del__,对象被销毁时执行,且总会在最后被执行'''
class AA:
def __del__(self):
print('对象被销毁前执行该方法,且总是在最后被执行')
4.__getattr__
默认返回none,可以return
任何值
'''__getattr__ 会在对象.属性时,'属性没有'的情况下才会触发'''
class aaa:
def __getattr__(self,item):
print('对象.属性,属性没有的时候触发')
print(item) # item就是没有的属性
a = aaa()
a.x # 类中没有x属性,但会在__getattr__被触发打印
'''
对象.属性,属性没有的时候触发
x
'''
5.__setattr__
添加/修改属性会触发他的执行
'''会在'对象.属性 = 属性值'时来触发'''
class aaa:
def __setattr__(self, key, value):
print('会在对象.属性 = 属性值时触发,赋值时')
print(key, value) # 就是赋值的属性值
a = aaa()
a.i=10
# 会在对象.属性 = 属性值时触发,赋值时
# i 10
6.__call
__
会在调用对象时触发
class aaa:
def __call__(self, *args, **kwargs):
print(self) # <__main__.aaa object at 0x0000016E0D605940>
print('在调用对象时触发该方法...') # 在调用对象时触发该方法...
a = aaa()
a() # 对象加()调用
7.__new__
#__new__是在实例创建之前被调用的,因为它的任务就是创建实例然后返回该实例,是个静态方法。
#__new__在__init__之前被调用,__new__的返回值(实例)将传递给__init__方法的第一个参数,然后__init__给这个实例设置一些参数
相当于要做三件事,
1.调用`__new__`创建对象,然后找一个变量来接受`__new__`的返回值,这个返回值表示创建出来的对象的引用
2.`__init__`(刚刚创建出来的对象的应用)
3.返回对象的引用
总结:
__new__至少要有一个参数cls,代表要实例化的类,此参数在实例化时由Python解释器自动提供
__new__必须要有返回值,返回实例化出来的实例,这点在自己实现__new__时要特别注意,可以return父类__new__出来的实例,或者直接是object的__new__出来的实例
__init__有一个参数self,就是这个__new__返回的实例,__init__在__new__的基础上可以完成一些其它初始化的动作,__init__不需要返回值
我们可以将类比作制造商,__new__方法就是前期的原材料购买环节,__init__方法就是在有原材料的基础上,加工,初始化商品环节
魔法方法的应用
__del__
class MyFile:
def __init__(self,file_name,mode = 'r',encoding = 'utf-8'):
self.file_name = file_name
self.mode = mode
self.encoding = encoding
def file_open(self):
self.f = open(self.file_name,self.mode,encoding= self.encoding)
def read_file(self):
res = self.f.read()
print(f'''
当前文本名是
{self.file_name}
文本内容为
{res}
''')
def __del__(self):
self.f.close()
print('文件关闭成功')
f = MyFile('1.txt')
f.file_open()
f.read_file()
print('文件销毁')
单例模式
1.定义
单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在。当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场。
实例化多个对象,会产生不同的内存地址,单例可以让所有调用者,在调用类产生对象的情况下都执行同一份内存地址.例如打开文件的操作
比如,某个服务器程序的配置信息存放在一个文件中,客户端通过一个 AppConfig 的类来读取配置文件的信息。如果在程序运行期间,有很多地方都需要使用配置文件的内容,也就是说,很多地方都需要创建 AppConfig 对象的实例,这就导致系统中存在多个 AppConfig 的实例对象,而这样会严重浪费内存资源,尤其是在配置文件内容很多的情况下。事实上,类似 AppConfig 这样的类,我们希望在程序运行期间只存在一个实例对象。
2.单例的目的:
减少内存的占用
3.实现单例模式
意图:保证一个类仅有一个实例,并提供一个访问它的全局访问点。
主要解决:一个全局使用的类频繁地创建与销毁。
何时使用:当您想控制实例数目,节省系统资源的时候。
如何解决:判断系统是否已经有这个单例,如果有则返回,如果没有则创建。
关键代码:构造函数是私有的。
- 使用模块
- 使用
__new__
- 使用装饰器
- 使用元类
1.使用模块
python模块就是天然的单例模式,因为模块在第一次导入时,会生成 .pyc
文件,当第二次导入时,就会直接加载 .pyc
文件,而不会再次执行模块代码。因此,我们只需把相关的函数和数据定义在一个模块中,就可以获得一个单例对象了。
# mysingleton.py
class My_Singleton(object):
def foo(self):
pass
my_singleton = My_Singleton()
将上面的代码保存在文件 mysingleton.py
中,然后这样使用:
from mysingleton import my_singleton
my_singleton.foo()
2.使用__new__
知识点:
1> 一个对象的实例化过程是先执行类的`__new__方法`,如果我们没有写,默认会调用object的`__new__`方法,返回一个实例化对象,然后再调用`__init__方法`,对这个对象进行初始化,我们可以根据这个实现单例.
2> 在一个类的`__new__方法中`先判断是不是存在实例,如果存在实例,就直接返回,如果不存在实例就创建.
重写 __new__ 方法 一定要 return super().__new__(cls)* 否则 Python 的解释器 得不到 分配了空间的 对象引用,就不会调用对象的初始化方法
注意:__new__ 是一个静态方法,在调用时需要 主动传递 cls 参数
为了使类只能出现一个实例,我们可以使用__new__
来控制实例的创建
我们将类的实例和一个类变量 _instance
关联起来,如果 cls._instance
为 None 则创建实例,否则直接返回 cls._instance
。
class Singleton(object):
_instance = None
def __new__(cls, *args, **kw):
if not cls._instance:
cls._instance = super(Singleton, cls).__new__(cls, *args, **kw)
return cls._instance
class MyClass(Singleton):
a = 1
3.使用装饰器
装饰器可以动态的修改一个类或函数的功能, 在此,使用装饰器来装饰某个类,使其只能生成一个实例
装饰器里面的外层变量定义一个字典,里面存放这个类的实例.当第一次创建的时候,就将这个实例保存到这个字典中.
然后以后每次创建对象的时候,都去这个字典中判断一下,如果已经被实例化,就直接取这个实例对象.如果不存在就保存到字典中.
__author__ = 'Fioman'
__time__ = '2019/3/6 10:22'
def singleton(cls):
# 单下划线的作用是这个变量只能在当前模块里访问,仅仅是一种提示作用
# 创建一个字典用来保存类的实例对象
_instance = {}
def _singleton(*args, **kwargs):
# 先判断这个类有没有对象
if cls not in _instance:
_instance[cls] = cls(*args, **kwargs) # 创建一个对象,并保存到字典当中
# 将实例对象返回
return _instance[cls]
return _singleton
@singleton
class A(object):
a = 1
def __init__(self, x=0):
self.x = x
print('这是A的类的初始化方法')
a1 = A(2)
a2 = A(3)
print(id(a1), id(a2))
换个思路
from functools import wraps
def singleton(cls):
instances = {}
@wraps(cls)
def getinstance(*args, **kw):
if cls not in instances:
instances[cls] = cls(*args, **kw)
return instances[cls]
return getinstance
@singleton
class MyClass(object):
a = 1
在上面,我们定义了一个装饰器 singleton
,它返回了一个内部函数 getinstance
,该函数会判断某个类是否在字典 instances
中,如果不存在,则会将 cls
作为 key,cls(*args, **kw)
作为 value 存到 instances
中,否则,直接返回 instances[cls]
。
4.使用metaclass
元类可以控制类的创建过程,他主要做三件事:
- 拦截类的创建
- 修改类的定义
- 返回修改后的类
使用元类实现单例模式的代码如下
class Singleton(type):
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
return cls._instances[cls]
class MyClass(metaclass=Singleton):
pass
总结
Python 的模块是天然的单例模式,这在大部分情况下应该是够用的,当然,我们也可以使用装饰器、元类等方法