面向对象高级语法部分

经典类vs新式类

把下面代码用python2 和python3都执行一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#_*_coding:utf-8_*_
 
 
class A:
    def __init__(self):
        self.n = 'A'
 
class B(A):
    # def __init__(self):
    #     self.n = 'B'
    pass
 
class C(A):
    def __init__(self):
        self.n = 'C'
 
class D(B,C):
    # def __init__(self):
    #     self.n = 'D'
    pass
 
obj = D()
 
print(obj.n)

classical vs new style:

  • 经典类:深度优先
  • 新式类:广度优先
  • super()用法

抽象接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import abc
 
class Alert(object):
    '''报警基类'''
    __metaclass__ = abc.ABCMeta
 
    @abc.abstractmethod
    def send(self):
        '''报警消息发送接口'''
        pass
 
 
 
class MailAlert(Alert):
    pass
 
 
= MailAlert()
m.send()

上面的代码仅在py2里有效,python3里怎么实现呢?

  

-----------------------------------------

@staticmethod
#静态方法 实际和类没有什么关系了,调用不了类的变量也调用不了实例的变量。
#调用必须通过类调用。
@classmethod
#类方法 只能访问类变量,不能访问实例变量
@property
#属性方法 把一个方法变成一个静态属性 调用是不用()
如果要赋值:
class Dog(object):
def __init__():
self.__food = None @property
def eat(self):
print("%s is eating" % self.__food)
@eat.setter #赋值调用的这个
def eat(self,food)
print("set to food:",food)
self.__food = food
@eat.deleter #删除调用这个
del eat(slef):
del self.__food
赋值:
d = Dog("lalala")
d.eat = "baozi"
d.eat
删除:
del d.eat
----------------------------------------

  

静态方法

通过@staticmethod装饰器即可把其装饰的方法变为一个静态方法,什么是静态方法呢?其实不难理解,普通的方法,可以在实例化后直接调用,并且在方法里可以通过self.调用实例变量或类变量,但静态方法是不可以访问实例变量或类变量的,一个不能访问实例变量和类变量的方法,其实相当于跟类本身已经没什么关系了,它与类唯一的关联就是需要通过类名来调用这个方法

1
2
3
4
5
6
7
8
9
10
11
12
13
class Dog(object):
 
    def __init__(self,name):
        self.name = name
 
    @staticmethod #把eat方法变为静态方法
    def eat(self):
        print("%s is eating" % self.name)
 
 
 
= Dog("ChenRonghua")
d.eat()

上面的调用会出以下错误,说是eat需要一个self参数,但调用时却没有传递,没错,当eat变成静态方法后,再通过实例调用时就不会自动把实例本身当作一个参数传给self了。

1
2
3
4
Traceback (most recent call last):
  File "/Users/jieli/PycharmProjects/python基础/自动化day7面向对象高级/静态方法.py", line 17in <module>
    d.eat()
TypeError: eat() missing 1 required positional argument: 'self'

想让上面的代码可以正常工作有两种办法

1. 调用时主动传递实例本身给eat方法,即d.eat(d)

2. 在eat方法中去掉self参数,但这也意味着,在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
11
12 d = Dog("ChenRonghua")
13 d.eat()

类方法  

类方法通过@classmethod装饰器实现,类方法和普通方法的区别是, 类方法只能访问类变量,不能访问实例变量

1
2
3
4
5
6
7
8
9
10
11
12
class Dog(object):
    def __init__(self,name):
        self.name = name
 
    @classmethod
    def eat(self):
        print("%s is eating" % self.name)
 
 
 
= Dog("ChenRonghua")
d.eat()

执行报错如下,说Dog没有name属性,因为name是个实例变量,类方法是不能访问实例变量的

1
2
3
4
5
6
Traceback (most recent call last):
  File "/Users/jieli/PycharmProjects/python基础/自动化day7面向对象高级/类方法.py", line 16in <module>
    d.eat()
  File "/Users/jieli/PycharmProjects/python基础/自动化day7面向对象高级/类方法.py", line 11in eat
    print("%s is eating" % self.name)
AttributeError: type object 'Dog' has no attribute 'name'

此时可以定义一个类变量,也叫name,看下执行效果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Dog(object):
    name = "我是类变量"
    def __init__(self,name):
        self.name = name
 
    @classmethod
    def eat(self):
        print("%s is eating" % self.name)
 
 
 
= Dog("ChenRonghua")
d.eat()
 
 
#执行结果
 
我是类变量 is eating

属性方法  

