面向对象进阶

面向对象进阶

Wisdom is knowing what to do next , virtue is doing it .

classmethod 和 staticmethod

classmethod

装饰给类内部的方法,使该方法绑定给类使用。由类调用,将类作为第一个参数传入方法,不影响对象对该方法的调用。

class People:
    def __init__(self,name,age):
        self.name = name
        self.age = age
        print(self)

    @classmethod
    def tell_info(cls):
        print(cls)#这里只是说明这个方法已经绑定给了类,所以其参数是类
        print('此处是类方法。。。')

p = People('tank',18)
p.tell_info()
#<__main__.People object at 0x00000272647D8A20>
# <class '__main__.People'>
# 此处是类方法。。。

staticmethod

是一个装饰器,可以装饰给类内部的方法,使该方法不绑定给对象,也不绑定给类使其变成一个普通的函数,但是不改变其调用方式。(__class__对象的属性,获取当前对象的类)

小练习

1、定义MySQL类
1.对象有id、host、port三个属性
  

  2.定义工具create_id,在实例化时为每个对象随机生成id,保证id唯一
  
  3.提供两种实例化方式,方式一:用户传入host和port 方式二:从配置文件中读取host和port进行实例化

#下面代码仅给出了实例化的两种方式,和ID的产生
import hashlib,uuid,settings#settings为配置文件(配置文件其实就是一个自定义的模块)
class Teacher:
    def __init__(self,user,pwd):#通过对象的绑定方法产生一个对象(对象名 = 类(参数))
        self.user = user
        self.pwd = pwd

    def index(self):
        if self.user == 'tahk' and self.pwd == '123':
            print('验证通过,显示主页。。。')

    @classmethod
    def login_auth_from_settings(cls):#通过配置文件的方式产生一个对象(通过类的绑定方法产生一个对象)
        obj = cls(settings.USER,settings.PWD)
        return obj

    @staticmethod
    def create_id():
        uuid_obj = uuid.uuid4()
        md5 = hashlib.md5()
        md5.update(str(uuid_obj).encode('utf8'))
        return md5.hexdigest()

obj = Teacher.login_auth_from_settings()#通过配置文件产生对象需要单独调用实例化方法
obj.index()
tea1 = Teacher('tank', '123')
print(tea1.create_id())
tea1.index()
print(Teacher.create_id())

  

isinstance 和 issubclass

isinstance

isinstance******(参数1,参数2)返回bool值判断参数1(对象)是否是参数二(类)的实例。

issubclass

issubclass*****判断参数一(子类)是否是参数二(父类)的子类反射*******指通过字符串对对象或类的属性进行操作。

class Foo:
    pass

class Goo(Foo):
    pass


foo_obj = Foo()
print(isinstance(foo_obj, Foo))
print(isinstance(foo_obj, Goo))  # False
print(issubclass(Goo, Foo))  # True

反射

反射指通过字符串对对象或类的属性进行操作。

hasattr:通过判断该字符串是否是对象或类的属性。

getattr:通过字符串获取对象或类的属性。

setattr:通过字符串设置对象或类的属性,如果属性不存在会为对象添加属性。

delattr:通过字符串删除对象或类的属性。

class People:#创建一个类
    country = 'China'

    def __init__(self,name,age,sex):
        self.name = name
        self.age = age
        self.sex = sex

p = People('tank',17,'male')
#普通方式
print('name' in p.__dict__)#判断name是否是对象的属性值
#hasattr
print(hasattr(p,'name'))
print(hasattr(People,'country'))
#获取属性值
#普通方式
print(p.__dict__.get('name'))
#getattr
print(getattr(p,'name','jason_sb'))#如果有值则返回属性值,如果没有则返回最右侧的这个值
print(getattr(People,'country2','China'))
#为对象或类添加属性
#普通方式
p.level = 10
print(p.level)
#setattr
setattr(p,'sal','3.0')
print(hasattr(p,'sal'))
#删除对象的属性
#普通方式
del p.level
print(hasattr(p,'level'))
#delattr
delattr(p,'sal')
print(hasattr(p,'asl'))
print(p.__dict__.get('level'))

反射小练习:使用反射实现输入属性的名字就可以执行类或对象中的方法。

class Movie:
    def input_cmd(self):
        print('输入命令:')
        while True:
            cmd = input('请输入方法名').strip()
            if hasattr(self,cmd):
                method = getattr(self,cmd)
                method()
    def upload(self):
        print('电影开始上传')

    def download(self):
        print('电影开始下载')

