• Python 抽象篇:面向对象之类的方法与属性


    概览:
    类成员之字段:

    -普通字段,保存在对象中,执行职能通过对象访问
    -静态字段,保存在类中,执行可以通过对象访问,也可以通过类访问
    类成员之方法:
    -普通方法,保存在类中,由对象来调用,self->对象
    -静态方法,保存在类中,由类直接调用
    -类方法,保存在类中,由类直接调用,cl->s当前类
    应用场景:
    如果对象中需要保存一些值,执行某功能时,需要使用对象中的值-->普通方法

    不需要任何对象中的值-->静态方法
    类成员之属性:property
    1.类成员之字段
    class Province:
        country = '中国'#静态字段,属于类,跟对象没有关系,从上之下执行
        def __init__(self,name):
            self.name=name#普通字段,属于对象,通过对象访问
            # sef.country='中国'
    
    henna=Province('河南')
    hebei=Province('河北')
    print(hebei.country) #中国
    print(Province.country) #中国
    print(hebei.name) #河北

    静态字段在内存中只保存一份

    普通字段在每个对象中都要保存一份

    应用场景: 通过类创建对象时,如果每个对象都具有相同的字段,那么就使用静态字段

    2.方法

    class Bar:
        def __init__(self,name,age):#self=z,name=greg,age=84
            self.n=name
            self.a=age
        def foo(self):
            print(self.n,self.a)
    z=Bar('greg',25)
    print(z.a)
    z.foo()

    创建方法

        构造方法,__init__(self,arg)

            obj = 类('a1')

      普通方法

            obj = 类(‘xxx’)

            obj.普通方法名()

         构造方法不同于其它方法之处在于:当一个对象被创建时,会立即调用构造方法,而且可以继承。

    # -*- coding: utf-8 -*-
    # 2017/12/3 13:50
    class Foo:
        def bar(self):#self是对象
            print('bar')
            print(self)#<__main__.Foo object at 0x000001E82A4D13C8>
        @staticmethod
        def sta():
            print('123')
    
        @staticmethod
        def stas(a1,a2):#静态方法self不必须
            print(a1,a2)
    
        @classmethod
        def classmd(cls):#cls是类名
            print('classmd')
            print(cls) #<class '__main__.Foo'>
    #普通方法
    obj=Foo()
    obj.bar() #bar
    Foo.bar(obj ) #bar
    #静态方法
    obj.sta() #123
    obj.classmd()
    Foo.sta() #123
    Foo.stas(1,2) #1,2
    Foo.classmd() 
    """
    bar
    <__main__.Foo object at 0x000001C83C765390>
    bar
    <__main__.Foo object at 0x000001C83C765390>
    123
    classmd
    <class '__main__.Foo'>
    123
    1 2
    classmd
    <class '__main__.Foo'>
    """

    普通方法:可以在实例化后直接调用,由对象调用;至少一个self参数;执行普通方法时,自动将调用该方法的对象赋值给self,self.调用实例变量或类变量

    类方法:由类调用; 实例也可调用,至少一个cls参数;执行类方法时,自动将调用该方法的类复制给cls;类方法和普通方法的区别是, 类方法只能访问类变量,不能访问实例变量

    静态方法:由类调用;实例也可调用,无默认参数;不可以访问实例变量或类变量的,一个不能访问实例变量和类变量的方法,其实相当于跟类本身已经没什么关系了,它与类唯一的关联就是需要通过类名来调用这个方法

    类变量定义在类的定义之后,实例变量则是以为self.开头,实例也能够访问类变量

    class Foo(object):
        val = 0
        valu=2
        def __init__(self):
            self.val = 1
    
    if __name__ == '__main__':
        foo = Foo()
        print(foo.val)#1
        print(foo.valu)#2
        print( Foo.val)#0

    没有init方式时

    class Foo(object):
        val = 0
        def __init__(self):
            pass
    if __name__ == '__main__':
        foo = Foo()
        print(foo.val)#0
        print( Foo.val)#0

    还可以通过以下方式访问类变量

    class Foo(object):
        val = 3
        def __init__(self):
            print(self.__class__.val)
    if __name__ == '__main__':
        foo = Foo() #3

    类方法可以访问类变量

    class Foo(object):
        val = 3
        def __init__(self):
            pass
    
        @classmethod
        def echo(cls):
            print(cls.val)
    if __name__ == '__main__':
        Foo.echo()#3

    3.属性

    新式类中的属性有三种访问方式,并分别对应了三个被@property、@方法名.setter、@方法名.deleter修饰的方法

    分别将三个方法定义为对同一个属性:获取、修改、删除

    class Foo:
        def __init__(self):
            self.name='a'
            self.name_list=['greg']
    
        def bar(self):
            print('bar')
    
        @property #属性
        def per(self):
            # print('124')
            del self.name_list[0]
            print(self.name_list)
            return 123
    
        @per.setter
        def per(self,val):
            print(val)
    
        @per.deleter
        def per(self):
            print(666)
    
    obj=Foo()
    obj.bar() #bar
    r=obj.per #[]
    print(r) #123
    obj.per=345 #345
    del obj.per #666

    property的构造方法中有个四个参数,分别叫做:fget,fset,fdel ,doc

    如果没有参数,产生的属性既不可读,也不可写

    如果有一个参数,说明是取值方法,产生的属性是只读的。

    第一个参数是方法名,调用 对象.属性 时自动触发执行方法

    第二个参数是方法名,调用 对象.属性 = XXX 时自动触发执行方法

    第三个参数是方法名,调用 del 对象.属性 时自动触发执行方法,用于删除特性的方法

    第四个参数是字符串,调用 对象.属性.__doc__ ,此参数是该属性的描述信息,即文档字符串

    class Foo:
        def f1(self):
            return 123
    
        def f2(self,v):
            print(v)
    
        def f3(self):
            print('del')
    
        # per=property(fget=f1)#等同于下面三句
        # @property
        # def per(self):
        #     return 123
    
        per = property(fget=f1,fset=f2,fdel=f3,doc='f4')
    obj=Foo()
    ret=obj.per
    print(ret)
    obj.per=12345
    del obj.per
    # print(obj.per.__doc__)

    4.类的私有(private)特性

    为了让方法或者特性变为 私有(从外部无法访问),只要在它的名字前面加上双下划线即可。

    • 公有成员,在任何地方都能访问
    • 私有成员,只有在类的内部才能方法
    class Secretive:
        def __inaccessible(self):
            print("你看不到我")
    
        def accessible(self):
            print("密码是:")
            self.__inaccessible()
    
    s=Secretive()
    # s.__inaccessible() #AttributeError: 'Secretive' object has no attribute '__inaccessible'
    s.accessible()
    # 密码是:
    # 你看不到我

    非要访问私有属性的话,可以通过 对象._类__属性名,比如Secretive._Secretive.__inaccessible

    特殊成员

    __init__()  构造方法  类()自动执行

    __call__() 对象()    类()()自动执行

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

    class Foo:
        def __init__(self):
            print('__init__')
    
        def __call__(self, *args, **kwargs):
            print('__call__')
    
    obj = Foo()  # 执行 __init__
    obj()  # 执行 __call__

    __str__             str()

    class Foo:
        def __init__(self,n,a):
            self.name=n
            self.age=a
        def __str__(self):
            return '%s-%s'%(self.name,self.age)
    obj=Foo('greg',89)
    print(obj) #print(str(obj)) str(obj)

    __int__             int(对象)

    class Foo:
        def __init__(self):
            pass
        def __int__(self):
            return 1111
        def __str__(self):
            return 'greg'
    obj=Foo()
    print(obj,type(obj))
    #int,对象,自动执行对象的__init__方法,并将返回值赋值给int对象
    
    r=int(obj)
    print(r)
    i=str(obj)
    print(i)

    __add__

    class Foo:
        def __init__(self,name,age):
            self.name=name
            self.age=age
        def __add__(self, other):
            self=obj1
            other=obj2
            # return self.age+other.age#37 <class 'int'>
            return Foo('tt',99)#<__main__.Foo object at 0x0000017B7E2FC9B0> <class '__main__.Foo'>
    
    obj1=Foo('greg',19)
    obj2=Foo('gregory',18)
    r=obj1+obj2#两个对象相加时,自动执行第一个对象的__add__,
    # 并且将第二个对象当做参数传递
    print(r,type(r))

    __dict__ 将对象中封装的所有内容通过字典的形式返回

    class Foo:
        def __init__(self,name,age):
            self.name=name
            self.age=age
        def show(self):
            return "%s-%s"%(self.name,self.age)
    
    obj=Foo('greg',18)
    print(obj.name) #greg
    b="name"
    print(obj.__dict__) #{'name': 'greg', 'age': 18}
    print(obj.__dict__['name'])#greg
    print(obj.__dict__[b])#greg

    __getitem__切片(slice类型)或者索引,返回与所给键对应的值

    __setitem__,按一定的方式存储于key相关的value

    __delitem__,删除和key相关的键

    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__,输出__getitem__ k1
    obj['k2'] = 'greg'  # 自动触发执行 __setitem__,输出__setitem__ k2 greg
    del obj['k1']  # 自动触发执行 __delitem__,输出__delitem__ k1

    __iter__

     # 如果类中有 __iter__ 方法,对象=》可迭代对象

                    # 对象.__iter__() 的返回值: 迭代器

                    # for 循环,迭代器,next

                    # for 循环,可迭代对象,对象.__iter__(),迭代器,next

                    # 1、执行li对象的类F类中的 __iter__方法,并获取其返回值

                    # 2、循环上一步中返回的对象

    class Foo:
        def __init__(self,name,age):
            self.name=name
            self.age=age
        def __iter__(self):
            return iter([11,22,33])
    
    li=Foo('greg',18)
    
    #如果类中由__iter__方法,对象—》可迭代对象
    #执行li对象的类Foo类中的__iter__方法
    #循环上一步中的返回的对象
    
    for i in li:
        print(i)

    __doc__

    class Foo:
        '描述'
        """ 描述类信息 """
        def func(self):
            pass
    print(Foo.__doc__)
    #输出:描述

    __module__ 和  __class__ 

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

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

    from A.B import C
    
    obj = C()
    print obj.__module__  # 输出A.B,即:输出模块
    print obj.__class__      # 输出 A.B.C,即:输出类

    __new__ 和 __metaclass__

    class Foo:
        def func(self):
            print(123)
            return 1
    
    def function(self):
        print(123)
    
    obj=Foo()
    print(type(obj))#<class '__main__.Foo'>
    print(type(Foo))#<class 'type'>
    #obj对象是Foo类的一个实例,Foo类对象是 type 类的一个实例,即:Foo类对象 是通过type类的构造方法创建
    
    Foo2=type('Foo2',(object,),{'func2':function})#声明一个类
    obj2=Foo2()
    obj2.func2()
    #type第一个参数:类名,type第二个参数:当前类的基类,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 Foo = type('Foo',(object,),{'func':func,'__init__':__init__})
     8 
     9 f = Foo("jack",22)
    10 f.func()
    加上构造方法

     类 是由 type 类实例化产生

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

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

    class MyType(type):
        def __init__(self,*args,**kwargs):
            #self=Foo类 self永远是类名
            print(123)
            pass
    
        def __call__(self, *args, **kwargs):
            #self=Foo
            print(456)
      
    
    class Foo(object,metaclass=MyType):#Foo是MyType的对象
        def __init__(self):
            print('Foo')
            pass
    
        def __new__(cls, *args, **kwargs):
            x=cls
            return x
    
        def func(self):
            print("hello world")
    
    obj=Foo() #加()是执行MyType的call方法,Foo里面要执行,要用call中的方法
    #call不会调用Foo中init方法
    结果:123
       456

    单下划线、双下划线、头尾双下划线说明:

    • __foo__: 定义的是特列方法,类似 __init__() 之类的。

    • _foo: 以单下划线开头的表示的是 protected 类型的变量,即保护类型只能允许其本身与子类进行访问,不能用于 from module import *

    • __foo: 双下划线的表示的是私有类型(private)的变量, 只能是允许这个类本身进行访问了。

  • 相关阅读:
    BestCoder 2nd Anniversary/HDU 5718 高精度 模拟
    FZU 2168 前缀和+dp递推
    poj 1088 记忆化搜索
    Codeforces Round #241 (Div. 2) B dp
    poj 3053 优先队列处理
    取消修改
    csv乱码
    iconv()
    cakephp中sql查询between
    虚拟机上linux与windows之间复制粘贴
  • 原文地址:https://www.cnblogs.com/ningxin18/p/7780913.html
Copyright © 2020-2023  润新知