属性方法的作用就是通过@property把一个方法变成一个静态属性

1
2
3
4
5
6
7
8
9
10
11
12
class Dog(object):
 
    def __init__(self,name):
        self.name = name
 
    @property
    def eat(self):
        print(" %s is eating" %self.name)
 
 
= Dog("ChenRonghua")
d.eat()

调用会出以下错误, 说NoneType is not callable, 因为eat此时已经变成一个静态属性了, 不是方法了, 想调用已经不需要加()号了,直接d.eat就可以了

1
2
3
4
5
Traceback (most recent call last):
 ChenRonghua is eating
  File "/Users/jieli/PycharmProjects/python基础/自动化day7面向对象高级/属性方法.py", line 16in <module>
    d.eat()
TypeError: 'NoneType' object is not callable

正常调用如下

1
2
3
4
5
= Dog("ChenRonghua")
d.eat
 
输出
 ChenRonghua is eating

好吧,把一个方法变成静态属性有什么卵用呢?既然想要静态变量,那直接定义成一个静态变量不就得了么?well, 以后你会需到很多场景是不能简单通过 定义 静态属性来实现的, 比如 ,你想知道一个航班当前的状态,是到达了、延迟了、取消了、还是已经飞走了, 想知道这种状态你必须经历以下几步:

1. 连接航空公司API查询

2. 对查询结果进行解析

3. 返回结果给你的用户

因此这个status属性的值是一系列动作后才得到的结果,所以你每次调用时,其实它都要经过一系列的动作才返回你结果,但这些动作过程不需要用户关心, 用户只需要调用这个属性就可以,明白 了么?

 class Flight(object):
def __init__(self,name):
self.flight_name = name def checking_status(self):
print("checking flight %s status " % self.flight_name)
return 1 @property
def flight_status(self):
status = self.checking_status()
if status == 0 :
print("flight got canceled...")
elif status == 1 :
print("flight is arrived...")
elif status == 2:
print("flight has departured already...")
else:
print("cannot confirm the flight status...,please check later") f = Flight("CA980")
f.flight_status

cool , 那现在我只能查询航班状态, 既然这个flight_status已经是个属性了, 那我能否给它赋值呢?试试吧

1
2
3
= Flight("CA980")
f.flight_status
f.flight_status =  2

输出, 说不能更改这个属性,我擦。。。。,怎么办怎么办。。。

1
2
3
4
5
6
checking flight CA980 status
flight is arrived...
Traceback (most recent call last):
  File "/Users/jieli/PycharmProjects/python基础/自动化day7面向对象高级/属性方法.py", line 58in <module>
    f.flight_status =  2
AttributeError: can't set attribute

当然可以改, 不过需要通过@proerty.setter装饰器再装饰一下,此时 你需要写一个新方法, 对这个flight_status进行更改。

 class Flight(object):
def __init__(self,name):
self.flight_name = name def checking_status(self):
print("checking flight %s status " % self.flight_name)
return 1 @property
def flight_status(self):
status = self.checking_status()
if status == 0 :
print("flight got canceled...")
elif status == 1 :
print("flight is arrived...")
elif status == 2:
print("flight has departured already...")
else:
print("cannot confirm the flight status...,please check later") @flight_status.setter #修改
def flight_status(self,status):
status_dic = {
0 : "canceled",
1 :"arrived",
2 : "departured"
}
print("\033[31;1mHas changed the flight status to \033[0m",status_dic.get(status) ) @flight_status.deleter #删除
def flight_status(self):
print("status got removed...") f = Flight("CA980")
f.flight_status
f.flight_status = 2 #触发@flight_status.setter
del f.flight_status #触发@flight_status.deleter
class Flight(object):
def __init__(self,name):
self.flight_name = name def checking_status(self):
print("checking flight %s status " % self.flight_name)
return 1 @property
def flight_status(self):
status = self.checking_status()
if status == 0 :
print("flight got canceled...")
elif status == 1 :
print("flight is arrived...")
elif status == 2:
print("flight has departured already...")
else:
print("cannot confirm the flight status...,please check later") @flight_status.setter #修改
def flight_status(self,status):
status_dic = {
0 : "canceled",
1 :"arrived",
2 : "departured"
}
print("\033[31;1mHas changed the flight status to \033[0m",status_dic.get(status) ) @flight_status.deleter #删除
def flight_status(self):
print("status got removed...") f = Flight("CA980")
f.flight_status
f.flight_status = 2 #触发@flight_status.setter
del f.flight_status #触发@flight_status.deleter

