码迷,mamicode.com
首页 > 编程语言 > 详细

python类

时间:2016-10-01 21:49:18      阅读:374      评论:0      收藏:0      [点我收藏+]

标签:

1、基本语法

  class class_name(base_class):  base_class是它继承的父类

    class_var

    def methods(self,args):

      statements

 

  经典类、新式类

  版本2和版本3的区别,3都是新式类

 

  经典类和新式类的区别:

    1__slots__,

    新式类里有这个,‘槽’的意思,对属性的一个限制,只能访问槽里边的属性。

    2)继承顺序,super

    3__new__,

    4)__getattribute__

    技术分享

    技术分享

      因为Python是动态的,所以可以随便往里边添加属性,但是如果有了槽之后,即有了__slots__之后,只能添加槽里边有的东西。

      三个引号包括的内容在help帮助里边会显示。

      我们写程序的时候尽量用新式类。

2、属性和封装

  实例属性和类属性

class Car(object):
    country=u’中国’
    def __init__(self,length,width,height,owner=None):
        self.owner=owner
        self.length=length
        self.width=width
        self.height=heigth                            

  实例属性一般定义再__init__里边,比如上边的self.owner,self.length,self.width,self.height。类属性一般定义在方法外边,比如上边的country属性。

 

  技术分享

 

 

  当我们调用a.country时,先去实例属性中找,如果有,就用实例属性的,如果没有就找类属性的。当我们用Car.country的时候,我们调用的类属性。

  当我们把acountry删除之后,a的在实例属性中找不到,就会到类属性中找。而bcountry没有删除,所以直接就用实例属性中的country

 

 

  私有属性

 

    不能直接访问。对类自己可见,对外不可见的。

 

    目的:保证赋值的合理性。

 

    两种做法:

 

      __xxx  两个下划线,不能直接访问到,但可以间接访问到

 

      _xxx  一个下划线,可以直接访问到

 

      __xxx__    两边都有两个下划线,这是系统自带的属性。

 

 

#coding:utf-8
class Car(object):
    country=u中国
    def __init__(self,length,width,height,owner=None):
        self.__owner=owner

        assert length>0 ,length must larger than 0
        self._length=length
        self._width=width
        self._height=height
        self._country=China

    def getOwner(self):
        return self.__owner
    def setOwner(self):
        self.owner=value
    def getLength(self):
        return self.__length

    def setLength(self,value):
        assert value>0 ,value must larger than 0

