创建类和对象
面向对象编程是一种编程方式,此编程方式的落地需要使用 “类” 和 “对象” 来实现,所以,面向对象编程其实就是对 “类” 和 “对象” 的使用。
类就是一个模板,模板里可以包含多个函数,函数里实现一些功能
对象则是根据模板创建的实例,通过实例对象可以执行类中的函数
创建类:
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
私有变量会在代码生成之前被转换为长格式(变为公有)。转换机制是这样的:在变量前端插入类名,再在前端加入一个下划线字符。这就是所谓的私有变量轧压(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()
参考: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__

浙公网安备 33010602011771号