Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2621582
  • 博文数量: 315
  • 博客积分: 3901
  • 博客等级: 少校
  • 技术积分: 3640
  • 用 户 组: 普通用户
  • 注册时间: 2011-05-08 15:32
个人简介

知乎:https://www.zhihu.com/people/monkey.d.luffy Android高级开发交流群2: 752871516

文章分类

全部博文(315)

文章存档

2019年(2)

2018年(1)

2016年(7)

2015年(32)

2014年(39)

2013年(109)

2012年(81)

2011年(44)

分类: Python/Ruby

2012-02-22 21:38:24

   13章主要就是类了,看了该抽时间学习C++了,如果C++学习好了,我想来学习这个可能要好理解多了,以前学习的只是皮毛;但是看这章还是飘的很快。管它先看一遍吧,不不然没时间了,马上要去公司实习了。

   类就是相关的格式,构造,析构(python叫解构),继承,覆盖这些都是一样的,只是语法不同而已。还有一些很嚼舌的概念,类的属性,实例的属性,以及它们的区别,当然还有很多其他的,我记不住了。这章理论偏多了些,理解要多了些:

 

13. 1 以下是一个计算旅馆收费记账的类实例;

 

#file: hotel.py

#!/usr/bin/env python

# -*- coding: UTF-8 -*-

 

class HotelRoomCalc(object):

    def __init__(self, rt, sales=0.085, rm=0.1): #覆盖__init__,记住无须返回值,否则无法达到统一(都是返回一个实例对象)

        '''HotelRoomCalc default arguments:

           sales tax = 8.5% and room tax = 10%'''

        self.salesTax = sales

        self.roomTax = rm

        self.roomRate = rt

 

    def calcTotal(self, days = 1):

        #这个daily的计算不是很清除,发现课本写法我试了不太对,再研究!后来看见这个return float.__new__(cls, round(val, 2)),知道了round是为了保留位数而做的。

        daily = round((self.roomRate * 14 * (1 + self.roomTax + self.salesTax)), 2)

        return float(days) * daily

 

if __name__ == "__main__":

    sfo = HotelRoomCalc(299) #对应rt, python根据参数位置来识别self自动的,不需要作者传入(省略参数)

    print sfo.calcTotal()

    print sfo.calcTotal(2)

   

    sea = HotelRoomCalc(189, 0.086, 0.058) #覆盖默认参数

    print sea.calcTotal()

    print sea.calcTotal(4)

 

 

13. 2 小技巧(如果你在学习中需要某个类,或者方法,或者内建类型,你又不太清楚,可以用下列方法查查)

>>> x = 3.0 + 4j

>>> dir(x)

['__abs__', '__add__', '__class__', '__coerce__', '__delattr__', '__div__', '__divmod__', '__doc__', '__eq__', '__float__', '__floordiv__', '__format__', '__ge__', '__getattribute__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__int__', '__le__', '__long__', '__lt__', '__mod__', '__mul__', '__ne__', '__neg__', '__new__', '__nonzero__', '__pos__', '__pow__', '__radd__', '__rdiv__', '__rdivmod__', '__reduce__', '__reduce_ex__', '__repr__', '__rfloordiv__', '__rmod__', '__rmul__', '__rpow__', '__rsub__', '__rtruediv__', '__setattr__', '__sizeof__', '__str__', '__sub__', '__subclasshook__', '__truediv__', 'conjugate', 'imag', 'real']

>>> [type(getattr(x, i)) for i in ('conjugate', 'imag',

... 'real')]

[, , ]

>>> x.imag

4.0

>>> x.conjugate()

(3-4j)

编程中还是挺实用的。

 

13.6.5 实例属性 vs 类属性

   From:

核心提示:使用类属性来修改自身(不是实例属性)

正如上面所看到的那样,使用实例属性来试着修改类属性是很危险的。原因在于实例拥有它们自已的属性集, Python 中没有明确的方法来指示你想要修改同名的类属性,比如,没有 global关键字可以用来在一个函数中设置一个全局变量(来代替同名的局部变量)。修改类属性需要使用类名,而不是实例名。

理解:

看完这小节,还算是有点理解。大家都知道,我们用类来创建一个实例,那么我们的初始属性当然就是类属性了,当我们一旦创建实例后,我们的实例就可以独立“称王”了。我们可以用实例去做我们想做的事情,包括修改实例中的本来属性(这个属性值刚开始是类属性值);但是我们的类不会受到影响,我们依然可以用我们的类去实例化n多的类实例。

我们在改变实例的属性的时候,其实是创建了一个新的实例,我们的类属性依然如故。所以类中的这些属性就像是静态成员一样,无论外界如何改变,其本身一样不变。也就是实例属性在修改成员变量的值的时候,会有效的“隐藏”类属性,如果我们删除(del foo.x)的时候,又可以访问类属性了(print foo.x)

列子:

Class Foo(object):

  def __init__(self):

    self.x = 23

    def __del__(self):

    pass

 

>>foo = Foo()

>>Foo.x    #类属性23

>>foo.x    #类属性23

>>foo.x = 2 #创建一个新的实例,隐藏类属性

>>Foo.x    #类属性依旧不变23

>>foo.x    #实例属性2

>>del foo.x  #删除实例属性

