面向对象----类(十四)

面向对象是一种编程方式,此编程方式的实现是基于对类和对象的使用。
类是一个模板,模板中包装了多个“函数”供使用(可以讲多函数中公用的变量封装到对象中)。
对象,根据模板创建的实例(即对象),实例用于调用被包装在类中的函数。类是对象的定义 ,而实例是“ 真正的实物”,它存放了类中所定义的对象的具体信息。
面向对象三大特性:封装、继承和多态。

类的定义:

使用 class 语句来创建一个新类,class 之后为类的名称并以冒号结尾:

class ClassName:
   '类的帮助信息'   #类文档字符串
   class_suite    #类体

#类的帮助信息可以通过ClassName.__doc__查看。
#class_suite 由类成员,方法,数据属性组成。

实例

#!/usr/bin/python
# -*- coding: UTF-8 -*-
class Employee:
   '所有员工的基类'
   empCount = 0
 
   def __init__(self, name, salary):
      self.name = name
      self.salary = salary
      Employee.empCount += 1
   
   def displayCount(self):
     print "Total Employee %d" % Employee.empCount
 
   def displayEmployee(self):
      print "Name : ", self.name,  ", Salary: ", self.salary
      
#empCount 变量是一个类变量,它的值将在这个类的所有实例之间共享。你可以在内部类或外部类使用 Employee.empCount 访问。
#第一种方法__init__()方法是一种特殊的方法,被称为类的构造函数或初始化方法,当创建了这个类的实例时就会调用该方法
#self 代表类的实例,self 在定义类的方法时是必须有的,虽然在调用时不必传入相应的参数。

self代表类的实例,而非类
类的方法与普通的函数只有一个特别的区别——它们必须有一个额外的第一个参数名称, 按照惯例它的名称是 self。

class Test:
    def prt(self):
        print(self)
        print(self.__class__)
 
t = Test()
t.prt()
#以上实例执行结果为:
#<__main__.Test instance at 0x10d066878>
#__main__.Test

#从执行结果可以很明显的看出,self 代表的是类的实例,代表当前对象的地址,而 self.__class__ 则指向类。
#self 不是 python 关键字,我们把他换成 runoob 也是可以正常执行的:

class Test:
    def prt(runoob):
        print(runoob)
        print(runoob.__class__)
t = Test()
t.prt()

#以上实例执行结果为:
#<__main__.Test instance at 0x10d066878>
#__main__.Test
''' 创建实例对象
实例化类其他编程语言中一般用关键字 new,但是在 Python 中并没有这个关键字,类的实例化类似函数调用方式。
以下使用类的名称 Employee 来实例化,并通过 __init__ 方法接收参数。'''

#"创建 Employee 类的第一个对象"
emp1 = Employee("Zara", 2000)
#"创建 Employee 类的第二个对象"
emp2 = Employee("Manni", 5000)

''' 访问属性
您可以使用点号 . 来访问对象的属性。使用如下类的名称访问类变量:'''

emp1.displayEmployee()
emp2.displayEmployee()
print "Total Employee %d" % Employee.empCount

''' 可以使用以下函数的方式来访问属性:
getattr(obj, name[, default]) : 访问对象的属性。
hasattr(obj,name) : 检查是否存在一个属性。
setattr(obj,name,value) : 设置一个属性。如果属性不存在,会创建一个新属性。
delattr(obj, name) : 删除属性。'''

类的成员

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

#coding=utf-8
class Province:
    # 静态字段
    country = '中国'
    def __init__(self, name):
        # 普通字段
        self.name = name
# 直接访问普通字段
obj = Province('河北省')
print(obj.name)
# 直接访问静态字段
print(Province.country)

'''
由上述代码可以看出【普通字段需要通过对象来访问】【静态字段通过类访问】,在使用上可以看出普通字段和静态字段的归属是不同的。其静态字段在内存中只保存一份,普通字段在每个对象中都要保存一份。
应用场景: 通过类创建对象时,如果每个对象都具有相同的字段,那么就使用静态字段。
'''
字段

2、类的方法包括实例方法、类方法、静态方法。

