记录我的成长吧~

创建类和对象

面向对象编程是一种编程方式,此编程方式的落地需要使用 “类” 和 “对象” 来实现,所以,面向对象编程其实就是对 “类” 和 “对象” 的使用。

  类就是一个模板,模板里可以包含多个函数,函数里实现一些功能

  对象则是根据模板创建的实例,通过实例对象可以执行类中的函数

创建类:
    class Person(object):
        pass
    类名以大写字母开头,object 表示该类从哪里个类继承下来的。
创建实例:
    xiaoming = Person()
    xiaohong = Person()
  • 面向对象:【创建对象】【通过对象执行方法】
  • 函数编程:【执行函数】

面向对象三大特性

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

一、封装

对于面向对象的封装来说,其实就是使用构造方法将内容封装到 对象 中,然后通过对象直接或者self间接获取被封装的内容。

什么时候会用到封装:

  • 多个方法共用一组变量,变量封装到对象
  • 通过一个Template创建多个对象

如何调用被封装的内容:

  • 通过对象直接调用
  • 通过self间接调用
class Person(object):
    def __init__(self,name,age,sex):
        self.name = name
        self.age = age
        self.sex = sex
    def say_name(self):
        return self.name
p1 = Person('abc',18,'man')
print p1.name   # 直接调用p1对象的name属性
print p1.say_name() #通过self间接调用被封装的内容

类和对象在内存中是如何保存?

 

二、继承

 对于面向对象的继承来说,其实就是将多个类共有的方法提取到父类中,子类仅需继承父类而不必一一实现每个方法。

继承,面向对象中的继承和现实生活中的继承相同,即:子可以继承父的内容

继承的中有两个类:

  •   基类:即父类
  •   派生类:即子类

 

class Animal:

    def eat(self):
        print "%s 吃 " %self.name
    def drink(self):
        print "%s 喝 " %self.name
    def shit(self):
        print "%s 拉 " %self.name
    def pee(self):
        print "%s 撒 " %self.name


class Cat(Animal):

    def __init__(self, name):
        self.name = name
        self.breed = ''

    def cry(self):
        print '喵喵叫'

class Dog(Animal):
    
    def __init__(self, name):
        self.name = name
        self.breed = ''
        
    def cry(self):
        print '汪汪叫'
        

# ######### 执行 #########

c1 = Cat('小白家的小黑猫')
c1.eat()

c2 = Cat('小黑的小白猫')
c2.drink()

d1 = Dog('胖子家的小瘦狗')
d1.eat()
继承实例

按发展历程划分类又分为两种:

  •   经典类
  •   新式类

函数式编程 --> 函数式面向对象(低级)经典类  --> 函数式面向对象(添加新功能)新式类

区别直观上看只是有无object,类只要是直接或者间接的继承都是新式类

多继承

1、Python的类可以继承多个类,Java和C#中则只能继承一个类

2、Python的类如果继承了多个类,那么其寻找方法的方式有两种,分别是:深度优先广度优先

  • 当类是经典类时,多继承情况下,会按照深度优先方式查找
  • 当类是新式类时,多继承情况下,会按照广度优先方式查找
"""新式类 广度优先"""
class D(object):
    def bar(self):
        print "D bar"
class C(D):
    def bar(self):
        print "C bar"
class B(D):
    pass
class A(B,C):
    pass

obj = A()
print obj.bar()

"""经典类 深度优先"""
class D:
    def bar(self):
        print "D bar"
class C(D):
    def bar(self):
        print "C bar"
class B(D):
    pass
class A(B,C):
    pass

obj = A()
print obj.bar()
多继承

三、多态

Pyhon不支持多态并且也用不到多态,多态的概念是应用于Java和C#这一类强类型语言中,而Python崇尚“鸭子类型”。

综上所述:

问题一:什么样的代码才是面向对象?
 
答:从简单来说,如果程序中的所有功能都是用 类 和 对象 来实现,那么就是面向对象编程了。
 
