美文网首页初学者python
7、深入类和对象

7、深入类和对象

作者: python与数据分析 | 来源:发表于2019-08-15 13:56 被阅读0次

1、with语句(上下文管理器)

Python 提供了 with 语法用于简化资源操作的后续清除操作,是 try/finally 的替代方法,实现原理建立在上下文管理器之上。

#上下文管理器
class Sample:
    def __enter__(self):
        print('enter')
        #获取资源
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        #释放资源
        print('exit')

    def do_something(self):
        print('doing something')

#会自动执行enter和exit方法
with Sample() as sample:
    sample.do_something()


# 运行结果
enter
doing something
exit

python中with可以明显改进代码友好度,比如:

with open('a.txt') as f:
    print f.readlines()

为了我们自己的类也可以使用with, 只要给这个类增加两个函数enter, exit即可:

class A:
    def __enter__(self):
        print 'in enter'
    def __exit__(self, e_t, e_v, t_b):
        print 'in exit'
 
with A() as a:
    print 'in with'


# 运行结果
in enter
in with
in exit

另外python库中还有一个模块contextlib,使你不用构造含有enter, exit的类就可以使用with:

from contextlib import contextmanager
from __future__ import with_statement


 @contextmanager
 def context():
     print 'entering the zone'
     try:
         yield
     except Exception, e:
         print 'with an error %s'%e
         raise e
     else:
         print 'with no error'

 with context():
     print '----in context call------'


# 运行结果
entering the zone
----in context call------
with no error

使用的最多的就是这个contextmanager, 另外还有一个closing 用处不大

from contextlib import closing
import urllib
 
with closing(urllib.urlopen('http://www.python.org')) as page:
    for line in page:
        print line

2、super函数

2.1、super() 函数是用于调用父类(超类)的一个方法

#!/usr/bin/python
# -*- coding: UTF-8 -*-
 
class FooParent(object):
    def __init__(self):
        self.parent = 'I\'m the parent.'
        print ('Parent')
    
    def bar(self,message):
        print ("%s from Parent" % message)
 
class FooChild(FooParent):
    def __init__(self):
        # super(FooChild,self) 首先找到 FooChild 的父类(就是类 FooParent),然后把类 FooChild 的对象转换为类 FooParent 的对象
        super(FooChild,self).__init__()    
        print ('Child')
        
    def bar(self,message):
        super(FooChild, self).bar(message)
        print ('Child bar fuction')
        print (self.parent)
 
if __name__ == '__main__':
    fooChild = FooChild()
    fooChild.bar('HelloWorld')

# 运行结果
Parent
Child
HelloWorld from Parent
Child bar fuction
I'm the parent.

2.2、使用 super() 可以很好地避免构造函数被调用两次。

class A():
    def __init__(self):
        print('enter A')
        print('leave A')


class B(A):
    def __init__(self):
        print('enter B')
        super().__init__()
        print('leave B')


class C(A):
    def __init__(self):
        print('enter C')
        super().__init__()
        print('leave C')


class D(B, C):
    def __init__(self):
        print('enter D')
        super().__init__()
        print('leave D')


d = D()
print(D.__mro__)      #(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
    
#执行结果
D
B
C
A

3、python对象的自省机制

检查某些事物以确定它是什么、它知道什么以及它能做什么,运行时能够获得对象的类型。

type() :一个参数返回对象类型, 三个参数,返回新的类型对象
dir() : 用于返回参数的属性和方法列表
getattr() : 用于返回一个对象属性值
hasattr() : 用于判断对象是否包含对应的属性
isinstance() : 用于判断一个对象是否是一个已知的类型

# class type(name, bases, dict)
# 参数
# name -- 类的名称。
# bases -- 基类的元组。
# dict -- 字典,类内定义的命名空间变量。
# 一个参数实例
>>> type(1)
<type 'int'>
>>> type('runoob')
<type 'str'>
>>> type([2])
<type 'list'>
>>> type({0:'zero'})
<type 'dict'>
>>> x = 1         
>>> type( x ) == int    # 判断类型是否相等
True
  
# 三个参数
>>> class X(object):
...     a = 1
...
>>> X = type('X', (object,), dict(a=1))  # 产生一个新的类型 X
>>> X
<class '__main__.X'>
# type() 和isinstance()区别
1. type() 不会认为子类是一种父类类型,不考虑继承关系。
2. isinstance() 会认为子类是一种父类类型,考虑继承关系。
# 如果要判断两个类型是否相同推荐使用 isinstance()。
示例:
    class A:
        pass
    class B(A):
        pass

    isinstance(A(), A)    # returns True
    type(A()) == A        # returns True
    isinstance(B(), A)    # returns True
    type(B()) == A        # returns False
class Student(Person): def __init__(self,school_name):
        self.school_name = school_name if __name__ == "__main__":

    user = Student('仙剑') #通过 __dict__ 查询有哪些属性
    print(user.__dict__)        #{'school_name': '仙剑'}

    print(Person.__dict__)      #{'__module__': '__main__', '__doc__': '人类', 'name': 'user', '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>}

    print(Person.__doc__)       #人类

    #可以添加属性
    user.__dict__['school_addr'] = '北京'
    print(user.school_addr)     #北京

    #dir也可以查看属性,比__dict__功能更强大
    print(dir(user)) #['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'name', 'school_addr', 'school_name']</pre>

4、类方法,静态方法,和实例方法