class Foo(object):  
    def test(self)://定义了实例方法  
        print("object")  
    @classmethod  
    def test2(clss)://定义了类方法  
        print("class")  
    @staticmethod  
    def test3()://定义了静态方法  
        print("static")  
方法
#coding=utf-8
class Apple:
    def fun1(self):
        return 'normal'
    @staticmethod
    def fun2():
        return 'staticmethod'
    @classmethod
    def fun3(cls):
        return 'classmethod'
print Apple.fun1
print Apple.fun2
print Apple.fun3
print "-"*80

apple = Apple()
print apple.fun1
print apple.fun2
print apple.fun3
print "-"*80

apple1 = Apple()
print apple1.fun1
print apple1.fun2
print apple1.fun3

'''
输出结果:
1、<unbound method Apple.fun1>
2、<function fun2 at 0x00000000022FC4A8>
3、<bound method classobj.fun3 of <class __main__.Apple at 0x0000000001E7C768>>
4、----------------------------------------------------------------------------
5、<bound method Apple.fun1 of <__main__.Apple instance at 0x00000000022FAE08>>
6、<function fun2 at 0x00000000022FC4A8>
7、<bound method classobj.fun3 of <class __main__.Apple at 0x0000000001E7C768>>
8、----------------------------------------------------------------------------
9、 <bound method Apple.fun1 of <__main__.Apple instance at 0x00000000022FAE48>>
10、<function fun2 at 0x00000000022FC4A8>
11、<bound method classobj.fun3 of <class __main__.Apple at 0x0000000001E7C768>>
--------------------- ------------------------------------------------------
'''

'''
解析:
1、普通方法传入的第一个参数必须是self(当然也可以不用self,官方要求尽量用self),self是指实例对象本身;
2、静态方法无需传参;
3、类方法传入的第一个参数必须是class,是指类本身。
对比结果1,5,9行: 
fun1通过class调用时,它是未绑定的方法,而实例化apple和apple1之后,它属于绑定的方法,且实例化后的apple和apple1内存地址不同,因为它们属于不同的实例对象。
对比结果2,6,10行: 
静态方法fun2通过class调用或者通过实例化后的对象调用,是没有任何区别的,全部都是指向同一块内存地址。可以简单的理解成静态方法与类或者实例没有任何关系,一旦调用后,它的内存地址即确定。
对比结果3,7,11行: 
类方法fun3通过class调用或者通过实例化后的对象调用,是没有任何区别的,全部都是指向同一块内存地址。为什么?因为实例化对象apple和apple1调用类方法fun3传入的第一个参数是类本身Apple,也就是说apple.fun3 = apple1.fun3 = Apple.fun3。

区别总结:
1、静态方法装饰器下定义的方法属于函数(function);
2、类方法装饰器下定义的方法属于方法(method);
3、静态方法无需传入任何参数;
4、类方法传入的第一个参数必须是class本身cls;
5、静态方法与类方法一旦被调用,内存地址即确定。通过类调用和通过实例化对象调用的结果完全一样。
6、三种方法从不同层次上来对方法进行了描述:实例方法针对的是实例,类方法针对的是类,他们都可以继承和重新定义,而静态方法则不能继承,可以认为是全局函数
'''
实例解析

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

#coding=utf-8
# ############### 定义 ###############
class Foo:
    def func(self):
        pass
    # 定义属性
    @property
    def prop(self):
        pass
# ############### 调用 ###############
foo_obj = Foo()
foo_obj.func()
foo_obj.prop   #调用属性

'''
由属性的定义和调用要注意一下几点:
定义时,在普通方法的基础上添加 @property 装饰器;
定义时,属性仅有一个self参数
调用时,无需括号
           方法:foo_obj.func()
           属性:foo_obj.prop
注意:属性存在意义是:访问属性时可以制造出和访问字段完全相同的假象
        属性由方法变种而来,如果Python中没有属性,方法完全可以代替其功能
'''
属性

类的作用域

类的参数

嵌套类

类的继承

类的多态

猜你喜欢

转载自www.cnblogs.com/windyrainy/p/10654862.html