movie_obj = Movie()
movie_obj.input_cmd()

魔法方法

魔法方法(类的内置方法):凡是在类内部定义,以__开头__结尾都称之为魔法方法,又称类的内置方法,
会在某些条件成立的情况下触发。
__init__:在调用类时触发。
__str__:会在打印对象时触发,必须要return一个字符串类型的值。
__str__应用:打印一个列表等等。
__del__:会在程序执行结束时触发,对象销毁,该方法会在最后被执行和其定义的位置无关。
__getattr__:会在对象.属性时,属性没有的情况下触发,如果没有默认返回None,我们可以加return 我们想要的值。
__getattribute__:不管属性有没有都会触发,如果和__getattr__同时出现,则只执行前者(__getattribute__)
__setattr__:会在对象.属性 = 属性值 时触发,出发时外部的对象添加属性赋值就没用了,属性赋值在内部进行。
__call__:会在对象被调用时触发。
__new__:会在__init__执行前触发,真正的实例化对象就是通过object类中的__new__进行的,__new__会创建一个空的实例化对象。

class Foo(object):

    def __new__(cls, *args, **kwargs):
        print(cls)
        return object.__new__(cls)#通过object产生一个空对象

    def __init__(self):
        print('在调用类时触发。。。')

    def __str__(self):
        print('在打印时触发。。。')
        return 'xiaohua'

    def __del__(self):
        print('对象被销毁前执行该方法')

    def __getattr__(self, item):
        print('会在对象.属性时,属性没有的情况下触发')
        print(item)
        #默认返回None,若想打印属性的结果,必须return一个值
        return 1

    def __setattr__(self, key, value):
        print('会在对象.属性 = 属性值 时触发...')
        print(key,value)
        print(type(self))
        print(self,111)
        self.__dict__[key] = value

    def __call__(self, *args, **kwargs):
        print(self)
        print('调用对象时触发该方法...')

foo_obj = Foo()
print(foo_obj.__class__)
foo_obj.x = 10
#print(foo_obj.x)
print(foo_obj)

小练习:使用魔法方法和open,实现with open的功能。

class MyFile:
    def __init__(self,file_name,mode = 'r',encoding = 'utf8'):
        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 file_read(self):
        res = self.f.read()
        print(f'''
        当前文件名称:{self.file_name}
        当前文件数据:{res}
        ''')

    def __del__(self):
        self.f.close()
        print('文件关闭成功')

f = MyFile('biji.txt')
f.file_open()
f.file_read()

单例模式

单例模式指的是单个实例,实例指的时调用类产生的对象。

​ 实例化多个对象会产生不同的内存地址,单例可以让所有调用者, 在调用类产生对象的情况下都指向同一份内存地址。 例如: 打开文件。

​ 单例的目的:
​ 为了减少内存的占用。

class File:
    __instance = None
    # 单例方式1
    @classmethod
    def singleton(cls,file_name):
        if not cls.__instance:
            obj = cls(file_name)
            cls.__instance = obj
        return cls.__instance

    def __init__(self,file_name,mode='r',encoding = 'utf8'):
        self.file_name = file_name
        self.mode = mode
        self.encoding = encoding

    def open(self):
        self.f = open(self.file_name,self.mode,encoding=self.encoding)

    def read(self):
        res = self.f.read()
        print(res)

    def close(self):
        self.f.close()

file1 = File.singleton('biji.txt')#此处必须要调用这个方法才行
print(file1)
file2 = File.singleton('biji.txt')
print(file2)
class File:
    __instance = None
    # 单例方式2
    def __new__(cls, *args, **kwargs):
        if not cls.__instance:
            cls.__instance = object.__new__(cls)
        return cls.__instance

    def __init__(self,file_name,mode='r',encoding = 'utf8'):
        self.file_name = file_name
        self.mode = mode
        self.encoding = encoding

    def open(self):
        self.f = open(self.file_name,self.mode,encoding=self.encoding)

    def read(self):
        res = self.f.read()
        print(res)

    def close(self):
        self.f.close()

file1 = File('biji.txt')#此处必须要调用这个方法才行
print(file1)
file2 = File('biji.txt')
print(file2)
posted @ 2019-10-12 21:20  ylpb  阅读(138)  评论(0编辑  收藏  举报