问题二:函数式编程 和 面向对象 如何选择?分别在什么情况下使用?
 
答:须知:对于 C# 和 Java 程序员来说不存在这个问题,因为该两门语言只支持面向对象编程(不支持函数式编程)。而对于 Python 和 PHP 等语言却同时支持两种编程方式,且函数式编程能完成的操作,面向对象都可以实现;而面向对象的能完成的操作,函数式编程不行(函数式编程无法实现面向对象的封装功能)。
 
所以,一般在Python开发中,全部使用面向对象 或 面向对象和函数式混合使用

 类的成员

注:所有成员中,只有普通字段的内容保存对象中,即:根据此类创建了多少对象,在内存中就有多少个普通字段。而其他的成员,则都是保存在类中,即:无论对象的多少,在内存中只创建一份。

一、字段

字段包括:普通字段和静态字段,他们在定义和使用中有所区别,而最本质的区别是内存中保存的位置不同,

  • 普通字段属于对象
  • 静态字段属于

什么时候用:

  普通字段:

    类中的法使用公共字段时,就要封装到普通字段里

  静态字段:

    通过类创建对象时,如果每个对象都具有相同的字段,那么就使用静态字段;例如:所有的省都属于中国

普通字段和静态字段的区别:

  • 静态字段在内存中只保存一份
  • 普通字段在每个对象中都要保存一份
"""字段"""
class Province(object):
    country = "ZH"  #静态字段
    def __init__(self,name):
        self.name = name #普通字段
    def sya(self):
        pass
shanxi = Province("shanxi")
print id(shanxi.country)
shanghai = Province("shanghai")
print id(shanghai.country)
#注意:对于静态字段,尽量用类访问
print Province.country
类成员之字段

  注意:为了明确区分调用时使用的是什么字段,须用明显区分的调用方式,如:静态字段只能通过类访问

二、方法

  • 普通方法:由对象调用;至少一个self参数;执行普通方法时,自动将调用该方法的对象赋值给self
  • 类方法:由调用; 至少一个cls参数;执行类方法时,自动将调用该方法的复制给cls
  • 静态方法:由调用;可以任意参数;

 什么时候使用:

  •   普通方法:对象调用
  •   静态方法:如果全部用的是面向对象编程静态方法会用到,类可以直接调用静态方法,避免了创建完类再创建对象调用的过程;避免了内存的浪费;实际上类+方法=函数;
  •   类方法:单例模式会用到;类方法相当于静态方法对类方法做了一个约束,把类当参数传进来。
"""方法"""
class Province(object):
    def __init__(self):
        pass

    def f1(self):#由对象触发,至少一个self参数
        #普通方法
        pass

    @classmethod
    def f2(cls):#只能有一个参数,只能是cls
        #类方法
        print cls
        pass
    
    @staticmethod
    def f3(): #参数可有可无
        pass

#普通方法的执行:
p1 = Province()

#类方法的执行:
Province.f2()
#指定结果
#   print cls =class
#    <class '__main__.Province'>
#   类触发函数时,会将自身传给f2

#静态方法执行
Province.f3()
类成员之方法

 

三、属性  

如果你已经了解Python类中的方法,那么属性就非常简单了,因为Python中的属性其实是普通方法的变种。

why:

  把方法伪造成字段

how:

  •   1、方法上加个@property,并且只能有一个self参数
  •   2、调用时无需括号

when:

  分页展示,pager类,按当前页起始位置请求数据库数据

# ############### 定义 ###############
class Pager(object):

    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(1)
print p.start #就是起始值,即:m
print p.end  # 就是结束值,即:n

#select * from table limit p.start,p.end
分页展示数据

属性的定义有两种方式:

  • 装饰器 即:在方法上应用装饰器
  • 静态字段 即:在类中定义值为property对象的静态字段

装饰器方式:在类的普通方法上应用@property装饰器

经典类

 

# ############### 定义 ###############    
class Goods:

    @property
    def price(self):
        return "wupeiqi"
