zoukankan      html  css  js  c++  java
  • Python学习备忘录[转]

    来源:http://blog.csdn.net/nilxin/article/details/1613574

    类中的特殊方法

    一般说来,特殊的方法都被用来模仿某个行为。例如,如果你想要为你的类使用x[key]这样的索引操作(就像列表和元组一样),那么你只需要实现__getitem__()方法就可以了。想一下,Python就是对list类这样做的!

    下面这个表中列出了一些有用的特殊方法。如果你想要知道所有的特殊方法,你可以在《Python参考手册》中找到一个庞大的列表。

    名称                     说明
    ---------------------------------------------------------
    __init__(self,...)      这个方法在新建对象恰好要被返回使用之前被调用。
    __del__(self)           恰好在对象要被删除之前调用。
    __str__(self)           在我们对对象使用print语句或是使用str()的时候调用。
    __lt__(self,other)      当使用 小于 运算符(<)的时候调用。类似地,对于所有的运算符(+,>等等)都有特殊的方法。
    __getitem__(self,key)   使用x[key]索引操作符的时候调用。
    __len__(self)           对序列对象使用内建的len()函数的时候调用。
    __repr__(s)             repr() and `...` conversions
    __cmp__(s, o)           Compares s to o and returns <0, 0, or >0.
                            Implements >, <, == etc...
    __hash__(s)             Compute a 32 bit hash code; hash() and dictionary ops
    __nonzero__(s)          Returns 0 or 1 for truth value testing
    __getattr__(s, name)    called when attr lookup doesn't find <name>
    __setattr__(s, name, val) called when setting an attr
                            (inside, don't use "self.name = value"
                            use "self.__dict__[name] = val")
    __delattr__(s, name)    called to delete attr <name>
    __call__(self, *args)   called when an instance is called as function.

    exec和eval语句

    exec语句用来执行储存在字符串或文件中的Python语句。例如,我们可以在运行时生成一个包含Python代码的字符串,然后使用exec语句执行这些语句。
    下面是一个简单的例子。

    >>> exec 'print "Hello World"'
    Hello World

    eval语句用来计算存储在字符串中的有效Python表达式。下面是一个简单的例子。

    >>> eval('2*3')
    6

    assert语句

    assert语句用来声明某个条件是真的。例如,如果你非常确信某个你使用的列表中至少有一个元素,而你想要检验这一点,并且在它非真的时候引发一个错误,那么assert语句是应用在这种情形下的理想语句。当assert语句失败的时候,会引发一个AssertionError。

    >>> mylist = ['item']
    >>> assert len(mylist) >= 1
    >>> mylist.pop()
    'item'
    >>> assert len(mylist) >= 1
    Traceback (most recent call last):
      File "<stdin>", line 1, in ?
    AssertionError repr函数

    repr函数用来取得对象的规范字符串表示。反引号(也称转换符)可以完成相同的功能。注意,在大多数时候有eval(repr(object)) == object。

    >>> i = []
    >>> i.append('item')
    >>> `i`
    "['item']"
    >>> repr(i)
    "['item']"

    基本上,repr函数和反引号用来获取对象的可打印的表示形式。你可以通过定义类的__repr__方法来控制你的对象在被repr函数调用的时候返回的内容。

    类和实例变量

    有两种类型的域 —— 类的变量和对象的变量,它们根据是类还是对象拥有这个变量而区分。

    类的变量 由一个类的所有对象(实例)共享使用。只有一个类变量的拷贝,所以当某个对象对类的变量做了改动的时候,这个改动会反映到所有其他的实例上。

    对象的变量 由类的每个对象/实例拥有。因此每个对象有自己对这个域的一份拷贝,即它们不是共享的,在同一个类的不同实例中,虽然对象的变量有相同的名称,但是是互不相关的。通过一个例子会使这个易于理解。

    #!/usr/bin/python
    # Filename: objvar.py

    class Person:
        '''Represents a person.'''
        population = 0

        def __init__(self, name):
            '''Initializes the person's data.'''
            self.name = name
            print '(Initializing %s)' % self.name

            # When this person is created, he/she
            # adds to the population
            Person.population += 1

        def __del__(self):
            '''I am dying.'''
            print '%s says bye.' % self.name

            Person.population -= 1

            if Person.population == 0:
                print 'I am the last one.'
            else:
                print 'There are still %d people left.' % Person.population

        def sayHi(self):
            '''Greeting by the person.

            Really, that's all it does.'''
            print 'Hi, my name is %s.' % self.name

        def howMany(self):
            '''Prints the current population.'''
            if Person.population == 1:
                print 'I am the only person here.'
            else:
                print 'We have %d persons here.' % Person.population

    swaroop = Person('Swaroop')
    swaroop.sayHi()
    swaroop.howMany()

    kalam = Person('Abdul Kalam')
    kalam.sayHi()
    kalam.howMany()

    swaroop.sayHi()
    swaroop.howMany()输出

    ___FCKpd___5nbsp;python objvar.py
    (Initializing Swaroop)
    Hi, my name is Swaroop.
    I am the only person here.
    (Initializing Abdul Kalam)
    Hi, my name is Abdul Kalam.
    We have 2 persons here.
    Hi, my name is Swaroop.
    We have 2 persons here.
    Abdul Kalam says bye.
    There are still 1 people left.
    Swaroop says bye.
    I am the last one.

    这是一个很长的例子,但是它有助于说明类与对象的变量的本质。这里,population属于Person类,因此是一个类的变量。name变量属于对象(它使用self赋值)因此是对象的变量。

    观察可以发现__init__方法用一个名字来初始化Person实例。在这个方法中,我们让population增加1,这是因为我们增加了一个人。同样可以发现,self.name的值根据每个对象指定,这表明了它作为对象的变量的本质。

    记住,你只能使用self变量来参考同一个对象的变量和方法。这被称为 属性参考 。

    在这个程序中,我们还看到docstring对于类和方法同样有用。我们可以在运行时使用Person.__doc__和Person.sayHi.__doc__来分别访问类与方法的文档字符串。

    就如同__init__方法一样,还有一个特殊的方法__del__,它在对象消逝的时候被调用。对象消逝即对象不再被使用,它所占用的内存将返回给系统作它用。在这个方法里面,我们只是简单地把Person.population减1。

    当对象不再被使用时,__del__方法运行,但是很难保证这个方法究竟在什么时候运行。如果你想要指明它的运行,你就得使用del语句,就如同我们在以前的例子中使用的那样。

    给C++/Java/C#程序员的注释
    Python中所有的类成员(包括数据成员)都是公共的 ,所有的方法都是有效的。
    只有一个例外:如果你使用的数据成员名称以双下划线前缀 比如__privatevar,Python的名称管理体系会有效地把它作为私有变量。
    这样就有一个惯例,如果某个变量只想在类或对象中使用,就应该以单下划线前缀。而其他的名称都将作为公共的,可以被其他类/对象使用。记住这只是一个惯例,并不是Python所要求的(与双下划线前缀不同)。
    同样,注意__del__方法与destructor的概念类似。

    继承

    面向对象的编程带来的主要好处之一是代码的重用,实现这种重用的方法之一是通过继承机制。继承完全可以理解成类之间的类型和子类型关系。

    假设你想要写一个程序来记录学校之中的教师和学生情况。他们有一些共同属性,比如姓名、年龄和地址。他们也有专有的属性,比如教师的薪水、课程和假期,学生的成绩和学费。

    你可以为教师和学生建立两个独立的类来处理它们,但是这样做的话,如果要增加一个新的共有属性,就意味着要在这两个独立的类中都增加这个属性。这很快就会显得不实用。

    一个比较好的方法是创建一个共同的类称为SchoolMember然后让教师和学生的类继承 这个共同的类。即它们都是这个类型(类)的子类型,然后我们再为这些子类型添加专有的属性。

    使用这种方法有很多优点。如果我们增加/改变了SchoolMember中的任何功能,它会自动地反映到子类型之中。例如,你要为教师和学生都增加一个新的身份证域,那么你只需简单地把它加到SchoolMember类中。然而,在一个子类型之中做的改动不会影响到别的子类型。另外一个优点是你可以把教师和学生对象都作为SchoolMember对象来使用,这在某些场合特别有用,比如统计学校成员的人数。一个子类型在任何需要父类型的场合可以被替换成父类型,即对象可以被视作是父类的实例,这种现象被称为多态现象。

    另外,我们会发现在重用父类的代码的时候,我们无需在不同的类中重复它。而如果我们使用独立的类的话,我们就不得不这么做了。

    在上述的场合中,SchoolMember类被称为基本类或超类 。而Teacher和Student类被称为导出类或子类 。

    现在,我们将学习一个例子程序。
    使用继承

    #!/usr/bin/python
    # Filename: inherit.py

    class SchoolMember:
    '''Represents any school member.'''
    def __init__(self, name, age):
            self.name = name
            self.age = age
    print '(Initialized SchoolMember: %s)' % self.name

    def tell(self):
    '''Tell my details.'''
    print 'Name:"%s" Age:"%s"' % (self.name, self.age),

    class Teacher(SchoolMember):
    '''Represents a teacher.'''
    def __init__(self, name, age, salary):
            SchoolMember.__init__(self, name, age)
            self.salary = salary
    print '(Initialized Teacher: %s)' % self.name

    def tell(self):
            SchoolMember.tell(self)
    print 'Salary: "%d"' % self.salary

    class Student(SchoolMember):
    '''Represents a student.'''
    def __init__(self, name, age, marks):
            SchoolMember.__init__(self, name, age)
            self.marks = marks
    print '(Initialized Student: %s)' % self.name

    def tell(self):
            SchoolMember.tell(self)
    print 'Marks: "%d"' % self.marks

    t = Teacher('Mrs. Shrividya', 40, 30000)
    s = Student('Swaroop', 22, 75)

    print # prints a blank line

    members = [t, s]
    for member in members:
        member.tell() # works for both Teachers and Students输出

    $ python inherit.py
    (Initialized SchoolMember: Mrs. Shrividya)
    (Initialized Teacher: Mrs. Shrividya)
    (Initialized SchoolMember: Swaroop)
    (Initialized Student: Swaroop)

    Name:"Mrs. Shrividya" Age:"40" Salary: "30000"
    Name:"Swaroop" Age:"22" Marks: "75"

    为了使用继承,我们把基本类的名称作为一个元组跟在定义类时的类名称之后。然后,我们注意到基本类的__init__方法专门使用self变量调用,这样我们就可以初始化对象的基本类部分。这一点十分重要——Python不会自动调用基本类的constructor,你得亲自专门调用它。

    我们还观察到我们在方法调用之前加上类名称前缀,然后把self变量及其他参数传递给它。

    注意,在我们使用SchoolMember类的tell方法的时候,我们把Teacher和Student的实例仅仅作为SchoolMember的实例。

    另外,在这个例子中,我们调用了子类型的tell方法,而不是SchoolMember类的tell方法。可以这样来理解,Python总是首先查找对应类型的方法,在这个例子中就是如此。如果它不能在导出类中找到对应的方法,它才开始到基本类中逐个查找。基本类是在类定义的时候,在元组之中指明的。

    一个术语的注释——如果在继承元组中列了一个以上的类,那么它就被称作多重继承 。

    字符串

    字符串是字符的序列。字符串基本上就是一组单词。

    我几乎可以保证你在每个Python程序中都要用到字符串,所以请特别留心下面这部分的内容。下面告诉你如何在Python中使用字符串。

    * 使用单引号(')

    你可以用单引号指示字符串,就如同'Quote me on this'这样。所有的空白,即空格和制表符都照原样保留。
    * 使用双引号(")

    在双引号中的字符串与单引号中的字符串的使用完全相同,例如"What's your name?"。
    * 使用三引号('''或""")

    利用三引号,你可以指示一个多行的字符串。你可以在三引号中自由的使用单引号和双引号。例如:

    '''This is a multi-line string. This is the first line.
    This is the second line.
    "What's your name?," I asked.
    He said "Bond, James Bond."
    '''

    * 转义符

    假设你想要在一个字符串中包含一个单引号('),那么你该怎么指示这个字符串?例如,这个字符串是What's your name?。你肯定不会用'What's your name?'来指示它,因为Python会弄不明白这个字符串从何处开始,何处结束。所以,你需要指明单引号而不是字符串的结尾。可以通过 转义符 来完成这个任务。你用/'来指示单引号——注意这个反斜杠。现在你可以把字符串表示为'What/'s your name?'。

    另一个表示这个特别的字符串的方法是"What's your name?",即用双引号。类似地,要在双引号字符串中使用双引号本身的时候,也可以借助于转义符。另外,你可以用转义符//来指示反斜杠本身。

    值得注意的一件事是,在一个字符串中,行末的单独一个反斜杠表示字符串在下一行继续,而不是开始一个新的行。例如:

    "This is the first sentence./
    This is the second sentence."

    等价于"This is the first sentence. This is the second sentence."
    * 自然字符串

    如果你想要指示某些不需要如转义符那样的特别处理的字符串,那么你需要指定一个自然字符串。自然字符串通过给字符串加上前缀r或R来指定。例如r"Newlines are indicated by /n"。
    * Unicode字符串

    Unicode是书写国际文本的标准方法。如果你想要用你的母语如北印度语或阿拉伯语写文本,那么你需要有一个支持Unicode的编辑器。类似地,Python允许你处理Unicode文本——你只需要在字符串前加上前缀u或U。例如,u"This is a Unicode string."。

    记住,在你处理文本文件的时候使用Unicode字符串,特别是当你知道这个文件含有用非英语的语言写的文本。
    * 字符串是不可变的

    这意味着一旦你创造了一个字符串,你就不能再改变它了。虽然这看起来像是一件坏事,但实际上它不是。我们将会在后面的程序中看到为什么我们说它不是一个缺点。
    * 按字面意义级连字符串

    如果你把两个字符串按字面意义相邻放着,他们会被Python自动级连。例如,'What/'s' 'your name?'会被自动转为"What's your name?"。

    给C/C++程序员的注释
    在Python中没有专门的char数据类型。确实没有需要有这个类型,我相信你不会为此而烦恼。

    给Perl/PHP程序员的注释
    记住,单引号和双引号字符串是完全相同的——它们没有在任何方面有不同。

    给正则表达式用户的注释
    一定要用自然字符串处理正则表达式。否则会需要使用很多的反斜杠。例如,后向引用符可以写成'//1'或r'/1'。

    私有变量

    Python对私有类成员有部分支持。任何象__spam这样形式的标识符(至少有两个前导下划线,至多有一个结尾下划线)目前被替换成_classname__spam,其中classname是所属类名去掉前导下划线的结果。这种搅乱不管标识符的语法位置,所以可以用来定义类私有的实例、变量、方法,以及全局变量,甚至于保存对于此类是私有的其它类的实例。如果搅乱的名字超过255个字符可能会发生截断。在类外面或类名只有下划线时不进行搅乱。

    名字搅乱的目的是给类一种定义“私有”实例变量和方法的简单方法,不需担心它的其它类会定义同名变量,也不怕类外的代码弄乱实例的变量。注意搅乱规则主要是为了避免偶然的错误,如果你一定想做的话仍然可以访问或修改私有变量。这甚至是有用的,比如调试程序要用到私有变量,这也是为什么这个漏洞没有堵上的一个原因。(小错误:导出类和基类取相同的名字就可以使用基类的私有变量)。

    注意传递给exec,eval()或evalfile()的代码不会认为调用它们的类的类名是当前类,这与global语句的情况类似,global的作用局限于一起字节编译的代码。同样的限制也适用于getattr() ,setattr()和delattr(),以及直接访问__dict__的时候。

    下面例子中的类实现了自己的__getattr__和__setattr__方法,把所有属性保存在一个私有变量中,这在Python的新旧版本中都是可行的:

    class VirtualAttributes:
        __vdict = None
        __vdict_name = locals().keys()[0]
        
        def __init__(self):
            self.__dict__[self.__vdict_name] = {}
       
        def __getattr__(self, name):
            return self.__vdict[name]
       
        def __setattr__(self, name, value):
            self.__vdict[name] = value

    参考资料:

    http://www.e7blog.com/blog/user1/python/
    http://www.czug.org/docs/python/TutorialCN/X_e7_ac_ac_e4_b9_9d_e7_ab_a0_e7_b1_bb/

  • 相关阅读:
    【数据结构】线性表&&顺序表详解和代码实例
    【智能算法】超详细的遗传算法(Genetic Algorithm)解析和TSP求解代码详解
    【智能算法】用模拟退火(SA, Simulated Annealing)算法解决旅行商问题 (TSP, Traveling Salesman Problem)
    【智能算法】迭代局部搜索(Iterated Local Search, ILS)详解
    10. js时间格式转换
    2. 解决svn working copy locked问题
    1. easyui tree 初始化的两种方式
    10. js截取最后一个斜杠后面的字符串
    2. apache整合tomcat部署集群
    1. apache如何启动
  • 原文地址:https://www.cnblogs.com/walkerwang/p/2121986.html
Copyright © 2011-2022 走看看