class Date():
    #构造函数
    def __init__(self,year,month,day):
        self.year = year
        self.month = month
        self.day = day

    #实例方法
    def tomorrow(self):
        self.day += 1

    # 静态方法不用写self
    @staticmethod
    def parse_from_string(date_str):
        year, month, day = tuple(date_str.split("-"))
        # 静态方法不好的地方是采用硬编码,如果用类方法的话就不会了
        return Date(int(year), int(month), int(day))

    #类方法
    @classmethod
    def from_string(cls, date_str):
        year, month, day = tuple(date_str.split("-"))
        # cls:传进来的类,而不是像静态方法把类写死了
        return cls(int(year), int(month), int(day))

    def __str__(self):
        return '%s/%s/%s'%(self.year,self.month,self.day)

if __name__ == "__main__":
    new_day = Date(2018,5,9)
    #实例方法
    new_day.tomorrow()
    print(new_day)       #2018/5/10

    #静态方法
    date_str = '2018-05-09'
    new_day = Date.parse_from_string(date_str)
    print(new_day)       #2018/5/9

    # 类方法
    date_str = '2018-05-09'
    new_day = Date.from_string(date_str)
    print(new_day)  # 2018/5/9

5、类和实例属性的查找顺序

image
class C(D):
    pass

class B(D): 
    pass

class A(B,C): 
     pass

#顺序:A,B,C,D #__mro__,类的属性查找顺序
print(A.__mro__)      #(<class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.D'>, <class 'object'>)</pre>

image
class E:
   pass

class C(E): 
   pass

class B(D): 
   pass

class A(B,C): 
   pass

#顺序:A,B,D,C,E #__mro__,类的属性查找顺序
print(A.__mro__) #(<class '__main__.A'>, <class '__main__.B'>, <class '__main__.D'>, <class '__main__.C'>, <class '__main__.E'>, <class 'object'>)</pre>

6、类变量和实例变量

python的类变量和实例变量,顾名思义,类变量是指跟类的变量,而实例变量,指跟类的具体实例相关联的变量

class A:
    #类变量
    bb = 11
    def __init__(self,x,y): #实例变量
        self.x = x
        self.y = y

a = A(2,3)
A.bb = 111111
print(a.x,a.y,a.bb)    # 2 3 111111
print(A.bb)            # 111111
 a.bb = 2222     #实际上会在实例对象a里面新建一个属性bb
print(a.bb)          # 2222
print(A.bb)          # 111111</pre>

7、使用isinstance而不是type

7.1、语法:

 isinstance(object, classinfo)

其中,object 是变量,classinfo 是类型即 (tuple,dict,int,float,list,bool等) 和 class类

若参数 object 是 classinfo 类的实例,或者 object 是 classinfo 类的子类的一个实例, 返回 True。
若 object 不是一个给定类型的的对象, 则返回结果总是False。

若 classinfo 不是一种数据类型或者由数据类型构成的元组,将引发一个 TypeError 异常。

7.2、isinstance简单用法

>>> isinstance(1,int)
True
>>> 
>>> isinstance('1',str)
True
>>> 
>>> isinstance(1,list)
False

7.3、type()与isinstance()的区别:

  • 共同点两者都可以判断对象类型
  • 不同点对于一个 class 类的子类对象类型判断,type就不行了,而 isinstance 可以。
class A:
    pass

class B(A):
    pass

b = B()

#判断b是不是B的类型
print(isinstance(b,B))        #True
# b是不是A的类型呢,也是的
#因为B继承A,isinstance内部会去检查继承链
print(isinstance(b,A))        #True

print(type(b) is B)           #True
#b指向了B()对象,虽然A是B的父类,但是A是另外一个对象,它们的id是不相等的
print(type(b) is A)           #False

相关文章

  • 7、深入类和对象

    1、with语句(上下文管理器) Python 提供了 with 语法用于简化资源操作的后续清除操作,是 try/...

  • 深入理解类和对象

    1.1 抽象基类(abc模块) python的抽象类的写法,继承抽象类的类必须要实现抽象方法,否则会报错 1.2 ...

  • JAVA入门的进一步加深

    学习目的 深入了解Java语言里面的类、对象、数组的三种输出方式、属性、方法。 相关技术、及其使用 类和对象类:一...

  • 再有人问什么是元类,就把这篇文章扔给他!

    我之前在深入理解python中的类和对象中说过,python中的类也是一个对象,可以说是类对象,可以由type来创...

  • 4.类和对象(构造深入)

    数据成员指针 定义:数据类型类名:: *指针名 = &类名::数据成员 解引用:对象名.* 指针名对象指针 ->*...

  • python入门系列:深入类和对象

    鸭子类型和多态 引言 在鸭子类型中,关注的不是对象的类型本身,而是它是如何使用的。 例如,在不使用鸭子类型的语言中...

  • JVM内存管理之深入理解对象

    深入理解对象 我们知道,Java是一门面向对象设计的语言,面向对象的程序设计语言中有类和对象的概念。类就是具备某些...

  • 类数组对象与arguments

    原文出处 JavaScript深入之类数组对象与arguments 类数组对象 所谓的类数组对象: 拥有一个 le...

  • 3-ndk学习之jni基础篇(2)

    对象深入学习,参数中有对象 直接撸代码:首先有两个实体类Person和Student 然后MainActivity...

  • JavaScript深入之类数组对象与arguments

    JavaScript深入系列第十三篇,讲解类数组对象与对象的相似与差异以及arguments的注意要点 类数组对象...

网友评论

    本文标题:7、深入类和对象

    本文链接:https://www.haomeiwen.com/subject/dqoajctx.html