day7 面向对象 静态方法 类方法 属性方法 类的特殊成员方法 元类 反射 异常处理
一、面向对象高级语法部分
1、静态方法
通过@staticmethod装饰器即可把其装饰的方法变为一个静态方法,什么是静态方法呢?其实不难理解,普通的方法,可以在实例化后直接调用,并且在方法里可以通过self.调用实例变量或类变量,但静态方法是不可以访问实例变量或类变量的,一个不能访问实例变量和类变量的方法,其实相当于跟类本身已经没什么关系了,它与类唯一的关联就是需要通过类名来调用这个方法
class Dog(object): def __init__(self, name, color): self.name = name self.color = color @staticmethod def eat(obj_dog): # 这里的self和其他类方法的self不同,不建议使用self # def eat(self): # 可以替换为其他任意字符,调用时不会自动添加 print('%s is eating' % obj_dog.name) huskie = Dog('Huskie', 'gray') huskie.eat(huskie) # 这里调用的时候必须要传参数,否则会报错
2、类方法
类方法通过@classmethod装饰器实现,类方法和普通方法的区别是, 类方法只能访问类变量,不能访问实例变量
class Dog(object): def __init__(self, name, color): self.name = name self.color = color @classmethod def eat(cls): # classmethod方法第一个参数一般是cls print('%s is eating' % cls.name) d = Dog('aa', 'gray') d.eat() # 调用是报错 AttributeError: type object 'Dog' has no attribute 'name'
根据定义 类方法只能访问类变量,不能访问实例变量,所以下面进行修改
class Dog(object): name = 'haha' def __init__(self, name, color): self.name = name self.color = color @classmethod def eat(cls): # classmethod方法第一个参数一般是cls ,代表该类本身,自动添加 print('%s is eating' % cls.name) d = Dog('aa', 'gray') d.eat() # 给Dog加上name属性后调用正确
3、属性方法
属性方法的作用就是通过@property把一个方法变成一个静态属性
class Dog(object): name = 'haha' def __init__(self, name, color): self.name = name self.color = color @property def eat(self): print('%s is eating' % self.name) d = Dog('aa', 'gray') d.eat # 不能使用d.eat(),否则会出现NoneType is not callable,因为eat此时已经变成一个静态属性了, 不是方法了 # 输出:aa is eating
除了@property还有@attr.deleter、@attr.setter 分别是删除和修改
#!/usr/bin/env python # -*- coding:utf-8 -*- # Author:Glen import random import time class Flight(object): def __init__(self, name): self.name = name self.status = 3 def get_flight_status(self): print('获取航班状态中') time.sleep(2) self.status = random.randrange(0, 3) print('当前航班状态为 %s' % self.status) @property def flight_status(self): if self.status == 0: return '航班状态正常' elif self.status == 1: return '航班延迟' else: return '航班状态未知' @flight_status.setter def flight_status(self, status): print('change flight_status') self.status = status @flight_status.deleter def flight_status(self): print('delete flight_status attr') print(hasattr(self, 'status')) del self.status print(hasattr(self, 'status')) sc = Flight('sc') sc.get_flight_status() # 获取航班状态 print(sc.flight_status) sc.flight_status = 3 # 修改航班状态 触发flight_status.setter print(sc.flight_status) del sc.flight_status # 删除航班状态 触发flight_status.deleter print(sc.flight_status) # 报错 'Flight' object has no attribute 'status'
4、类的特殊成员方法
1、__doc__ 表示类的描述信息
2、_module__ 表示当前操作的对象在那个模块
3、__class__ 表示当前操作的对象的类是什么
4、__init__ 构造方法,通过创建对象时自动触发执行
5、__del__ 析构方法,当对象在内存中被释放时自动触发执行,默认情况下析构函数的调用是由解释器在进行垃圾回收时自动触发执行的
6、__dict__ 查看类或对象中的所有成员
7、__str__ 如果一个类定义了__str__方法,那么打印对象时默认输出该方法的返回值
class Foo(object): """member's function test""" def __init__(self, name, age): self.name = name self.age = age def func(self): return self.name def __str__(self): # 重写了__str__方法 return "I am Foo's child {name}".format(name=self.name) def __del__(self): # 程序运行结束后会输出alice is over print("{name} is over".format(name=self.name)) f = Foo('alice', 23) print(f.__doc__) # 输出 member's function test print(f.__module__) # 输出 __main__ print(f.__class__) # 输出 <class '__main__.Foo'> print(f.__dict__) # 输出 {'name': 'alice', 'age': 23} print(f) # 输出 I am Foo's child alice
8、__getitem__、__setitem__、__delitem__ 用于索引操作,如字典。以上分别表示获取、设置、删除数据 相当于可以生成一个自定义的字典
class MyDict(object): def __init__(self): self.all = {} def __getitem__(self, item): if item in self.all: return self.all[item] else: return '{item} not in dict'.format(item=item) def __setitem__(self, key, value): self.all[key] = value def __delitem__(self, key): del self.all[key] my_dict = MyDict() print(my_dict['kk']) # 输出 kk not in dict my_dict['kk'] = 'hello' print(my_dict['kk']) # 输出 hello
9、__call__ 对象后面加括号,触发执行。
10、__new__、__metaclass__ __metaclass__其用来表示该类由谁来实例化创建 __new__决定一个类的上层架构,早于__init__执行
11、type 类是由type类实例化产生的,type类则是解释器写死的
# ----------普通方式生成类---------- class Test(object): def __init__(self, name): self.name = name def func(self): print('hello {name}'.format(name=self.name)) t = Test('geln') # ----------特殊方式生成类---------- def func(self): print('hello glen') def __init__(self, name): self.name = name Test = type('Test', (object,), {'func':func, '__init__':__init__}) f = Test('glen') #type第一个参数:类名 #type第二个参数:当前类的基类 是元组,必须有逗号 #type第三个参数:类的成员
那么问题来了,类默认是由 type 类实例化产生,type类中如何实现的创建类?类又是如何创建对象?
答:类中有一个属性 __metaclass__,其用来表示该类由 谁 来实例化创建,所以,我们可以为 __metaclass__ 设置一个type类的派生类,从而查看 类 创建的过程。
转载自:https://www.cnblogs.com/tkqasn/p/6524879.html
自定义元类
元类的主要目的就是为了当创建类时能够自动地改变类。通常,你会为API做这样的事情,你希望可以创建符合当前上下文的类。假想一个很傻的例子,你决定在你的模块里所有的类的属性都应该是大写形式。有好几种方法可以办到,但其中一种就是通过设定__metaclass__。采用这种方法,这个模块中的所有类都会通过这个元类来创建,我们只需要告诉元类把所有的属性都改成大写形式就万事大吉了。
__metaclass__实际上可以被任意调用,它并不需要是一个正式的类。所以,我们这里就先以一个简单的函数作为例子开始。
1、使用函数当做元类
# 元类会自动将你通常传给‘type’的参数作为自己的参数传入 def upper_attr(future_class_name, future_class_parents, future_class_attr): '''返回一个类对象,将属性都转为大写形式''' #选择所有不以'__'开头的属性 attrs = ((name, value) for name, value in future_class_attr.items() if not name.startswith('__')) # 将它们转为大写形式 uppercase_attr = dict((name.upper(), value) for name, value in attrs) #通过'type'来做类对象的创建 return type(future_class_name, future_class_parents, uppercase_attr)#返回一个类 class Foo(object): __metaclass__ = upper_attr bar = 'bip'
print hasattr(Foo, 'bar') # 输出: False print hasattr(Foo, 'BAR') # 输出:True f = Foo() print f.BAR # 输出:'bip'
2、使用class来当做元类
由于__metaclass__必须返回一个类。
# 请记住,'type'实际上是一个类,就像'str'和'int'一样。所以,你可以从type继承 # __new__ 是在__init__之前被调用的特殊方法,__new__是用来创建对象并返回之的方法,__new_()是一个类方法 # 而__init__只是用来将传入的参数初始化给对象,它是在对象创建之后执行的方法。 # 你很少用到__new__,除非你希望能够控制对象的创建。这里,创建的对象是类,我们希望能够自定义它,所以我们这里改写__new__ # 如果你希望的话,你也可以在__init__中做些事情。还有一些高级的用法会涉及到改写__call__特殊方法,但是我们这里不用,下面我们可以单独的讨论这个使用 class UpperAttrMetaClass(type): def __new__(upperattr_metaclass, future_class_name, future_class_parents, future_class_attr): attrs = ((name, value) for name, value in future_class_attr.items() if not name.startswith('__')) uppercase_attr = dict((name.upper(), value) for name, value in attrs) return type(future_class_name, future_class_parents, uppercase_attr)#返回一个对象,但同时这个对象是一个类
但是,这种方式其实不是OOP。我们直接调用了type,而且我们没有改写父类的__new__方法。现在让我们这样去处理:
class UpperAttrMetaclass(type): def __new__(upperattr_metaclass, future_class_name, future_class_parents, future_class_attr): attrs = ((name, value) for name, value in future_class_attr.items() if not name.startswith('__')) uppercase_attr = dict((name.upper(), value) for name, value in attrs) # 复用type.__new__方法 # 这就是基本的OOP编程,没什么魔法。由于type是元类也就是类,因此它本身也是通过__new__方法生成其实例,只不过这个实例是一个类. return type.__new__(upperattr_metaclass, future_class_name, future_class_parents, uppercase_attr)
你可能已经注意到了有个额外的参数upperattr_metaclass,这并没有什么特别的。类方法的第一个参数总是表示当前的实例,就像在普通的类方法中的self参数一样。当然了,为了清晰起见,这里的名字我起的比较长。但是就像self一样,所有的参数都有它们的传统名称。因此,在真实的产品代码中一个元类应该是像这样的:
class UpperAttrMetaclass(type): def __new__(cls, name, bases, dct): attrs = ((name, value) for name, value in dct.items() if not name.startswith('__') uppercase_attr = dict((name.upper(), value) for name, value in attrs) return type.__new__(cls, name, bases, uppercase_attr)
如果使用super方法的话,我们还可以使它变得更清晰一些。
class UpperAttrMetaclass(type): def __new__(cls, name, bases, dct): attrs = ((name, value) for name, value in dct.items() if not name.startswith('__')) uppercase_attr = dict((name.upper(), value) for name, value in attrs) return super(UpperAttrMetaclass, cls).__new__(cls, name, bases, uppercase_attr)
二、反射
class Client(object): def __init__(self, name, conn, addr): self.name = name self.conn = conn self.addr =addr client = Client('glen', 5, 'sc') print(hasattr(client, 'name')) # 判断是否有该属性,返回Boolean print(getattr(client, 'name')) # 获取实例的值 print(setattr(Client, 'age', 23)) # 设置实例或类的值 print(getattr(Client, 'age')) # 获取实例或类的值 print(delattr(Client, 'age')) # 删除值
三、异常处理
异常处理就是尝试执行一段代码,如果出现了预期的错误则执行相应的代码
class MyException(Exception): # 实现自己的异常 # def __init__(self, msg): # 父类就是这样定义的,不用重写 # self.message = msg # # def __str__(self): # 父类就是这样定义的不用重写 # return self.message pass try: a = [1, 3, 4] # a[5] # IndexError # a.hh # AttributeError # raise IndexError('哈哈') # 主动制造麻烦 # raise MyException('我自己搞的麻烦') # assert a[0] == 3,'list 值不对' # 断言,如果不是这样就出错 AssertionError except IndexError as e: print('我知道要出这个错误错', e) except AttributeError as e: print('我知道要出这个错误错', e) except MyException as e: print('我知道要出这个错误错', e) except AssertionError as e: print('断言错误,可以用在程序测试中', e) except Exception as e: print('我只是知道要出错,具体什么错误我不清楚', e) else: print('没有异常出现,很不错') finally: print('有没有异常我都会执行')