# ############### 调用 ###############
obj = Goods()
result = obj.price  # 自动执行 @property 修饰的 price 方法,并获取方法的返回值
类成员之属性:经典类

 注意:Python WEB框架 Django 的视图中 request.POST 就是使用的静态字段的方式创建的属性

新式类,具有三种@property装饰器

  细分属性:获取、修改、删除

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

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):
        del self.original_price
# ############### 调用 ###############
obj = Goods()

obj.price          # 自动执行 @property 修饰的 price 方法,并获取方法的返回值
print obj.price   #30.0
obj.price = 10    # 自动执行 @price.setter 修饰的 price 方法,并将  10 赋值给方法的参数
print obj.price  #8.0
del obj.price     # 自动执行 @price.deleter 修饰的 price 方法
print obj.price  # AttributeError: 'Goods' object has no attribute 'original_price
实例

静态字段方式,创建值为property对象的静态字段

  BAR = property(get_bar)

  装饰器的另一种表现形式而已

类成员的修饰符

类的所有成员在上一步骤中已经做了详细的介绍,对于每一个类的成员而言都有两种形式:

  • 公有成员,在任何地方都能访问
  • 私有成员,只有在类的内部才能方法

私有成员:

  • 定义方法:  __Class
  • 只能内部访问
  • 特殊的访问方式: 对象._类__成员

类的特殊成员

 

class A(object):
       def __init__(self):
              self.__private()
              self.public()
       def __private(self):
              print 'A.__private()'
       def public(self):
              print 'A.public()'
class B(A):
       def __private(self):
              print 'B.__private()'
       def public(self):
              print 'B.public()'
#b = B()
print '\n'.join(dir(A))
#print '\n'.join(dir(B))

##输出
#   _A__private
#   ...
#   __init__
#   public
View Code

私有变量会在代码生成之前被转换为长格式(变为公有)。转换机制是这样的:在变量前端插入类名,再在前端加入一个下划线字符。这就是所谓的私有变量轧压(Private name mangling)。如类 A里的__private标识符将被转换为_A__private,这就是上一节出现_A__private和__private消失的原因了。

一是因为轧压会使标识符变长,当超过255的时候,Python会切断,要注意因此引起的命名冲突。
二是当类名全部以下划线命名的时候,Python就不再执行轧压。如:
class ____(object):
   def __init__(self):
          self.__method()
   def __method(self):
          print '____.__method()'
>>> print '\n'.join(dir(____))
__class__
__delattr__
__dict__
__doc__
__getattribute__
__hash__
__init__
__method              # 没被轧压
__module__
__new__
__reduce__
__reduce_ex__
__repr__
__setattr__
__str__
__weakref__
>>> obj = ____()
____.__method()
>>> obj.__method()      # 可以外部调用
____.__method()
View Code

  参考:http://www.chengxuyuans.com/Python/67370.html

 

1. __doc__
  表示类的描述信息
 
2. __module__ 和  __class__ 
  __module__ 表示当前操作的对象在那个模块
  __class__     表示当前操作的对象的类是什么
  
3. __init__
  构造方法,通过类创建对象时,自动触发执行。
 
4. __del__
  析构方法,当对象在内存中被释放时,自动触发执行。
    注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,
  所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。
5. __call__   对象后面加括号,触发执行。 注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()() 6. __dict__   类或对象中的所有成员 7. __str__   如果一个类中定义了__str__方法,那么在打印 对象 时,默认输出该方法的返回值 8、__getitem__、__setitem__、__delitem__ 用于索引操作,如字典。以上分别表示获取、设置、删除数据 9、__getslice__、__setslice__、__delslice__ 该三个方法用于分片操作 10. __iter__ 用于迭代器,之所以列表、字典、元组可以进行for循环,是因为类型内部定义了 __iter__ 11. __new__ 和 __metaclass__

 

 

posted on 2015-12-11 20:36  徐长伟  阅读(149)  评论(0)    收藏  举报