注意以上代码里还写了一个@flight_status.deleter, 是允许可以将这个属性删除

类的特殊成员方法

__doc__         #输出类的注释
__module__ #输出模块 XX.XX
__class__ #输出类 xx.xx.xx
__init__ #构造方法
__del__ #析构方法 对象在内存中释放的时候,自动触发执行
__call__ #对象后面加(),触发执行 对象()或 类()()
__dict__ #查看类所有成员,不包括实例属性或是查看对象的实例属性,不包括类的属性
__str__ #定义了它,那么打印对象时,默认打该方法的返回值
__getitem__ #用于索引操作,如字典。获取
__setitem__ #用于索引操作,如字典。设置
__delitem__ #用于索引操作,如字典。删除
__new__ #实例时候也会自动执行,并且在__init__之前。因为__new__调用了__init__.new是用来创建实例的
__metaclass__ #其用来表示该类由谁来实例化创建

1. __doc__  表示类的描述信息

1
2
3
4
5
6
7
8
class Foo:
    """ 描述类信息,这是用于看片的神奇 """
 
    def func(self):
        pass
 
print Foo.__doc__
#输出:类的描述信息

2. __module__ 和  __class__ 

  __module__ 表示当前操作的对象在那个模块

  __class__     表示当前操作的对象的类是什么

 class C:

     def __init__(self):
self.name = 'wupeiqi'
 from lib.aa import C

 obj = C()
print obj.__module__ # 输出 lib.aa,即:输出模块
print obj.__class__ # 输出 lib.aa.C,即:输出类

3. __init__ 构造方法,通过类创建对象时,自动触发执行。

4.__del__

 析构方法,当对象在内存中被释放时,自动触发执行。

注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的

  

5. __call__ 对象后面加括号,触发执行。

注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()

1
2
3
4
5
6
7
8
9
10
11
12
class Foo:
 
    def __init__(self):
        pass
     
    def __call__(self*args, **kwargs):
 
        print '__call__'
 
 
obj = Foo() # 执行 __init__
obj()       # 执行 __call__

6. __dict__ 查看类或对象中的所有成员   

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Province:
 
    country = 'China'
 
    def __init__(self, name, count):
        self.name = name
        self.count = count
 
    def func(self*args, **kwargs):
        print 'func'
 
# 获取类的成员,即:静态字段、方法、
print Province.__dict__
# 输出:{'country': 'China', '__module__': '__main__', 'func': <function func at 0x10be30f50>, '__init__': <function __init__ at 0x10be30ed8>, '__doc__': None}
 
obj1 = Province('HeBei',10000)
print obj1.__dict__
# 获取 对象obj1 的成员
# 输出:{'count': 10000, 'name': 'HeBei'}
 
obj2 = Province('HeNan'3888)
print obj2.__dict__
# 获取 对象obj1 的成员
# 输出:{'count': 3888, 'name': 'HeNan'}

7.__str__ 如果一个类中定义了__str__方法,那么在打印 对象 时,默认输出该方法的返回值。

1
2
3
4
5
6
7
8
9
class Foo:
 
    def __str__(self):
        return 'alex li'
 
 
obj = Foo()
print obj
# 输出:alex li

8.__getitem__、__setitem__、__delitem__

用于索引操作,如字典。以上分别表示获取、设置、删除数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Foo(object):
 
    def __getitem__(self, key):
        print('__getitem__',key)
 
    def __setitem__(self, key, value):
        print('__setitem__',key,value)
 
    def __delitem__(self, key):
        print('__delitem__',key)
 
 
obj = Foo()
 
result = obj['k1']      # 自动触发执行 __getitem__
obj['k2'= 'alex'   # 自动触发执行 __setitem__
del obj['k1']   

9. __new__ \ __metaclass__

1
2
3
4
5
6
7
8
class Foo(object):
 
 
    def __init__(self,name):
        self.name = name
 
 
= Foo("alex")

上述代码中,obj 是通过 Foo 类实例化的对象,其实,不仅 obj 是一个对象,Foo类本身也是一个对象,因为在Python中一切事物都是对象

如果按照一切事物都是对象的理论:obj对象是通过执行Foo类的构造方法创建,那么Foo类对象应该也是通过执行某个类的 构造方法 创建。

1
2
print type(f) # 输出:<class '__main__.Foo'>     表示,obj 对象由Foo类创建
print type(Foo) # 输出:<type 'type'>              表示,Foo类对象由 type 类创建

所以,f对象是Foo类的一个实例Foo类对象是 type 类的一个实例,即:Foo类对象 是通过type类的构造方法创建。

那么,创建类就可以有两种方式:

a). 普通方式

