一 Python简介

      Python是一个可移植的面向对象的脚本语言。

        Python虽然是一个脚本语言,但也是一个完全面向对象的语言。由于它设计之初把易用性做为非常重要的一个考量标准,所以用起来非常简洁,优美(语法非常灵活),所以使用Python可以快速地编写出可运行代码。与C/C++相比,Python程序的运行速度比较慢,一门语言既然能够生存下来,就有它自己的原因,Python语言也一样。当今的计算机处理速度已经很快,对某些任务来说,运行速度并不是首要考虑的因素。比如说为了实现数据库访问的自动化,需要做一个数据库访问的代码生成器,这是一个常见的任务,其中涉及编程的许多方面,包括字符串处理、数据库访问,可能还包括一个GUI系统。这个任务显然不太适合用C或者C++来编写,因为使用C/C++来开发虽然可以节省那么一点运行时间,但却浪费了大量的开发时间。所以,语言没有好不好之分,只有适合不适合之分。

Python是动态强类型语言。由于是动态语言,所以变量的类型不是用关键字显式指定,而是在运行时根据赋给它的值动态判断出来的。


      另外,Python也跟C++一样同时支持结构化编程和面向对象编程两种范式。  Python的特定总结如下:


      1. Python是面向对象的。它支持继承以及多重继承、多态、操作符重载等面向对象的概念。

      2. Python是可移植的。使用Python语言编写的程序通常无需修改就可以运行在多个平台上,这点与Java类似。但是Python也提供一些Plantform dependent的模块,使用这些模块的时候必须小心,因为他们是不可移植的。

      3. Python是解释性语言。准确地说,Python先把源程序编译成中间代码(类似于java和c#),然后解释执行。但要注意的是,编译过程对程序员来说是透明的(这又不同于java和c#)。

      4.Python是一门动态语言。它支持元数据编程;支持运行时编译、执行等现代语言的高级特征。这些都很难甚至无法在C/C++中实现。Python甚至允许你在运行的时候增加一个对象的成员!

      5. 一切都是对象!Python中对象的概念比其他语言丰富得多,比如类是一个对象,因此你可以在运行的时候使用它,而不像C++一样,类是编译时的对象。正因为这种原因,使得Python是高度动态的。

      6. 自动内存管理。像java一样,你无需管理你的代码所使用的内存。在C和C++的程序中,那是一场恶梦。

      7. 其他:Python可以使用c/c++的编写的组件,也可以把python代码嵌入到c/c++代码中执行。


二 类定义



首先看下面的例子






class ZZClass:
      classNum = 0
      def __init__(self):
          self.num = 1
           ZZClass.classNum += 1
           print ("ZZClass _init__ called.")


      def __del__(self):
           ZZClass.classNum -= 1;
           print ("ZZClass __del__ called.")

      def Hello(self):
           print("hello world!")
          self.PrintClassNum(10) #普通函数中可以调用静态函数


      def setNum(self,num):
          self.num = num

      def getNum(self):
          return self.num

      @staticmethod
      def PrintClassNum(num=100):
           print (ZZClass.classNum) #在静态方法中只能通过类名访问类变量
          #print classNum          #在静态方法中不能直接访问类变量
           #print self.num          #在静态方法中不能访问实例变量
          print num


     @classmethod
      def ClassMethod(cls):
          #print cls.num           #在类方法中不能直接访问实例变量
          print "class method."
           print cls.classNum       #在类方法中可以直接访问类变量


 myObj = ZZClass()
 myObj.Hello()
 ZZClass.PrintClassNum(10) #可以通过类名来访问静态方法
 myObj02  = ZZClass()
 myObj02.PrintClassNum()   #可以通过对象实例来访问静态方法
 print myObj.classNum      #可以通过对象实例来访问类变量
 print ZZClass.classNum    #可以通过类名来访问静态变量




 myObj.setNum(10)
 myObj02.setNum(20)
 print myObj.getNum()
 print myObj02.getNum()

 myObj02 = 0
 print ZZClass.PrintClassNum()

 print ZZClass.ClassMethod() #通过类调用类方法
 print myObj.ClassMethod()   #通过实例调用类方法


输出结果:




ZZClass _init__ called. 
 
hello world!
 
 
1
 
 
10
 
 
1
 
 
10
 
 
ZZClass _init__ called.
 
 
2
 
 
100
 
 
2
 
 
2
 
 
10
 
 
20
 
 
ZZClass __del__ called.
 
 
1
 
 
100
 
 
None
 
 
class method.
 
 
1
 
 
None
 
 
ZZClass __del__ called.









分析:



1.与C++相比,Python中 定义方法采用def关键字,在类中定义的方法至少会有一个参数,一般以名为'self'的变量作为该参数(用其他名称也可以),而且需要作为第一个参数,用于对对象的变量引用。类似c++的this指针,只不过在C++中this 指针是隐藏的,由编译器来处理。



2.函数调用和变量的访问使用"."而不是"->"访问。



3._init__类似于构造函数,在生成对象时调用,可以用来进行一些初始化操作,不需要显示去调用,系统会默认去执行。构造方法支持重载,如果用户自己没有重新定义构造方法,系统就自动执行默认的构造方法。



   __del__类似于析构函数。在释放对象时调用,支持重载,可以在里面进行一些释放资源的操作,不需要显示调用。



4.实例变量和类变量:num是实例变量,classNum是类变量。前者类似C++的成员变量,后者类似C++的类的静态变量。类变量是所有对象共享的,不需要对象,可以直接用“类名.变量名”访问,与C++一样,使用对象实例也可以访问类变量。实例变量是每个对象一个拷贝,只能通过对象访问,实例变量是不需要在类中显示定义的。



类变量可以通过类名和实例对象两种方式进行访问,通过类名修改类变量,该类和所有实例所共享的数据将被修改,再次通过类或实例访问得到的将是新的数据,这一点与C++是一致的。但是通过实例对象修改类变量,其效果将仅仅作用在该实例上,再次通过类或其它实例访问得到的仍然是旧的数据。但这一修改方式将对该类变量实例化,其结果是该实例将得到一个单独的该变量拷贝,此后此对象不再与类共享该名称的变量。(这一点Python有点复杂),看下面的例子:




class classA:
      classVar = ''
      def __init__(self):
           pass

      def set_var1(self,x):
           classA.classVar= x

      def set_var2(self,y):
          self.var2 = y
          return self.var2


      oa = classA()
      ob = classA()


 
oa.set_var1("class variable.")
 print oa.classVar     #class variable.
 print ob.classVar     #class variable.

 oa.classVar = "changed."
 print oa.classVar     #changed.
 print ob.classVar     #class variable.

 oa.set_var1("class variable01")
 print oa.classVar      #changed.
 print ob.classVar      #class variable01


 ob.set_var1("class variable02")
 print oa.classVar       #changed.
 print ob.classVar       #class variable02

 ob.set_var2("inst variable")
 print ob.var2
#print oa.var2          #error! because var2 is a instance variable





    如果需要在类外修改类属性,必须通过类对象去引用然后进行修改。如果通过实例对象去引用,会产生一个同名的实例属性,这种方式修改的是实例属性,不会影响到类属性,并且之后如果通过实例对象去引用该名称的属性,实例属性会强制屏蔽掉类属性,即引用的是实例属性,除非删除了该实例属性。






5.普通函数和静态函数:Hello是普通函数,PrintClassNum是静态函数。printClassCount()类似C++的静态函数。就像静态函数没有this指针一样,它也没有self变量。静态函数只能访问静态成员变量(类变量)。与C++一样,可以使用实例对象和类名来调用静态函数,只能使用实例变量来调用普通函数。



在类外普通函数(实例函数)只能通过实例对象去调用,不能通过其他方式去调用。






6.类函数和静态函数: ClassMethod是一个类方法,拥有一个参数(类对象)。与静态方法使用类似,他们都可以通过类和实例进行调用,都无法访问实例成员。类方法可以通过自己的参数cls访问类成员,而静态方法则不行,可以通过类名间接访问。 staticmethod无需参数,classmethod需要类变量作为参数传递(不是类的实例), 类函数还有一个用途就是可以对类属性进行修改。




7.变量访问属性:C++的面向对象的语法都比较的规范,有公有、私有和保护的数据类型,而python类是没有权限控制的,所有变量都是可以被外部调用,虽然我们可以在变量或者方法的面前加上双下滑线__,表示私有访问权限,其实在内部实现上,是将私有变量进行了转化,规则是:_<类名>__<私有变量>。但这个实际上是python的伪私有,只是一种程序员约定俗称的规定,加了双下划线就表示私有变量,但是如果要在外部调用的话,还是可以调用的。看下面的例子:




class Test:
      count =  0
      def __init__(self,c):
          self.count = c
          self.__name="zhangzhe"     #私有变量
          self.__class__.count = self.__class__.count +1

      def __get_name(self):           #私有方法
          return self.__name

      def get_counte(self):
          return self.count


 
a = Test(3)
 print a.count #3
#print a.name  #AttributeError:Test instance has no attribute 'name'
print Test.count #1
 print a.get_counte() #3

 print a.__dict__  #{'count': 3, '_Test__name': 'zhangzhe'}
 print a._Test__name  #zhangzhe 

 

 print Test.__dict__  
#{'count': 1, '__module__': 'classdemo02', '_Test__get_name': <function __get_name at 0x101e92500>, '__doc__': None, '__init__': <function __init__ at 0x101e92488>, 'get_counte': <function get_counte at 0x101e92578>}
 
 print a._Test__get_name()   #zhangzhe


 b = Test(-1)
 print b.count    #1
 print Test.count #2


         这里定义的__name是私有属性,__get_name()是私有方法,直接访问的话,会提示找不到相关的属性或者方法。可以通过使用 a._Test__name和a._Test__get_name()来访问私有的变量和方法。


         注:在Python中没有像C++中public和private这些关键字来区别公有属性和私有属性,它是以属性命名方式来区分,如果在属性名前面加了2个下划线'__',则表明该属性是私有属性,否则为公有属性




小结:


          对于类属性和实例属性,如果在类方法中引用某个属性,该属性必定是类属性,而如果在实例方法中引用某个属性(不作更改),并且存在同名的类属性,此时若实例对象有该名称的实例属性,则实例属性会屏蔽类属性,即引用的是实例属性,若实例对象没有该名称的实例属性,则引用的是类属性;如果在实例方法更改某个属性,并且存在同名的类属性,此时若实例对象有该名称的实例属性,则修改的是实例属性,若实例对象没有该名称的实例属性,则会创建一个同名称的实例属性。想要修改类属性,如果在类外,可以通过类对象修改,如果在类里面,只有在类方法中进行修改。


   从类方法和实例方法以及静态方法的定义形式就可以看出来,类方法的第一个参数是类对象cls,那么通过cls引用的必定是类对象的属性和方法;而实例方法的第一个参数是实例对象self,那么通过self引用的可能是类属性、也有可能是实例属性(这个需要具体分析),不过在存在相同名称的类属性和实例属性的情况下,实例属性优先级更高。静态方法中不需要额外定义参数,因此在静态方法中引用类属性的话,必须通过类对象来引用。





        从上面看来,Python是非常的灵活 的,它的面向对象没有做到真正的不能访问,只是一种约定让大家去遵守,就像大家都用self来代表在类里的当前对象,你也可以用其他的,只是大家习惯了用self。






三 类中的内置方法




     除了上面的init和del方法外,Python类中还有如下的多个内置方法(类似于C++中的运算符重载):


   




python只支持面向对象吗 python语言支持面向对象_类属性





1.__new__():__new__()在__init__()之前被调用,用于生成实例对象。利用这个方法和类属性的特性可以实现设计模式中的单例模式。单例模式是指创建唯一对象吗,单例模式设计的类只能实例化一个对象。例如下面的代码:

__instance = None
 
 
         if ZZClass.__instance is None:         #生产唯一实例
             print("ZZClass __new__ called.")
             ZZClass.__instance = object.__new__(cls,*args,**kwargs)
         return ZZClass.__instance

2. __getattr__()、__setattr__()和__getattribute__(): 当读取对象的某个属性时,python会自动调用__getattr__()方法。例如,fruit.color将转换为fruit.__getattr__(color)。当使用赋值语句对属性进行设置时,python会自动调用__setattr__()方法。__getattribute__()的功能与__getattr__()类似,用于获取属性的值。但是__getattribute__()能提供更好的控制,代码更健壮。注意,python中并不存在__setattribute__()方法 。



3.    __str__()用于表示对象代表的含义,返回一个字符串.实现了__str__()方法后,可以直接使用print语句输出对象,也可以通过函数str()触发__str__()的执行。这样就把对象和字符串关联起来,便于某些程序的实现,可以用这个字符串来表示某个类。


例如:

def __str__(self):
          return  "ZZClass itself."


4.  __call__(): 在类中实现__call__()方法,可以在对象创建时直接返回__call__()的内容。使用该方法可以模拟静态方法。


例如:

class InternalClass:
         def __call__(self, *args, **kwargs):
             print "internal class."

     func = InternalClass()     # 调用InternalClass(),此时将类InternalClass作为函数返回,
                                      # 即为外部类ZZClass定义方法func(),func()将执行__call__()内的代码。       
  
   
   myObj.func()  #internal class.   
      myObj.func()   
  # 
  internal class.


5. __getitem__(): 如果类把某个属性定义为序列,可以使用__getitem__()输出序列属性中的某个元素。



class Persons:
     def __getitem__(self, item):
         return self.persons[item]

 allPersons = Persons()
 allPersons.persons = ["Alice","Joe"]
 print allPersons[1]

补充:


强类型语言
        一种总是强制类型定义的语言,Java和Python是强制类型定义的,如果你有一个整数,不显示地进行转换,不能将其视为一个字符串。




弱类型定义语言
          一种类型可以被忽略的语言,与强类型定义相反。VBScript是弱类型定义 的。在VBScript中,可以将字符串 '12' 和整数 3 进行连接得到字符串 '123', 然后可以把它看成整数 123,而不需要显示转换。



        注意:强弱类型中心词是‘类型’,而不是变量,一个变量是否能够绑定到多种类型,跟该语言是否强弱类型无关。




动态联编


          编译程序在编译阶段并不能确切知道将要调用的函数,只有在程序运行时才能确定将要调用的函数,为此要确切知道该调用的函数,要求联编工作要在程序运行时进行,这种在程序运行时进行联编工作被称为动态联编。


       其实它不是 Python 的特性,所有面向对象的语言基本都需要实现。它使得执行一个对象的方法时,使用的是它自己(或它的类)的方法,而不是它的父类的方法。


       动态联编通常的实现方法是把函数的入口地址保存起放在一个表里,(例如,c++的虚表),在运行时通过动态的查找表的方式来判断应该调用哪个函数。函数的执行效率没有静态联编的高,但比其灵活。




 静态联编


         静态联编是指联编工作出现在编译连接阶段,这种联编又称早期联编,它在编译时就解决了程序中的操作调用与执行该操作代码间的关系。