if __name__==__main__:
    a=Car(1.2,1.4,1.5,u黑板课)
    print a.getOwner()
    

 

  装饰器描述符

    描述符——定义了getset的一个对象。

    编程描述符有什么好处:像取属性一样操作方法,把方法当做属性去访问。

    a.setlength(-1)  这是直接用getset方法定义的方法

    a.length=-1   这是用描述符实现的

    用法:

    技术分享

 

    @property   get方法

    @owner.setter   set方法

    @owner.deleter   delete方法

    但是出现了一个新的问题,造成了代码的冗余。

 

 

    __getattr__ ——特殊方法

      自动调用

      当访问一个属性,访问不到时,它会自动调用。

    __setattr__

      给属性赋值的时候自动调用

    __delattr__

      删除属性的时候自动调用

 

    技术分享

    (需要把程序里边的__slot__修改成__slots__

    我们可以看到,我们只是产生了一个a,然后赋值的时候全部都调用了__setattr__,

    而且我们可以在这个地方对我们要赋的值就行判断,这样就免除了在每一次赋值的时候 都要判断的麻烦。

    如果我们用__slot__之后,就不会有__dict__这个东西了,就意味着无法再往里边添加__slot__以外的属性了,但是当我们把__dict__这个东西加进__slot__之后,我们,我们依然可以添

    加__slot__以外的属性。比如上边的例子a.name这个属性。

    技术分享

    当我们调用a.mm的时候,因为不存在这个属性,所以会自动调用__getattr__

    这样我们就通过这些解决了,我们在设置属性时要对属性进行判断的一个过程。

    但是我们为什么要用__slots____dict__一起来配合使用呢?(写到这里才发现上边写错了,是__slots__而不是__slot__)

    在__slots__里边加上__dict__之后,无法限制对属性的访问。如果没有slots的话,只有没有的属性才会调用__getattr__,有的属性就不会调用。而如果加上__slots__的话,slots里边有

    的也会调用__getattr__

 

    技术分享

 

    但是这样也会有新的问题出现,如何控制对属性的赋值呢,可以用下边的方法:

    技术分享

 

 

    大多数的时候,我们是这么用__getattr__的,,比如getattr(a,’length’)是在我们运行程序的时候才决定我们要访问哪一个属性。

    描述符

    非数据描述符定义了一个函数:__get__

    数据描述符定义连个函数:__get__    __set__

 

    描述符可以用作描述类的属性的这样的一个东西。当你定义了__get__    __set__,之后,这个类就可以作为另一个类的属性。

    举例:

 

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#copyRight by heibanke

class PositiveNum(object):
    def __init__(self,value):
        self.val = value
 
    def __get__(self, instance, owner):
        # instance = a,b
        # owner = Car
        print "__get__",instance,owner
        return self.val
 
    def __set__(self, instance, value):
        # instance = a,b
        print "__set__",instance,value
        try:
            assert int(value)>0
            self.val = value
        except AssertionError:
            print "ERROR: "+str(value)+" is not positive number."
        except:
            print "ERROR: "+str(value)+" is not number value."  
            
    def __delete__(self,instance):
        print "__delete__",instance
        self.val = None

    #def __getattribute__(self,name):
        #print self, name
        
class Car(object):
    country = u中国
    length = PositiveNum(0)
    width = PositiveNum(0)
    height = PositiveNum(0)
    #__slots__=(‘owner‘,‘length‘,‘width‘,‘height‘)
    
    def __init__(self, length, width, height, owner=None):
        self.owner = owner
        self.length = length
        self.width = width
        self.height = height
        


if __name__ == __main__:
    a = Car(1.2,1.4,1.5,u黑板客)
    b = Car(2.2,2.4,2.5,u小明)

    技术分享

 

 

    这样有一个好处,就是我们在对他进行初始化的时候,也把也进入了__init__里边对值进行了判断,免除了前边讲的冗余的问题。但是从运行结果上看,我们知道a.length

  b.length是一样的,为什么呢?因为length是个类属性。我们上边定义的那个类PositiveNum,里边有__set____get__函数,所以它不再是一个实例变量而是一个类变量。

 

 

    怎么解决这个问题呢?

 

    针对类修改PositiveNum

class PositiveNum(object):
    def __init__(self):
        self.default = 1
        self.data = {}
 
    def __get__(self, instance, owner):
        # instance = x
        # owner = type(x)
        print "__get__",instance,owner
        return self.data.get(instance, self.default)
 
    def __set__(self, instance, value):
        # instance = x
        print "__set__",instance,value
        try:
            assert int(value)>0
            self.data[instance] = value
        except AssertionError:
            print "ERROR: "+str(value)+" is not positive number."
        except:
            print "ERROR: "+str(value)+" is not number value."
            
    def __delete__(self,instance):
        print "__delete__",instance
        del self.data[instance]

    实际上data是一个字典,我们针对不同的instance进行输出。但是也有一个问题,这个时候我们可以对a.x这样的属性进行赋值,实际上我们不想这样的,怎么办呢?我们可以在Car类里

  边加上__slots__进行限制。

 

 

    另外新式类里边多了一个__attribute__的描述符。在访问属性的时候就会被调用,所以调用的时机比较多。一般来说我们很少用的,如果改变了它,会考虑很多情况,因为许多情况

  它都会被调用的。

 

 

  方法

 

    分类   

 

      类方法   @classmethod

 

      实例方法

 

      静态方法  @staticmethod

 

      特殊方法(魔法方法)  __init__

 

    

 

 

 

      方法和函数的区别:

 

        形式上的区别:

          1、调用是通过类和实例进行的,不能直接调用

 

          2、有自己的特殊参数 self   cls

          3、有自己的声明语法@classmethod  @staticmethod  __xx__

 

          实质的区别:——绑定

 

          类方法——绑定类

 

          实例方法——绑定实例

 

          静态方法——无绑定

 

          特殊方法——在某些场合自动调用

 

 

 

        静态方法和实例方法的区别主要体现在两个方面:

 

          1. 在外部调用静态方法时,可以使用"类名.方法名"的方式,也可以使用"对象名.方法名"的方式。而实例方法只有后面这种方式。也就是说,调用静态方法可以无需创建对

        象。

 

          2. 静态方法在访问本类的成员时,只允许访问静态成员(即静态成员变量和静态方法),而不允许访问实例成员变量和实例方法;实例方法则无此限制。

 

          3. 类方法可以被对象调用,也可以被实例调用;传入的都是类对象,主要用于工厂方法,具体的实现就交给子类处理

 

          4. 静态方法参数没有实例参数 self, 也就不能调用实例参数

 

#!/usr/bin/env python
# coding: utf-8
# http://stackoverflow.com/questions/12179271/python-classmethod-and-staticmethod-for-beginner

class Date(object):
    #self 作为实例参数
    def __init__(self, day=0, month=0, year=0):
        self.day = day
        self.month = month
        self.year = year
        
    def __str__(self):
        return "{0}-{1}-{2}".format(self.year, self.month, self.day)

   # cls作为类方法的参数
    @classmethod
    def from_string(cls, date_as_string):
        year, month, day = map(int, date_as_string.split(-))
        date1 = cls(day, month, year)
        return date1

    #静态方法,用类还是用
    @staticmethod
    def is_date_valid(date_as_string):
        year, month, day = map(int, date_as_string.split(-))
        return day <= 31 and month <= 12 and year <= 3999  

    @staticmethod
    def millenium(month, day):
        return Date(month, day, 2000) 
        
        
class DateTime(Date):

    #特殊方法,当我们print一个类的时候,按照__str__的方式显示出来
    def __str__(self):
        return "{0}-{1}-{2} - 00:00:00PM".format(self.year, self.month, self.day)  

            
if __name__=="__main__":
    
    s=2012-09-11
    if Date.is_date_valid(s):
        date1 = Date.from_string(2012-09-11)
        print date1
        date2 = DateTime.from_string(2012-09-11)
        print date2
        
    millenium_new_year1 = Date.millenium(1, 1)
    print millenium_new_year1
    
    millenium_new_year2 = DateTime.millenium(10, 10)
    print millenium_new_year2

 

 

    特殊方法

      属性访问:__getattr__,__setattr__,__getattribute__

      实例生成/类生成:__init__,__new__

      数字计算:__add__,__sub__,__mul__,__div__,__pow__,__round__

      调用方法:__str__,__repr__,__lent__,__bool__

      比较大小:__cmp__,__lt__,__le__,__eq__,__ne__,__gt__,__ge__

      集合访问:__setslice__,__getslice__,__getitem__,__setitem__,__contains__

      迭代器: __iter__,__next__

      技术分享

 

       技术分享

 

 

4、继承和组合

  继承——简单例子

  技术分享

 

  多重继承

  技术分享

  技术分享

  为什么会是这样呢?

  技术分享

 

 

  我们导入inspect来查看一下D优先继承哪些类。

 

  mro:method resolution order

    经典类(classic)是深度优先

    新式类(new)是广度优先

 

    技术分享

    由于我们定义的是经典类,所以D先继承了B,然后继承A,然后继承C。(深度优先)

    经典类和新式类的区别:

      经典类定义A的时候

        技术分享

      新式类定义A的时候

        技术分享

    super继承

      当我们有多重继承的时候,会导致父类别多次调用了。

       技术分享

 

      技术分享

 

      为了解决这个问题,在新式类中我们引进了super关键字,避免父类的多次调用。

 

      技术分享

 

      super是一个类,不是一个函数,调用规则:

      super(D,self).test()

 

    组合:

      把已有的类变成新的类属性。

      通过已有的类生成新类。

       技术分享

5、多态

  多态是不同的类的相同的方法,相同的参数,不同功能。调用时便于将一组对象放在集合里,无需判断对象的具体类型,统一调用。

  里氏代换原则:

    父类出现的地方,子类一定可以出现,反之不一定。

  重载:相同的方法的不同的参数。对应Pythonargskwargs

  最典型的是运算符重载。

 

6、元编程——比较难,但是大部分不会用到它。

  元(meta

  语法——》语句

  类——》对象

  元类——》类

  元类就是生成类的类。通过元类来编程就是元编程。

 

  元编程——type

    type(name,bases,attrs)

    name:类名字符串

    bases:父类元组

    attrs:属性字典

 

    A=type(‘A’,(object,),{‘b’:1})

    a=A()

    print A, a.b

 

      c++python的类的概念是不一样的。c++的类就是语法,编译的时候类并没有生成,只是在语法上限制了一些东西。而Python是一个对象,是可以生成出来的,比如上边的A,是

    通过编程序生成出来的。在Python里边可以通过元类生成类。

 

      技术分享

      但是这样的方式让人看起来不舒服,于是Python提供另外一种方法:

 

 

 

 

class simplemeta(type):
    def __init__(cls,name,bases,nmspc):
        super(simplemeta,cls).__init__(name,bases,nmspc)
        cls.uses_metaclass=lambda self:’yes’        


 

      写法1:

      A=simplemeta(‘A’,(),{})

      技术分享

      type也是一个类,类似于object类,type类里边的东西比object多一些。

 

     写法2

      class A(object):

        __metaclass__==simplemeta

      技术分享

      方法2中提供了__metaclass__的关键字,让我们很清楚的知道这就是一个元类。以后尽量用方法2来写。

 

      但是通过元类生成类和通过继承父类生成类有什么区别呢?

      元类和父类的区别:

        1、通过元类的初始化函数,或用metaclass关键字来生成新类

        2、通过继承父类来生成新类

 

      元类主要是定义类的行为,父类主要定义的是实例的行为。

 

  不可继承的类——最终类

class final(type):
    def __init__(cls,name,bases,namespace):
        super(final,cls).__init__(name,bases,namespace)
        for klass in bases:
            if isinstance(klass,final):
                raise TypeError(str(klass.__name__)+’is final’)                    

    当你想定义一个最终类的时候,加上这个元类就可以了。

    技术分享

      为什么?

      因为在finla类里边,有一些属性,因为Bfinal生成的,所以会在klaas里边,所以当我们运行的时候,isinstance会显示B是一个final,所以就raise TypeError(……)

 

 

      new的用途——新式类里边才会有的东西。

 

      __new____init__的区别:__new__是分配空间,__init__是配置参数,执行属性是先分配空间再配置参数。

 

      技术分享

 

 

      我们可以看到,第一个生成正整数没有成功,第二个成功了,为什么呢?

      因为__init__都已经配置好参数了,而对于int这种不可变的类型,你在对他改变是没有用的,而__new__只是分配好空间,没有产生什么值,所以就可以改变。

 

 

      单例模式中用__new__可以提前判断。

 

class singleton(object):
    def __new__(cls):
        if now hasattr(cls):
            cls.instance=super(singleton,cls).__new__(cls)
        return cls.instance        

 

      元类的用法

        抽象函数——虚函数,在子类里实现。

        class MyAbstractClass(object):

          def method1(self):

            raise NotImplementedError(‘please Implement this method’)

          但是这样用有一个问题:如果我们没有实现里边方法,当我们不用这个方法的时候,不会报错,只有当子类使用这个方法的时候才会报错,所以我们一般用下边的方法,

        导进来一个abs的类。

 

        接口,由一组抽象函数组成的类

 

        from abs import ABCMeta,abstractmethod

        from MyAbstractClass2(object):

          __metaclass__=ABCMeta

          @bastractmethod

          def method1(self):

            pass

 

          按照这么实现,即使子类没有调用这个方法,如果他没有实现这个方法,也会报错。

 

          技术分享

          注意看注释信息,报错的时机不一样的。

 

 

 

      元编程——ORM

        ORM:Object Relational Mapping对象关系映射

        将数据库的操作用面向对象的程序方法实现。

 

 

        技术分享

 

 

      匹配由ORM来产生,我们只要生成类进行操作就行了。

      好处:

        1、易改:便于更新数据库,sql语句是由底层根据数据库类型生成的上层数据模型无需变化。

        2、易用:便于对数据模型进行操作,创建,更新,查询,删除。用户编写简单,无需写sql语句即可操作数据。

        3、易看:使数据模型的程序文档化。便于维护。

      缺点:

        不灵活,没有sql语句强大等。

 

        class user(model);

 

          id=integerField(’uid’)

 

          name=stringField(‘username’)

 

          email=stringField(‘email’)

 

          password=stringField(‘password’)

 

          u=user(id=12345,name=Michael,email=test@orm.org,password=my_pwd)

          u.save()

          具体内容可参考廖雪峰老师的博客学习相关的知识。

 

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# http://www.liaoxuefeng.com/wiki/001374738125095c955c1e6d8bb493182103fac9270762a000/001386820064557c69858840b4c48d2b8411bc2ea9099ba000


 Simple ORM using metaclass 

__author__ = Michael Liao

class Field(object):
    def __init__(self, name, column_type):
        self.name = name
        self.column_type = column_type
    def __str__(self):
        return <%s:%s> % (self.__class__.__name__, self.name)

class StringField(Field):
    def __init__(self, name):
        super(StringField, self).__init__(name, varchar(100))

class IntegerField(Field):
    def __init__(self, name):
        super(IntegerField, self).__init__(name, bigint)

class ModelMetaclass(type):

    def __new__(cls, name, bases, attrs):
        print "name is ",name
        print "bases is ",bases
        print "attrs is ",attrs
        
        if name==Model:
            return type.__new__(cls, name, bases, attrs)
        print(Found model: %s % name)
        mappings = dict()
        for k, v in attrs.iteritems():
            if isinstance(v, Field):
                print(Found mapping: %s ==> %s % (k, v))
                mappings[k] = v
        for k in mappings.iterkeys():
            attrs.pop(k)
        attrs[__mappings__] = mappings # 保存属性和列的映射关系
        attrs[__table__] = name # 假设表名和类名一致
        return type.__new__(cls, name, bases, attrs)

class Model(dict):
    __metaclass__ = ModelMetaclass

    def __init__(self, **kw):
        print "Model instance __init__"
        super(Model, self).__init__(**kw)

    def save(self):
        fields = []
        params = []
        args = []
        for k, v in self.__mappings__.iteritems():
            fields.append(v.name)
            params.append(%s)
            args.append(self[k])
        sql = insert into %s (%s) values (%s) % (self.__table__, ,.join(fields), ,.join(params))
        print(SQL: %s % sql)
        print(ARGS: %s % str(args))

    @classmethod
    def find_all(cls, *args):


        sql = select * from %s % cls.__table__
        print(SQL: %s % sql)
# testing code:

class User(Model):
    id = IntegerField(uid)
    name = StringField(username)
    email = StringField(email)
    password = StringField(password)

    
u1 = User(id=12345, name=Michael, email=test1@orm.org, password=my-pwd)
u2 = User(id=22345, name=Richael, email=test2@orm.org, password=my-pwd)
u3 = User(id=32345, name=Hichael, email=test3@orm.org, password=my-pwd)

u1.save()
u2.save()
u3.save()

7wxpython

  技术分享

 

python类

标签:

原文地址:http://www.cnblogs.com/shixisheng/p/5926353.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!