1
2
3
4
class Foo(object):
  
    def func(self):
        print 'hello alex'

b). 特殊方式

1
2
3
4
5
6
7
def func(self):
    print 'hello wupeiqi'
  
Foo = type('Foo',(object,), {'func': func})
#type第一个参数:类名
#type第二个参数:当前类的基类
#type第三个参数:类的成员
 def func(self):
print("hello %s"%self.name) def __init__(self,name,age):
self.name = name
self.age = age
Foo = type('Foo',(object,),{'func':func,'__init__':__init__}) f = Foo("jack",22)
f.func()

So ,孩子记住,类 是由 type 类实例化产生

那么问题来了,类默认是由 type 类实例化产生,type类中如何实现的创建类?类又是如何创建对象?

答:类中有一个属性 __metaclass__,其用来表示该类由 谁 来实例化创建,所以,我们可以为 __metaclass__ 设置一个type类的派生类,从而查看 类 创建的过程。

  1 class MyType(type):
2 def __init__(self,*args,**kwargs):
3
4 print("Mytype __init__",*args,**kwargs)
5
6 def __call__(self, *args, **kwargs):
7 print("Mytype __call__", *args, **kwargs)
8 obj = self.__new__(self)
9 print("obj ",obj,*args, **kwargs)
10 print(self)
11 self.__init__(obj,*args, **kwargs)
12 return obj
13
14 def __new__(cls, *args, **kwargs):
15 print("Mytype __new__",*args,**kwargs)
16 return type.__new__(cls, *args, **kwargs)
17
18 print('here...')
19 class Foo(object,metaclass=MyType):
20
21
22 def __init__(self,name):
23 self.name = name
24
25 print("Foo __init__")
26
27 def __new__(cls, *args, **kwargs):
28 print("Foo __new__",cls, *args, **kwargs)
29 return object.__new__(cls)
30
31 f = Foo("Alex")
32 print("f",f)
33 print("fname",f.name)

类的生成 调用 顺序依次是 __new__ --> __init__ --> __call__

metaclass 详解文章:http://stackoverflow.com/questions/100003/what-is-a-metaclass-in-python 得票最高那个答案写的非常好

反射

通过字符串映射或修改程序运行时的状态、属性、方法, 有以下4个方法

反射
hasattr(obj,str) 判断一个对象是否有对应的字符串的方法
getattr(obj,str) 根据字符串去获取obj对象里的对应的方法的内存地址
setattr(obj,'y',v) 添加属性方法 obj.y =v
delattr(obj,str) 删除属性方法
 #!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author:kiko0o0 def bulk(self):
print("%s is yelling" % self.name) class Dog(object):
def __init__(self,name):
self.name = name
def eat(self,food):
print("%s is eating" % self.name,food) d = Dog("niu")
choice = input(':>>').strip()
if choice == 'name' : #更改属性
setattr(d,choice,'zk')
attr = getattr(d, choice)
print('name is %s' % attr) elif hasattr(d,choice): #调用输入的方法
func = getattr(d,choice)
func('apple') else:
setattr(d,choice,bulk) #添加输入的方法
func = getattr(d,choice)
func(d)

用法

 def getattr(object, name, default=None): # known special case of getattr
"""
getattr(object, name[, default]) -> value Get a named attribute from an object; getattr(x, 'y') is equivalent to x.y.
When a default argument is given, it is returned when the attribute doesn't
exist; without it, an exception is raised in that case.
"""
pass
判断object中有没有一个name字符串对应的方法或属性
 def setattr(x, y, v): # real signature unknown; restored from __doc__
