1012 笔记

类的方法

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 的模块是天然的单例模式,这在大部分情况下应该是够用的,当然,我们也可以使用装饰器、元类等方法

原文地址:https://www.cnblogs.com/fwzzz/p/11668335.html