zoukankan      html  css  js  c++  java
  • 第三模块-第一章笔记(面向对象)

    面向过程编程
    一、解释
    面向过程:核心是过程二字,过程即解决问题的步骤,基于面向过程去设计程序就像是在设计,流水线式的编程思想,
    在设计程序时,需要把整个流程设计出来,一条工业流水线,是一种机械式的思维方式。

    二、优缺点
    优点:程序体系结构清晰,可以把复杂的问题简单化,流程化。
    缺点:可扩展性差,一条流线只是用来解决一个问题,所以说面向过程的应用多为不需要经常变化的软件。
    应用场景:linux内核, git, httpd, shell脚本

    三、实例(利用程序函数进行面向过程编程)
    过滤一个文件下的子文件、字文件夹的内容中的相应的内容,在linux中的命令就是grep -rl 'python' /etc
    使用了python的包os里面的walk(),能够把参数中的路径下的文件夹打开并返回一个元组

    >>> import os
    >>> os.walk('D: est')
    generator object walk at 0x0000000002ADB3B8

    >>> os.walk('D:\test') # 以后使用这种路径方式,win下
    >>> os.walk(r'D: est') # 使用r 是让字符串中的符号没有特殊意义,针对的是转义
    出现错误,是因为路径的原因,但是在不同的机器上有的是可以的

    >>> g=os.walk('D: est')
    >>> next(g)
    Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    StopIteration
    以后推荐是用

    >>> g=os.walk('D:\test')
    >>> next(g)
    ('D:\test', ['a', 'b'], ['test.txt'])
    返回的是一个元组,第一个元素是文件的路径,第二个是文件夹,第三个是该路径下的文件

    1.2.1 程序流程
    找文件路径 --os.walk
    然后打开文件 --open
    读取文件的每一行内容 -- for line in f
    过滤一行内容中是否有Python if 'python' in line
    打印包含Python的文件路径
    程序是从上往下执行的,1产生的路径作为参数给2,2产生的给3...

    实例请看:https://www.cnblogs.com/rendawei/p/7051145.html 博客

    面向对象编程

    概述:
    对函数进行分类和封装,让开发“更快更好更强...”
    面向对象编程是一种编程方式,此编程方式的落地需要使用“类”和“对象”来实现,所以,面向对象编程其实就是对
    “类”和“对象”的使用。
    类就是一个模板,模板里可以包含多个函数,函数里实现一些功能
    对象则是根据模板创建的对象则是根据模板创建实例,通过实例对象可以执行类中的函数。
    1.class是关键字,表示类
    2.创建对象,类名称后加括号即可
    PS:类中的函数第一个参数必须是self(详细见:类的三大特性之封装)
    类中定义的函数叫做“方法”

    # 创建类
    class Foo:
    def Bar(self):
    print 'Bar'

    def Hello(self, name):
    print('i am %s' %name)

    #根据Foo创建对象obj
    obj = Foo()
    obj.Bar() #执行Bar方法
    obj.Hello('wupeiqi') #执行Hello方法

    面向对象:[创建对象] [通过对象执行方法]
    函数编程:[执行函数]
    观察上述对比答案则是肯定的,然后并非绝对,场景的不同适合其的编程方式也不同。
    总结:函数式的应用场景 --> 各个函数之间是独立且无共用的数据

    面向对象三大特性:
    面向对象的三大特性是指:封装、继承和多态。

    一、封装
    封装,顾名思义就是将内容封装到某个地方,以后再去调用被封装在某处的内容。
    所以,在使用面向对象的封装特性时,需要:
    1.将内容封装到某处
    2.从某处调用被封装的内容

    # 封装实例
    # 第一步:将内容封装到某处

    # 创建类
    class Foo:
    def __init__(self, name, age): #称为构造方法,根据类创建对象时自动执行
    self.name = name
    self.age = age

    # 根据Foo创建对象
    # 自动执行Foo类的 __init__ 方法
    obj1 = Foo('changhao', 20) #将changhao和20分别封装到 obj1 self的name和age属性中

    # 根据类Foo创建对象
    # 自动执行Foo类的 __init__ 方法
    obj2 = Foo('changhao2', 22) #将changhao2和22分别封装到 obj2 self的name和age属性中

    self是一个形式参数,当执行obj1=Foo('changhao',20)时,self等于obj1
    当执行obj2 = Foo('changhao2',22)时,self等于obj2

    所以,内容其实被封装到了对象obj1和obj2中,每个对象中都有name和age属性,在内存里类似于下图来保存。

    第二步:从某处调用被封装的内容
    调用被封装的内容时,有两种情况:
    通过对象直接调用
    通过self间接调用
    1. 通过对象直接调用被封装的内容
    obj1 = Foo('wupeiqi', 18)
    print(obj1.name)
    print(obj1.age)
    2. 通过self间接调用被封装的内容
    执行类中的方法时,需要通过self间接调用被封装的内容
    class Foo:
    def __init__(self, name, age):
    self.name = name
    self.age = age

    def detail(self):
    print(self.name)
    print(self.age)

    obj1 = Foo('wupeiqi', 18)
    obj1.detail() #python默认会将obj1传给self参数,即:obj1.detail(obj1),所以,此时方法内部的self=obj1,即self.name是wupeiqi;self.age是18

    obj2 = Foo('alex', 73)
    obj2.detail() #python默认会将obj2传给self参数,即:obj2.detail(obj2),所以,此时方法内部的self=obj2,即self.name是alex;self.age是78
    综上所述,对于面向对象的封装来说,其实就是使用构造方法将内容封装到对象中,然后通过对象直接或者self间接获取被封装的内容。

    练习一: 在终端输出如下信息
    小明,10岁,男,上山去砍柴
    小明,10岁,男,开车去东北
    小明,10岁,男,最爱大保健
    老李,90岁,男,上山去砍柴
    老李,90岁,男,开车去东北
    老李,90岁,男,最爱大保健
    老张...

    练习二: 游戏人生程序
    1.创建三个游戏人物,分别是:
    苍井井, 女, 18, 初始战斗力1000
    东尼木木, 男, 20, 初始战斗力1800
    多波波, 女, 19, 初始战斗力2500

    2. 游戏场景,分别:
    草丛战斗, 消耗200战斗力
    自我修炼, 增长100战斗力
    多人游戏, 消耗500战斗力

    二、继承
    继承,面向对象中的继承和现实生活中的继承相同,即:子可以继承父的内容。
    列如:
    猫可以:喵喵叫、吃、喝、拉、撒
    狗可以:汪汪叫、吃、喝、拉、撒
    对于面向对象的继承来说,其实就是将多个类共有的方法提取到父类中,子类仅需继承父类而不必一一实现每个方法。
    注:除了子类和父类的称谓,你可能看到过派生类和基类,他们与子类和父类只是叫法不同而已。

    class 父类:
    def 父类中的方法(self):
    class 子类(父类) #子类继承父类,即拥有了父类中所有方法
    pass
    zi = 子类() #创建子类对象
    zi.父类中的方法() #执行从父类中继承的方法

    那么问题又来了,多继承呢?
    是否可以继承多个类
    如果继承的多个类每个类中都定了相同的函数,那么那一个会被使用呢?
    1. python的类可以继承多个类, Java和C#中则只能继承一个类
    2. python的类如果继承了多个类,那么寻找方法的方式有两种,分别是:深度优先和广度有限

    寻找方法:
    1.深度优先
    A类 --> B类 --> D类 --> C类
    # 经典类,深度优先
    class D:
    def bar(self):
    print 'D.bar'
    class C(D):
    def bar(self):
    print 'C.bar'
    class B(D):
    # def bar(self):
    # print('B.bar')
    pass
    class A(B, C):
    # def bar(self):
    # print('A.bar')
    pass
    a = A()
    a.bar()
    # 结果是 D.bar
    '''
    执行Bar方法时
    首先去A类中查找,如果A类中没有,则继续去B类中找,如果B类中没有,则继续去D类中找,如果D类中没有,则继续去C类中
    找,如果还是未找到,则报错
    所以,查找顺序: A --> B --> D --> C
    在上述查找bar方法的过程中,一旦找到,则寻找过程立即中断,便不会再继续找了。
    '''

    2.广度优先
    A类 --> B类 --> C类 --> D类

    # 新式类,广度优先
    class D(object):
    def bar(self):
    print('D.bar')
    class C(D):
    def bar(self):
    print('C.bar')
    class B(D):
    # def bar(self):
    # print('B.bar')
    pass
    class A(B, C):
    # def bar(self):
    # print('A.bar')
    pass
    a = A()
    a.bar()
    # 结果是 C.bar
    '''
    执行bar方法时
    首先去A类中查找,如果A类中没有,则继续去B类中找,如果B类中没有,则继续去C类中找,如果C类中没有,则继续去D类中找,
    如果还是没有找到,则报错
    所以,查找顺序: A --> B --> C --> D
    在上述查找bar方法的过程中,一旦找到,则寻找过程立即中断,便不会再继续找了。
    '''

    当类是经典类时,多继承情况下,会按照深度优先方式查找
    当类是新式时,多继承情况下,会按照广度优先方式查找
    注:在上述查找过程中,一旦找到,则寻找过程立即中断,便不会再继续找了

    经典类和新式类;从字面上可以看出来一个老一个新,新的必然包含了跟多的功能,也是之后推荐的写法,从写法上区分的话,如果
    当前类或者父类继承了object类,那么该类便是新式类,否则便是经典类。

    class C1: C1是经典类
    pass

    class C2(C1): C2是经典类
    pass

    class N1(object): N1是新式类
    pass

    class N2(N1) N2是新式类

    三、多态
    python不支持java和C#这一类强类型语言中多态的写法,但是原生多态,其python崇尚"鸭子类型"。

    python "鸭子类型"
    class F1:
    pass

    class S1(F1):
    def show(self):
    print('S1.show')

    class S2(F1):
    def show(self):
    print('S2.show')

    def Func(obj):
    print(obj.show())

    s1_obj = S1()
    Func(s1_obj)
    s2_obj = S2()
    Func(s2_obj)

    # 输出结果
    # S1.show
    # None
    # S2.show
    # None

    总结:
    以上就是本节对于面向对象初级知识的介绍,总结如下:
    1.面向对象是一种编程方式,此编程方式的实现是基于对类 和 对象的使用
    2.类是一个模板,模板中包装了多个“函数”供使用
    3.对象,根据模板创建的实例(即:对象),实例用于调用被包装在类中的函数
    4.面向对象三大特性:封装、继承和多态

    参考此博客 http://www.cnblogs.com/wupeiqi/p/4493506.html
    http://www.cnblogs.com/wupeiqi/p/4766801.html

    类的成员:
    类的成员可以分为三大类:字段、方法和属性
    字段:普通字段、静态字段
    方法:普通方法、类方法、静态方法
    属性:普通属性
    注:所有成员中,只有普通字段的内容保存对象中,即:根据此类创建了多少对象,在内存中就有多少普通字段。而其他的成员,
    则都是保存在类中,即:无论对象的多少,在内存中只创建一份。

    一、字段
    字段包括:普通字段和静态字段,他们在定义和使用中有所区别,而最本质的区别是内存中保存的位置不同。
    1.普通字段属于对象
    2.静态字段属于类

    class Province:
    #静态字段
    country = '中国'
    def __init__(self, name):
    # 普通字段
    self.name = name

    obj = Province('河北省')
    print(obj.name) # 直接访问普通字段
    print(Province.country) # 直接访问静态字段

    由上述代码可以看出[普通字段需要通过对象来访问] [静态字段通过类访问],在使用上可以看出普通字段和静态字段的归属是不同的。

    1. 静态字段在内存中只保存一份
    2. 普通字段在每个对象中都要保存一份
    应用场景:通过创建对象时,如果每个对象都具有相同的字段,那么就是用静态字段。

    二、方法
    方法包括:普通方法、静态方法、类方法,三种方法在内存中都归属于类,区别在于调用方式不同。
    1. 普通方法:由对象调用;至少一个self参数;执行普通方法时,自动将调用该方法的对象赋值给self;
    2. 类方法:由类调用;至少一个cls参数;执行类方法时,自动将调用该方法的类复制给cls;
    3. 静态方法:有类调用;无默认参数;

    class Foo:
    def __init__(self, name):
    self.name = name

    def ord_func(self):
    """定义普通方法,至少有一个self参数"""
    print('普通方法')

    @classmethod
    def class_func(cls):
    """定义类方法,至少一个cls参数"""
    print('类方法')

    @staticmethod
    def static_func():
    """定义静态方法,无默认参数"""
    print('静态方法')

    # 调用普通方法
    f = Foo('changhao')
    f.ord_func()

    # 调用类方法
    Foo.class_func()

    # 调用静态方法
    Foo.static_func()

    相同点:对于所有的方法而言,均属于类(非对象)中,所以,在内存中也只保存一份。
    不同点:方法调用者不同、调用方法时自动传入的参数不同。

    三、属性
    python中的属性其实是普通方法的变种
    对于属性,有以下三个知识点:
    1. 属性的基本使用
    2. 属性的两种定义方式

    1. 属性的基本使用
    class Foo:
    def func(self):
    pass

    # 定义属性
    @property
    def prop(self):
    pass
    foo_obj = Foo()
    foo_obj.func()
    print(foo_obj.prop) #调用属性
    #######################################
    class Goods:

    @property
    def price(self):
    return "wupeiqi"

    obj = Goods()
    result = obj.price

    由属性的定义和调用要注意一下几点:
    1. 定义时,在普通方法的基础上添加@property装饰器;
    2. 定义时,属性仅有一个self参数
    3. 调用时,无需括号
    方法:foo_obj.func()
    属性:foo_obj.prop

    注意:属性存在意义是:访问属性时可以制造出和字段完全相同的假象
    属性由方法变种而来,如果python中没有属性,方法完全可以代替其功能。
    实例:对于主机列表页面,每次请求不可能把数据库中的所有内容都显示到页面上,而是通过分页的功能局部显示,所以在
    向数据库中请求数据时就要显示的指定获取从第m条到第n条的所有数据(即:limit m,n),这个分页的功能包括:
    1. 根据用户请求的当前页和总数据条数计算出m和n
    2. 根据m和n去数据库中请求数据

    class Pager:
    def __init__(self, current_page):
    # 用户当前请求的页码(第一页、第二页...)
    self.current_page = current_page
    # 每页默认显示10条数据
    self.per_items = 10

    @property
    def start(self):
    val = (self.current_page - 1) * self.per_items
    return val

    @property
    def end(self):
    val = self.current_page * self.per_items
    return val

    p = Pager(10)
    print(p.start) #就是起始值,即:m
    print(p.end) #就是结束值,即:n

    从上述可见,python的属性的功能是: 属性内部进行一系列的逻辑计算,最终将计算结果返回。

    2. 属性的两种定义方式
    属性的定义有两种方式:
    装饰器 即:在方法上应用装饰器
    静态字段 即:在类中定义值为property对象的静态方式

    装饰器方式:在类的普通方法上应用@property装饰器
    我们知道python中的类有经典类和新式类,新式类的属性比经典类的属性丰富。(如果类继object,那么该类是新式类。)

    经典类,具有一种@property装饰器(如上一步实例)
    class Goods:

    @property
    def price(self):
    return "wupeiqi"

    obj = Goods()
    result = obj.price # 自动执行 @property 修饰的price方法,并获取方法的返回值

    新式类,具有三种@property装饰器
    class Goods(object):

    @property
    def price(self):
    print('@property')

    @price.setter
    def price(self, value):
    print('@price.setter')

    @price.deleter
    def price(self):
    print('@price.deleter')

    obj = Goods()
    obj.price
    obj.price = 123
    del obj.price

    注:经典类中的属性只有一种访问方式,其对应被@property修饰的方法
    新式类中的属性有三种访问方式,分别对应了三个@property、@方法名.setter、@方法名.deleter修饰的方法

    由于新式类中具有三种访问方式,我们可以根据他们几个属性的访问特点,分别将三个方法定义为对同一个属性:获取、修改、删除
    class Goods(object):
    def __init__(self):
    # 原价
    self.original_price = 100
    # 折扣
    self.discount = 0.8

    @property
    def price(self):
    # 实际价格 = 原价 * 折扣
    new_price = self.original_price * self.discount
    return new_price

    @price.setter
    def price(self, value):
    self.original_price = value

    @price.deleter
    def price(self, value):
    del self.original_price

    obj = Goods()
    obj.price # 获取商品价格
    obj.price = 200 # 修改商品原价
    del obj.price # 删除商品原价

    静态字段方式,创建值为property对象的静态字段
    当使用静态字段的方式创建属性时,经典类和新式类无区别:
    class Foo:
    def get_bar(self):
    return 'wupeiqi'
    BAR = property(get_bar)

    obj = Foo()
    reuslt = obj.BAR # 自动调用get_bar方法,并获取方法的返回值
    print(reuslt)

    property的构造方法中有个四个参数
    第一个参数是方法名,调用对象.属性时自动触发执行方法
    第二个参数是方法名,调用对象.属性 == xxx时自动触发执行方法
    第三个参数是方法名,调用del 对象.属性时自动触发执行方法
    第四个参数是字符串,调用对象.属性.__doc__,参数是该属性的描述信息

    class Foo:
    def get_bar(self):
    return 'wupeiqi'

    # *必须两个参数
    def set_bar(self, value):
    return 'set value' + value

    def del_bar(self):
    return 'wupeiqi'

    BAR = property(get_bar, set_bar, del_bar, 'description...')

    obj = Foo()
    obj.BAR # 自动调用第一个参数中定义的方法:get_bar
    obj.BAR = "alex" # 自动调用第二个参数中定义的方法:set_bar方法,并将"alex"当作参数传入
    del Foo.BAR # 自动调用第三个参数中定义的方法:del_bar方法
    obj.BAR.__doc__ # 自动获取第四个参数中设置的值:description

    由于静态字段方式创建属性具有三种访问方式,我们可以根据他们几个属性的访问特点,分别将三个方法定义为对同一个属性:获取
    修改、删除

    定义属性共有两种方式,分别是装饰器和静态字段,而装饰器方式针对经典类和新式类又有所不同。

    类成员的修饰符
    类的所有成员在上一步骤中已经做了详细的介绍,对于每一个类的成员而言都有两种形式:
    1. 公有成员,在任何地方都能访问
    2. 私有成员,只有在类的内部才能访问
    私有成员和公有成员的定义不同:私有成员命名时,前两个字符是下划线。(特殊成员除外,列如:__init__、__call__、__dict__等)
    class C:
    def __init__(self):
    self.name = '公有字段'
    self.__foo = '私有字段'

    私有成员和公有成员的访问限制不同:
    静态字段:
    1. 公有静态字段:类可以访问;类内部可以访问;派生类中可以访问
    2. 私有静态字段;仅类内部可以访问;

    公有静态字段
    class C:
    name = "公有静态字段"
    def func(self):
    print(C.name)

    class D(C):
    def show(self):
    print(C.name)

    C.name #类访问
    obj = C()
    obj.func() #类内部可以访问
    obj_son = D()
    obj_son.show() # 派生类中可以访问

    私有静态字段
    class C:
    __name = "私有静态字段"
    def func(self):
    print(C.__name)

    class D(C):
    def show(self):
    print(C.__name)

    C.__name #类访问 ==>错误

    obj = C()
    obj.func() #类内部可以访问 ==> 正确
    obj_son = D()
    obj_son.show() #派生类中可以访问 ==>错误

    普通字段
    1. 公有普通字段:对象可以访问;类内部可以访问;派生类中可以访问
    2. 私有普通字段:仅类内部可以访问;
    ps: 如果想要强制访问私有字段,可以通过[对象._类名__私有字段名]访问(如:obj._C__foo),不建议强制访问私有成员。

    公有字段
    class C:
    def __init__(self):
    self.foo = "公有字段"

    def func(self):
    print(self.foo) # 类内部访问

    class D(C):
    def show(self):
    print(self.foo) # 派生类中访问

    obj = C()
    obj.foo #通过对象访问
    obj.func() #类内部访问
    obj_son = D()
    obj_son.show() #派生类中访问

    私有字段

    类成员的修饰符
    类的所有成员在上一步骤中已经做了详细的介绍,对于每一个类的成员而言都有两种形式:
    1.公有成员,在任何地方都能访问
    2.私有成员,只有在类的内部才能访问

    私有成员和公有成员的定义不同:私有成员命名时,前两个字符是下划线。(特殊成员外,列如:__init__、__call__、__dict__等)

    私有成员和公有成员的访问限制不同:
    静态字段:
    1. 公有静态字段:类可以访问;类内部可以访问;派生类中可以访问
    2. 私有静态字段:仅类内部可以访问;

    公有静态字段:
    class C:
    def __init__(self):
    self.foo = "公有字段"

    def func(self):
    print(self.foo) #类内部访问

    class D(C):
    def show(self):
    print(self.foo) #派生类中访问

    obj = C()
    obj.foo #通过对象访问
    obj.func() #类内部访问
    obj_son = D();
    obj_son.show() #派生类中访问

    私有静态字段:
    class C:
    def __init__(self):
    self.__foo = "私有字段"

    def func(self):
    print(self.__foo) #类内部访问

    class D(C):
    def show(self):
    print(self.__foo) #派生类访问

    obj = C()
    obj.__foo #通过对象访问 ==> 错误
    obj.func() #类内部访问 ==> 正确
    obj_son = D()
    obj_son.show() #派生类中访问 ==> 错误
    方法、属性的访问于上述方式相似,即:私有成员只能在类内部使用
    PS:非要访问私有属性的话,可以通过对象._类__属性名


    类的特殊成员
    上文介绍了python的类成员以及成员修饰符,从而了解到类中有字段、方法和属性三大类成员,并且成员名前如果有两个下划线,则
    表示该成员是私有成员,私有成员只能有类内部调用。无论人或事物往往都有不按套路出牌的情况,python的类成员也是如此,存在
    着一些具有特殊含义的成员,详情如下:

    1. __doc__
    表示类的描述信息
    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__)
    print(obj.__class__)

    3. __init__
    构造方法,通过类创建对象时,自动触发执行。
    class Foo:
    def __init__(self, name):
    self.name = name
    self.age = 18

    obj = Foo('wupeiqi') # 自动执行类中的 __init__ 方法

    4. __del__
    析构方法,当对象在内存中被释放时,自动触发执行。
    注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因此工作都是交给python
    解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。
    class Foo:
    def __del__(self):
    pass

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

    class Foo:
    def __init__(self):
    pass
    def __call__(self, *args, **kwargs):
    print('__call__')

    obj = Foo() #执行 __init__
    obj() #执行 __call__

    6. __dict__
    类或对象中的所有成员
    上文中我们知道:类的普通字段属于对象;类中的静态字段和方法等属于类,即:

    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__)
    # 输出{'__module__': '__main__', 'country': 'China', '__init__': <function Province.__init__ at 0x000000000272E730>,
    # 'func': <function Province.func at 0x000000000272E7B8>, '__dict__': <attribute '__dict__' of 'Province' objects>,
    # '__weakref__': <attribute '__weakref__' of 'Province' objects>, '__doc__': None}

    obj1 = Province('HeBei', 10000)
    print(obj1.__dict__)
    # 获取 对象obj1 的成员
    # 输出:{'count':10000, 'name':'HeBei'}

    7. __str__
    如果一个类中定义了__str__方法,那么在打印对象时,默认输出该方法的返回值。
    class Foo:
    def __str__(self):
    return 'wupeiqi'

    obj = Foo()
    print(obj) #输出:wupeiqi

    8. __getitem__、__setitem___、__delitem__
    用于索引操作,如字典。以上分别表示获取、设置、删除数据
    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'] = 'wupeiqi' #自动触发执行 __setitem__
    del obj['k1'] #自动触发执行 __delitem__

    9. __getslice__、__setslice__、__delslice__
    该三个方法用于分片操作,如:列表
    class Foo(object):
    def __getslice__(self, i, j):
    print('__getslice__',i,j)

    def __setslice__(self, i, j, sequence):
    print('__setslice__',i,j)

    def __delslice_(self, i, j):
    print('__delslice__', i, j)

    obj = Foo()
    obj[-1:1] # 自动触发执行 __getslice__
    obj[0:1] = [11,22,33,44] # 自动触发执行 __setslice__
    del obj[0:2] # 自动触发执行 __delslice__

    10. __iter__
    用于迭代器,之所以列表、字典、元祖可以进行for循环,是因为类型内部定义了 __iter__

    第一步:
    class Foo(object):
    pass

    obj = Foo()
    for i in obj:
    print(i) # TypeError: 'Foo' object is not iterable

    第二步:
    class Foo(object):
    def __iter__(self):
    pass

    obj = Foo()
    for i in obj:
    print(i) #iter() returned non-iterator of type 'NoneType'

    第三步:
    class Foo(object):
    def __init__(self, sq):
    self.sq = sq
    def __iter__(self):
    return iter(self.sq)
    obj = Foo([11,22,33,44])
    for i in obj:
    print(i)
    以上步骤可以看出,for循环迭代的其实是iter([11,22,33,44]),所以执行流程可以变更为:
    obj = iter([11,22,33,44])
    for i in obj:
    print(i)
    For循环语法内部
    obj = iter([11,22,33,44])
    while True:
    val = obj.next()
    print(val)

    11. __new__和__metaclass__
    阅读以下代码:
    class Foo(object):
    def __init__(self):
    pass
    obj = Foo() # obj 是通过Foo类实例化的对象

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

    如果按照一切事物都是对象的理论:obj对象是通过执行Foo类的构造方法创建,那么Foo类对象应该也是通过执行某个类的构造方法创建。
    print type(obj) # 输出:<class '__main__.Foo'> 表示,obj 对象由Foo类创建
    print type(Foo) # 输出:<type 'type'> 表示,Foo类对象由 type 类创建
    所以,obj对象是Foo类的一个实例,Foo类对象是type类的一个实例,即:Foo类对象是通过type类的构造方法创建。

    那么,创建类就可以有两种方式:
    a).普通方式
    class Foo(object):
    def func(self):
    print('hello wupeiqi')

    b).特殊方式(type类的构造函数)
    def func(self):
    print('hello wupeiqi')

    Foo = type('Foo', (object,), {'func':func})
    # type第一个参数:类名
    # type第二个参数:当前类的基类
    # type第三个参数:类的成员

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

    答:类中有一个属性__metaclass__,其用来表示该类由谁来实例化创建,所以,我们可以为__metaclass__设置一个type类的派生类
    ,从而查看类创建的过程。
  • 相关阅读:
    Android——继续深造——从安装Android Studio 2.0开始(详)
    PHP——安装wampserver丢失MSVCR110.dll
    Marza Gift for GDC 2016
    Retrieve OpenGL Context from Qt 5.5 on OSX
    Space Time Varying Color Palette
    Screen Space Depth Varying Glow based on Heat Diffusion
    Visualization of Detail Point Set by Local Algebraic Sphere Fitting
    Glass Dragon
    Jump Flood Algorithms for Centroidal Voronoi Tessellation
    京都之行
  • 原文地址:https://www.cnblogs.com/changha0/p/8031089.html
Copyright © 2011-2022 走看看