"""
Sets the named attribute on the given object to the specified value. setattr(x, 'y', v) is equivalent to ``x.y = v''
 def delattr(x, y): # real signature unknown; restored from __doc__
"""
Deletes the named attribute from the given object. delattr(x, 'y') is equivalent to ``del x.y''
"""
 class Foo(object):

     def __init__(self):
self.name = 'wupeiqi' def func(self):
return 'func' obj = Foo() # #### 检查是否含有成员 ####
hasattr(obj, 'name')
hasattr(obj, 'func') # #### 获取成员 ####
getattr(obj, 'name')
getattr(obj, 'func') # #### 设置成员 ####
setattr(obj, 'age', 18)
setattr(obj, 'show', lambda num: num + 1) # #### 删除成员 ####
delattr(obj, 'name')
delattr(obj, 'func')

动态导入模块

1
2
3
4
import importlib
 
__import__('import_lib.metaclass'#这是解释器自己内部用的
#importlib.import_module('import_lib.metaclass') #与上面这句效果一样,官方建议用这个

day-7心得的更多相关文章

  1. 我的MYSQL学习心得(一) 简单语法

    我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) 数据类型 我的MYSQL学习心得(五) 运 ...

  2. NoSql数据库使用半年后在设计上面的一些心得

    NoSql数据库这个概念听闻许久了,也陆续看到很多公司和产品都在使用,优缺点似乎都被分析的清清楚楚.但我心里一直存有一个疑惑,它的出现究竟是为了解决什么问题? 这个疑惑非常大,为此我看了很多分析文章, ...

  3. 我的MYSQL学习心得(二) 数据类型宽度

    我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) 数据类型 我的MYSQL学习心得(五) 运 ...

  4. 我的MYSQL学习心得(三) 查看字段长度

    我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(四) 数据类型 我的MYSQL学习心得(五) 运 ...

  5. 我的MYSQL学习心得(四) 数据类型

    我的MYSQL学习心得(四) 数据类型 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(五) 运 ...

  6. 我的MYSQL学习心得(五) 运算符

    我的MYSQL学习心得(五) 运算符 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) 数据 ...

  7. 我的MYSQL学习心得(六) 函数

    我的MYSQL学习心得(六) 函数 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) 数据类 ...

  8. 我的MYSQL学习心得(七) 查询

    我的MYSQL学习心得(七) 查询 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) 数据类 ...

  9. 我的MYSQL学习心得(八) 插入 更新 删除

    我的MYSQL学习心得(八) 插入 更新 删除 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得( ...

  10. 我的MYSQL学习心得(九) 索引

    我的MYSQL学习心得(九) 索引 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) 数据类 ...

随机推荐

  1. 三 web爬虫,scrapy模块介绍与使用

    Scrapy是一个为了爬取网站数据,提取结构性数据而编写的应用框架. 其可以应用在数据挖掘,信息处理或存储历史数据等一系列的程序中.其最初是为了页面抓取 (更确切来说, 网络抓取 )所设计的, 也可以 ...

  2. combobox默认值为第一个数据,修改为空值

    以前用combobox的时候默认是空的,可是昨天不知道为什么,默认的居然为第一个数据,实在让人烦恼.百度了很多,有些人说默认本来就是为空的,而有些也和我一样默认是第一个数据. 我想造成这个现象的原因应 ...

  3. vue2项目中better-scroll 插件使用时候页面不滚动

    参考这里 1.外面包裹层的高度没有设置或者条目的高度没有超过外面包裹层的高度 2.初始化BetterScroll的时机不对,当前元素还没有正常渲染出来,导致BetterScroll的高度的计算错误

  4. 原生JS日历 + JS格式化时间格式

    公司项目中用到,以前没做过,废了好几个小时 终于做好了 先来效果图(暂时没写样式 凑合着看吧) 点击左右按钮都能改变月份 下方表格中的数据也会跟着变化 贴上代码 : html部分: <div s ...

  5. 【ccf 2017/12/4】行车路线(dijkstra变形)

    问题描述 小明和小芳出去乡村玩,小明负责开车,小芳来导航. 小芳将可能的道路分为大道和小道.大道比较好走,每走1公里小明会增加1的疲劳度.小道不好走,如果连续走小道,小明的疲劳值会快速增加,连续走s公 ...

  6. [eShopOnContainers 学习系列] - 00 - 开发环境需求

    开发环境需求 https://github.com/dotnet-architecture/eShopOnContainers/wiki/00.-Dev-machine-requirements 我的 ...

  7. Struts11---文件上传

    01.创建对应的上传页面 <body> <form action="user/upload" method="post" enctype=&q ...

  8. Struts07---访问servlet的API

    01.创建登录界面 <%@ page language="java" import="java.util.*" pageEncoding="UT ...

  9. Agilent RF fundamentals (6) - Real TX/RX and RF model

    LNA:Low-Noise Amplifier PA: Power Amplifier1 VGA: Variable-Gain Amplifier  DC input Bias Volatage, B ...

  10. VS for Mac安装之路

    首先说四个字:水土不服 作为宇宙最强IDE,从开始编程就一直用的Visual Studio,最近新买了Mac,发现微软发布了VS for Mac,于是打算安装一个试试,怎奈,微软的产品在别家水土不服, ...