>>foo.x    #类属性(又重见天日)23

 

   以上只是简单实例,当然不是说类成员变量就不可变。如果是字典的话还是可以通过修改实例来更新类属性的;

   比如:

Class Foo(object):

  def __init__(self):

          x = {2003: 'poe2'}

 

    def __del__(self):

    pass

 

>>foo = Foo()

>>foo.x[2004] = jane

         >>Foo.x   # {2003:poe2, 2004:jane}

     >>del foo.x[2004] # 这是不可以的,因为你的实例不能去删除一个类,就是你的创造者

 

 

13.3 self VS this

From:

核心笔记:self 是什么?

self 变量用于在类实例方法中引用方法所绑定的实例。因为方法的实例在任何方法调用中总是作为第一个参数传递的,self 被选中用来代表实例。你必须在方法声明中放上 self(你可能已经注意到了这点),但可以在方法中不使用实例(self)。如果你的方法中没有用到 self , 那么请考虑创建一个常规函数,除非你有特别的原因(Me:比如你可以创建一个全局函数,然后在类中调用申明它,但这样做不好;你不需要包装,干嘛还要放在类中,我们用类就是想实现包装,代码重用等重大功能)。毕竟,你的方法代码没有使用实例,没有与类关联其功能,这使得它看起来更像一个常规函数。在其它面向对象语言中,self 可能被称为 this

Attention:只有在实例创建后,方法才是绑定的,不然就是未绑定的;只有绑定了的方法才可以通过实例来调用。

Latter:我们可以调用非绑定的方法,这是怎么回事;知道继承就还是明白点;

class EmplAddrBookEntry(AddrBookEntry):

'Employee Address Book Entry class' # 员工地址记录条目

def __init__(self, nm, ph, em):

AddrBookEntry.__init__(self, nm, ph) #这个地方就是调用未实例化的AddrBookEntry的地方;说法(既然我们的子类继承父类,然后__init__又是如此相似,我们在实例化EmpladdrBookEntry的时候就用子类的来替代好了,似乎工作机制是这样的!

self.empid = id

self.email = em

 

13.4 staticmethod() classmethod()内建函数

      这些方法是可以直接通过类调用或者实例调用的,用法:

class TestStaticMethod:

def foo():

print 'calling static method foo()'

foo = staticmethod(foo)

 

class TestClassMethod:

def foo(cls):

print 'calling class method foo()'

print 'foo() is part of class:', cls.__name__

foo = classmethod(foo)

改进:(使用函数修饰符)

class TestStaticMethod:

@staticmethod

def foo():

print 'calling static method foo()'

 

class TestClassMethod:

@classmethod

def foo(cls):

print 'calling class method foo()'

print 'foo() is part of class:', cls.__name__

 

13.11.2 通过继承覆盖(Overriding)方法

      Example:

class P(object):

def foo(self):

print 'Hi, I am P-foo()'

 

现在来创建子类 C,从父类 P 派生:

class C(P):

def foo(self):

print 'Hi, I am C-foo()'

 

如何调用基类方法:

      1

>>> P.foo(c)

Hi, I am P-foo()

2

class C(P):

def foo(self):

P.foo(self)

print 'Hi, I am C-foo()'

3

class C(P):

def foo(self):

super(C, self).foo()  #java的模式,这样好处是你可以不必去回想我的基类名称到底是什么了??

print 'Hi, I am C-foo()'

 

13.11.3 从标准类型派生

 

不可变类型的例子

 

class RoundFloat(float):

def __new__(cls, val): #覆盖__new__

return float.__new__(cls, round(val, 2))

 

class RoundFloat(float):

def __new__(cls, val): #cls类似this, super用法和前面类似

return super(RoundFloat, cls).__new__(cls, round(val, 2))

 

可变类型的例子(你不需改变很多东西,只希望拿来就用,这样你就不需要__new__或者__init__)

 

class SortedKeyDict(dict):

def keys(self):

return sorted(super( SortedKeyDict, self).keys())

 

13.5 方法解释顺序(MRO—method resolve order)

      涉及到深度优先和广度优先去搜索父类、子类、孙子类等等的解析顺序,确定最终调用的是那个类的方法或者变量值…….其实还是好理解的。至于新式类或者经典类的继承相关矛盾和问题,就看开发者如何处理了。

经典类,使用深度优先算法。因为新式类继承自 object,新的菱形类继承结构出现,问题也就接着而来了,所以必须新建一个 MRO。但某时候广度更符合开发者要求了。

后面还有很多关于定制,迭代器,包装(实现授权)的概念,描述符,元类,应该会头晕,很难理解。

中级定制:

#!/usr/bin/env python

class Time60(object):

      'Time60 - track hours and minutes'

def __init__(self, hr, min):

'Time60 constructor - takes hours and minutes'

self.hr = hr

self.min = min

def __str__(self):

'Time60 - string representation'

return '%d:%d' % (self.hr, self.min)

 

__repr__ = __str__ #这样__repr____str__就具有一样的功能了

 

def __add__(self, other):

'Time60 - overloading the addition operator'

return self.__class__(self.hr + other.hr,self.min + other.min)

def __iadd__(self, other):

'Time60 - overloading in-place addition'

self.hr += other.hr

self.min += other.min

return self

 

阅读(1361) | 评论(0) | 转发(0) |
0

上一篇:python函数相关

下一篇:python代码执行

给主人留下些什么吧!~~