Day7 - 面向对象高级语法
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Day7 - 面向对象高级语法相关的知识,希望对你有一定的参考价值。
参考文章:http://www.cnblogs.com/alex3714/articles/5213184.html
本节内容:
- 面向对象高级语法部分
- 静态方法、类方法、属性方法
- 类的特殊成员方法
- 反射
静态方法
通过 @staticmethod 装饰器即可把其装饰的方法变为一个静态方法,什么是静态方法呢?其实不难理解,普通的方法,可以在实例化后直接调用,并且在方法里可以通过self.调用实例变量或类变量,但静态方法是不可以访问实例变量或类变量的(只是名义上归类管理),一个不能访问实例变量和类变量的方法,其实跟类本身已经没什么关系了,它与类唯一的关联就是需要通过类名来调用这个方法。
1 class Dog(object): 2 def __init__(self, name): 3 self.name = name 4 5 @staticmethod # 把eat方法变为静态方法 6 def eat(self): 7 print("%s is eating" % self.name) 8 9 d = Dog("abc") 10 d.eat()
上面的调用会出以下错误,说是 eat 需要一个 sel f参数,但调用时却没有传递,没错,当 eat 变成静态方法后,再通过实例调用时就不会自动把实例本身当作一个参数传给 self 了。
1 Traceback (most recent call last): 2 File "D:/python_code/day6/001.py", line 10, in <module> 3 d.eat() 4 TypeError: eat() missing 1 required positional argument: ‘self‘
想让上面的代码可以正常工作有两种办法
1. 调用时主动传递实例本身给 eat 方法,即 d.eat(d) ,可以通过 obj. 调用示例中的其它变量。
2. 在eat方法中去掉 sel f参数,但这也意味着,在 eat 中不能通过 self. 调用实例中的其它变量了
1 class Dog(object): 2 3 def __init__(self,name): 4 self.name = name 5 6 @staticmethod 7 def eat(): 8 print(" is eating") 9 10 d = Dog("abc") 11 d.eat()
类方法
类方法通过 @classmethod 装饰器实现,类方法和普通方法的区别是, 类方法只能访问类变量(公有属性),不能访问实例变量
1 class Dog(object): 2 def __init__(self, name): 3 self.name = name 4 5 @classmethod 6 def eat(self): 7 print("%s is eating" % self.name) 8 9 d = Dog("abc") 10 d.eat()
执行报错如下,说Dog没有name属性,因为name是个实例变量,类方法是不能访问实例变量的
1 Traceback (most recent call last): 2 File "D:/python_code/day6/001.py", line 10, in <module> 3 d.eat() 4 File "D:/python_code/day6/001.py", line 7, in eat 5 print("%s is eating" % self.name) 6 AttributeError: type object ‘Dog‘ has no attribute ‘name‘
此时可以定义一个类变量(公有属性),也叫name,看下执行效果
1 class Dog(object): 2 3 name = "我是类变量" 4 5 def __init__(self, name): 6 self.name = name 7 8 @classmethod 9 def eat(self): 10 print("%s is eating" % self.name) 11 12 d = Dog("abc") 13 d.eat() 14 15 执行结果: 16 我是类变量 is eating
属性方法
属性方法的作用就是通过 @property 装饰器把一个方法变成一个静态属性
1 class Dog(object): 2 3 def __init__(self, name): 4 self.name = name 5 6 @property 7 def eat(self): 8 print("%s is eating" % self.name) 9 10 d = Dog("abc") 11 d.eat()
调用会出以下错误, 说NoneType is not callable, 因为eat此时已经变成一个静态属性了, 不是方法了, 想调用已经不需要加()号了,直接d.eat就可以了
1 ChenRonghua is eating 2 Traceback (most recent call last): 3 File "D:/python_code/day6/001.py", line 11, in <module> 4 d.eat() 5 TypeError: ‘NoneType‘ object is not callable
正常调用如下
1 d = Dog("abc") 2 d.eat 3 4 输出 5 ChenRonghua is eating
变成静态属性后, 想调用已经不需要加()号,也不可以给它传参数了,还不可以直接通过 del 语法删除,因为静态属性默认无法删除。传参数、删除都必须在类里在重新定义一个同名的方法。
1 class Dog(object): 2 def __init__(self, name): 3 self.name = name 4 self.__food = None 5 6 @property # attribute 7 def eat(self): 8 print("%s is eating %s" % (self.name, self.__food)) 9 @eat.setter 10 def eat(self, food): #修改(赋值) 11 print("set to food:", food) 12 self.__food = food 13 @eat.deleter 14 def eat(self): #删除 15 del self.__food 16 print("删完了") 17 18 d = Dog("abc") 19 d.eat 20 d.eat = "包子" #触发@eat.setter 21 d.eat 22 del d.eat #触发@eat.daleter
执行结果:
1 abc is eating None 2 set to food: 包子 3 abc is eating 包子 4 删完了
属性方法的应用实例:
好吧,把一个方法变成静态属性有什么卵用呢?既然想要静态变量,那直接定义成一个静态变量不就得了么?well, 以后你会需到很多场景是不能简单通过 定义 静态属性来实现的, 比如 ,你想知道一个航班当前的状态,是到达了、延迟了、取消了、还是已经飞走了, 想知道这种状态你必须经历以下几步:
1. 连接航空公司API查询
2. 对查询结果进行解析
3. 返回结果给你的用户
因此这个status属性的值是一系列动作后才得到的结果,所以你每次调用时,其实它都要经过一系列的动作才返回你结果,但这些动作过程不需要用户关心, 用户只需要调用这个属性就可以,明白 了么?
1 class Flight(object): 2 def __init__(self, name): 3 self.flight_name = name 4 5 def checking_status(self): 6 print("checking flight %s status " % self.flight_name) 7 return 1 8 9 @property 10 def flight_status(self): 11 status = self.checking_status() 12 if status == 0: 13 print("flight got canceled...") 14 elif status == 1: 15 print("flight is arrived...") 16 elif status == 2: 17 print("flight has departured already...") 18 else: 19 print("cannot confirm the flight status...,please check later") 20 21 @flight_status.setter # 修改 22 def flight_status(self, status): 23 status_dic = { 24 0: "canceled", 25 1: "arrived", 26 2: "departured" 27 } 28 print("\\033[31;1mHas changed the flight status to \\033[0m", status_dic.get(status)) 29 30 @flight_status.deleter # 删除 31 def flight_status(self): 32 print("status got removed...") 33 34 35 f = Flight("CA980") 36 f.flight_status 37 f.flight_status = 2 # 触发@flight_status.setter 38 del f.flight_status # 触发@flight_status.deleter
类的特殊成员方法
1. __doc__ 表示类的描述信息
1 class Dog(object): 2 ‘‘‘这个类是描述狗这个对象的‘‘‘ 3 4 def func(self): 5 pass 6 7 print(Dog.__doc__) 8 9 #输出:这个类是描述狗这个对象的
2. __module__ 和 __class__
__module__ 表示当前操作的对象在那个模块
__class__ 表示当前操作的对象的类是什么
1 class C: 2 3 def __init__(self): 4 self.name = ‘abc‘
1 from lib.aa import C 2 3 obj = C() 4 print obj.__module__ # 输出 lib.aa,即:输出模块 5 print obj.__class__ # 输出<class ‘ lib.aa.C‘>,即:输出类
3. __init__ 构造方法,通过类创建对象时,自动触发执行。
4.__del__
析构方法,当对象在内存中被释放时,自动触发执行。通常用于做一些收尾工作,如关闭一些数据库连接,关闭打开的临时文件。
注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的
5. __call__ 对象后面加括号,触发执行。
注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()
1 class Foo(object): 2 def __init__(self,name): 3 self.name =name 4 print(‘__init__‘) 5 6 def __call__(self, *args, **kwargs): 7 print(‘__call__‘) 8 9 10 obj = Foo(‘abc‘) # 执行 __init__ 11 #输出:__init__ 12 obj() # 执行 __call__ 13 #输出:__call__ 14 Foo(‘abc‘)() # 执行 __call__ 15 #输出:__init__、__call__
6. __dict__ 查看类或对象中的所有成员
1 class Province(object): 2 country = ‘China‘ 3 4 def __init__(self, name, count): 5 self.name = name 6 self.count = count 7 8 def func(self, *args, **kwargs): 9 print(‘func‘) 10 11 # 获取类的所有属性,不包括实例属性,即:公有属性(静态字段)、方法 12 print(Province.__dict__) 13 # 输出:{‘func‘: <function Province.func at 0x000001A21E77EC80>, ‘__dict__‘: <attribute ‘__dict__‘ of ‘Province‘ objects>, ‘country‘: ‘China‘, ‘__weakref__‘: <attribute ‘__weakref__‘ of ‘Province‘ objects>, ‘__init__‘: <function Province.__init__ at 0x000001A21E77EBF8>, ‘__doc__‘: None, ‘__module__‘: ‘__main__‘} 14 15 obj1 = Province(‘HeBei‘, 10000) 16 obj1.func() 17 # 获取实例 obj1 的所有属性,不包括类属性 18 print(obj1.__dict__) 19 # 输出:{‘count‘: 10000, ‘name‘: ‘HeBei‘} 20 21 obj2 = Province(‘HeNan‘, 3888) 22 obj2.func() 23 print(obj2.__dict__) 24 # 获取 对象 obj2 的成员 25 # 输出:{‘count‘: 3888, ‘name‘: ‘HeNan‘}
7.__str__ 如果一个类中定义了__str__方法,那么在打印 对象 时,默认输出该方法的返回值。
1 class Foo(object): 2 def __str__(self): 3 return "__str__" 4 5 obj = Foo() 6 print(obj) 7 # 输出:__str__
8.__getitem__、__setitem__、__delitem__
用于索引操作,如字典。以上分别表示获取、设置、删除数据
1 __author__ = "Alex Li" 2 3 4 class Foo(object): 5 def __init__(self): 6 self.data = {} 7 def __getitem__(self, key): #获取 8 print(‘__getitem__‘, key) 9 return self.data.get(key) 10 def __setitem__(self, key, value): #设置 11 print(‘__setitem__‘, key, value) 12 self.data[key] =value 13 def __delitem__(self, key): #删除 14 print(‘__delitem__‘, key) 15 16 obj = Foo() 17 obj[‘name‘] = "abc" # 自动触发执行 __setitem__ 18 print(obj[‘name‘]) #输出:abc 19 print(obj.data) #输出:{‘name‘: ‘abc‘} 20 del obj["sdfdsf"] # 自动触发执行 __delitem__,删没删除看 __delitem__ 方法里有没有删除 21 result = obj[‘name‘] # 自动触发执行 __getitem__ 22 print(result) #输出:abc 23 obj[‘k2‘] = ‘abc‘ # 自动触发执行 __setitem__ 24 del obj[‘k1‘] 25 print(obj[‘name‘]) #输出:abc 26 print(obj.data) #输出:{‘name‘: ‘abc‘, ‘k2‘: ‘abc‘}
9. __new__ \\ __metaclass__
1 class Foo(object): 2 def __init__(self, name): 3 self.name = name 4 5 f = Foo("abc")
上述代码中,f 是通过 Foo 类实例化的对象,其实,不仅 obj 是一个对象,Foo类本身也是一个对象,因为在Python中一切事物都是对象。
如果按照一切事物都是对象的理论:obj对象是通过执行Foo类的构造方法创建,那么Foo类对象应该也是通过执行某个类的 构造方法 创建。
1 print(type(f)) # 输出:<class ‘__main__.Foo‘> 表示:f 对象由Foo类创建 2 print(type(Foo)) # 输出:<type ‘type‘> 表示,Foo类对象由 type 类创建
所以,f对象是Foo类的一个实例,Foo类对象是 type 类的一个实例,即:Foo类对象 是通过type类的构造方法创建。
那么,创建类就可以有两种方式:
a). 普通方式
1 class Foo(object): 2 3 def func(self): 4 print (‘hello world!‘)
b). 特殊方式
1 def func(self): 2 print(‘hello world!‘) 3 4 # type --> 类的类 5 Foo = type(‘Foo‘, (object,), {‘func‘: func}) #新式类 6 #Foo = type(‘Foo‘, (), {‘func‘: func}) #经典类 7 # type第一个参数:类名 8 # type第二个参数:当前类的基类; 新式类:(object,) 、经典类:() 9 # type第三个参数:类的成员
1 def func(self): 2 print(‘hello %s‘ %self.name) 3 4 def __init__(self,name,age): 5 self.name = name 6 self.age = age 7 # type --> 类的类 8 Foo = type(‘Foo‘, (object,), {‘talk‘: func, 9 ‘__init__‘:__init__}) 10 f = Foo("world",22) 11 f.talk() #输出:hello world 12 print(type(f)) #输出:<class ‘__main__.Foo‘> 13 print(type(Foo)) #输出:<class ‘type‘>
所以说,类 是由 type 类实例化产生
那么问题来了,类默认是由 type 类实例化产生,type类中如何实现的创建类?类又是如何创建对象?
答:类中有一个属性 __metaclass__,其用来表示该类由 谁 来实例化创建,所以,我们可以为 __metaclass__ 设置一个type类的派生类,从而查看 类 创建的过程。
1 class MyType(type): 2 def __init__(self, what, bases=None, dict=None): 3 print("MyType __init__") 4 super(MyType, self).__init__(what, bases, dict) 5 6 def __call__(self, *args, **kwargs): 7 print("MyType __call__") 8 obj = self.__new__(self, *args, **kwargs) 9 #obj.data = {"name":111} 10 self.__init__(obj, *args, **kwargs) 11 12 class Foo(object): 13 __metaclass__ = MyType #元类:__metaclass__,跟 MyType 关联 14 15 def __init__(self, name): 16 self.name = name 17 print("Foo __init__") 18 19 def __new__(cls, *args, **kwargs): #用来创建实例的 20 print("Foo __new__") 21 #print(object.__new__(cls)) 22 return object.__new__(cls) #继承父类的__new__方法,一定要用 return 23 24 # 第一阶段:解释器从上到下执行代码创建Foo类 25 # 第二阶段:通过Foo类创建obj对象 26 # 类的生成调用顺序依次是 __new__ --> __init__ --> __call__ 27 obj = Foo("Alex") 28 print(obj.name)
类的生成 调用 顺序依次是 __new__ --> __init__ --> __call__
__new__ : 用来创建实例的,一般无须定义,自动存在,定义就是重构__new__方法
以上是关于Day7 - 面向对象高级语法的主要内容,如果未能解决你的问题,请参考以下文章