澳门新萄京官方网站-www.8455.com-澳门新萄京赌场网址

澳门新萄京官方网站python自带的八个装饰器,p

2019-05-03 作者:www.8455.com   |   浏览(173)

说到装饰器,就不得不说python自带的三个装饰器:

内容包含:

本文实例讲述了Python装饰器(decorator)定义与用法。分享给大家供大家参考,具体如下:

通常,访问类和实例属性的时候,将返回所存储的相关值,也就是直接和类(实例的)的__dict__打交道。若果要规范这些访问和设值方式的话,

将要学习的内容:
python进阶我们将要学习函数式编程
python模块:如何使用内置模块和第三方模块
python面向对象编程:面向对象的概念、属性、方法、继承和多态等
定制类:利用python的特殊方法定制类

1、@property   将某函数,做为属性使用

  • 元类
  • python 对象和类的绑定以及类方法,静态方法
  • python 子类调用父类方法总结
  • python 方法解析顺序MRQ
  • python定制类和魔法方法
  • 关于用法__slots__
  • @property使用
  • 修饰器

什么是装饰器(decorator)

一种方法是数据描述符,另一种就是python内置的数据描述符协议函数Property()。property是一种特殊的值,访问它时会计算它的值。

python中的函数式编程

函数:function,使用def定义的函数,参数不需要说明类型
函数式:fuctional。一种编程范式,在更高的抽象层次上进行编程

澳门新萄京官方网站 1

抽象层次

函数式编程特点:

  1. 把计算视为函数而非指令
  2. 纯函数式编程:不需要变量,(不管函数执行多少次,函数的结果是不变的。)没有副作用,测试简单
  3. 支持高阶函数,代码简洁

python支持的函数式编程的特点:

  1. 不是纯函数式编程,允许有变量
  2. 支持高阶函数:函数也可以有变量传入
  3. 支持闭包,有了闭包就可以返回函数
  4. 有限度的支持匿名函数

 @property 修饰,就是将方法,变成一个属性来使用。

0、元类

元类就是类的类,所体现的终极思想就是一切皆对象。

澳门新萄京官方网站 2

image.png

关于深层次,待使用到在总结。

简单来说,可以把装饰器理解为一个包装函数的函数,它一般将传入的函数或者是类做一定的处理,返回修改之后的对象.所以,我们能够在不修改原函数的基础上,在执行原函数前后执行别的代码.比较常用的场景有日志插入,事务处理等.

特性的原型函数是property(getf=None,setf=None,delf=None,doc=None),函数的前三个参数分别对应描述符的__get__、__set__、__delete__方法。

python中的高阶函数

首先变量可以指向函数。

>>> abs(-10)
10
>>> abs
<built-in function abs>
>>> f=abs
>>> f(-10)
10

# 首先abs取绝对值的函数,是一个函数,调用可以对一个数求绝对值,可以得到函数调用的结果。直接输入abs,实际返回一个函数对象,我们还可以定义一个变量f,指向abs,对f进行调用的结果和abs结果一样。这说明,变量可以指向一个函数,直接对这个变量进行调用,和调用函数的效果一样。

而函数名其实就是指向函数的对象。

>>> abs
<built-in function abs>
>>> abs=len
>>> abs(-10)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: object of type 'int' has no len()
>>> abs([1,2,3])
3

# 最初abs是一个函数变量,将abs指向另一个函数变量,len,再次执行abs(-10),就报错了,因为abs指向的函数已经发生改变了。说明函数名和普通的变量没有什么区别,只是指向一个函数对象。

澳门新萄京官方网站 3

高阶函数定义

>>> def add(x,y,f):
...     return f(x) f(y)
...
>>> add(-10,2,abs)
12
# 高阶函数例子: 定义一个加法函数,f为一个函数变量,指向另一个函数,对x和y取绝对值后加起来得到结果,add函数传入一个函数变量作为参数,所以add是一个接收函数的高阶函数。

求开方值的函数,sqrt,它的调用要使用math.sqrt,在math模块下

class A():


    @property
    def pfunc(self):
        return self.value

    @pfunc.setter
    def pfunc(self,value):
        self.value = value

    @property
    def pfunc1(self):
        print('this is property')

if __name__=="__main__":

    A.pfunc = 9
    print A.pfunc
    A.pfunc1

1、python 对象和类的绑定以及类方法,静态方法

通常我们要使用一个类中的方法时,都需要实例化该类,再进行调用,那类中 self 和 cls 有什么含义,能不能不初始化一个实例而直接调用类方法,对象方法和类方法,静态方法又有什么关系。是本篇文章思考的问题。

类的调用有以下两种方法:

>>>class Test:
...    def func(self, message):
...        print message
...
>>>object1=Test()
>>>x=object1.func
>>>x('abc')
abc
>>>t=Test.func
>>>t(object1,'abc')
abc

但是对于 t=Test.func 来说,变量名 t 是关联到了类 Test 的func 方法的地址上,t是非绑定的,所以在调用t(object1, ‘abc’) 时,必须显式的将实例名与 self 关联,否则将会报出”TypeError: unbound method func() must be called with Test instance as first argument (got str instance instead)” 的错误。

装饰器

class Foo(object):
    def __init__(self,name):
        self._name=name
    def getname(self):
        return self._name
    def setname(self,value):
        self._name=value
    def delname(self):
        del self._name
    name=property(getname,setname,delname)

map()函数

map()是 Python 内置的高阶函数,它接收一个函数 f 和一个 list,并通过把函数f依次作用在list的每个元素上,得到一个新的 list 并返回。注意:map()函数不改变原有的list,而是返回一个新的 list。利用map()函数,可以把一个 list 转换为另一个list,只需要传入转换函数。由于list包含的元素可以是任何类型,因此,map()不仅仅可以处理只包含数值的list,事实上它可以处理包含任意类型的list,只要传入的函数f可以处理这种数据类型。

def f(x):
    return x*x
print map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9])
[1, 4, 9, 10, 25, 36, 49, 64, 81]

# 将用户名字的list的英文名按规范改写
def format_name(s):
    return s[0].upper() s[1:].lower()

print map(format_name, ['adam', 'LISA', 'barT'])

 

参考学习

明白以下几点:
1、类默认的方法都是绑定对象的,而self参数也是指向该对象,没有实例化对象时,类中方法调用会出错,也涉及到python自动传递self参数。
2、若想不实例化而直接通过 类名.方法 来调用,需要指定该方法绑定到类,如下,一要使用@classmethod 装饰器,二方法中第一个参数为cls,而不是self。

>>> class Foo(object):          
...     @classmethod                #定义类方法要点1
...     def foo(cls):               #定义类方法要点2
...             print 'call foo'
... 
>>> Foo.foo()
call foo
>>> Foo().foo()
call foo

类也是对象,因此和下面的静态方法还是有不一样。类中直接定义的属性如下,在类方法中也是可以直接使用的。

class pizza(object):
    radius = 42
    @classmethod
    def get_radius(cls):
        return cls.radius
print pizza.get_radius()

类方法对于创建工厂函数最有用,如下

class pizza(object):
    def __init__(self,ingre):
        self.ingre = ingre

    @classmethod
    def from_other(cls,fridge):
        return cls(fridge.juice() fridge.cheese())  
    def get_ingre(self):
        return self.ingre

cls代表该类,cls()也是用来创建对象,和pizza(fridge.juice() fridge.cheese())效果一样。待理解,工厂方法是什么?
3、若只想当成一个普通函数,定义不包含self和cls,则可以使用静态方法,如下:

>>> class Foo(object):
...     @staticmethod
...     def foo():
...             print 'call foo'
... 
>>> Foo.foo()
call foo
>>> Foo().foo()
call foo

作者:_Zhao_
链接:http://www.jianshu.com/p/4b871019ef96
來源:简书

最简单的函数,返回两个数的和

这样就可以对属性进行读取、设置和删除了:

reduce()函数

reduce()函数也是Python内置的一个高阶函数。reduce()函数接收的参数和 map()类似,一个函数 f,一个list,但行为和 map()不同,reduce()传入的函数 f 必须接收两个参数,reduce()对list的每个元素反复调用函数f,并返回最终结果值。也有第三个可选参数,作为计算的初始值。

澳门新萄京官方网站 4

reduce函数计算过程例子

2、@classmethod  修饰类的方式

2、python 子类调用父类方法总结

参考来源

talk is weak,从程序开始:

class Person(object):
    def __init__(self):
        self.name = "Tom"
    def getName(self):
        return self.name

class Student(Person):
    def __init__(self):
        self.age = 12
    def getAge(self):
        return self.age

if __name__ == "__main__":
    stu = Student()
    print stu.getName()

作者:nummy
链接:http://www.jianshu.com/p/dfa189850651

澳门新萄京官方网站 5

image.png

上面只是说明一个常用的子类调用父类场景,即调用父类的初始化函数。
直接运行以上代码会出错,因为尽管Student类继承了Person类,但是并没有调用父类的init()方法,因为子类中对init函数进行了重写,若没有重写会直接继承父类的init函数自动运行。有以下两种方法:

参考
1、super方法

class Base:
    def __init__(self):
        print('Base.__init__')

class A(Base):
    def __init__(self):
        # super().__init__()
        super(A,self).__init__()
        print('A.__init__')

class B(Base):
    def __init__(self):
        # super().__init__()
        super(B,self).__init__()
        print('B.__init__')

class C(A,B):
    def __init__(self):
        # super().__init__()  # Only one call to super() here  python3
        super(C,self).__init__()
        print('C.__init__')

运行结果

>>> c = C()
Base.__init__
B.__init__
A.__init__
C.__init__
>>>

2、调用未绑定的父类构造方法

class Person(object):
    def __init__(self):
        self.name = "Tom"
    def getName(self):
        return self.name

class Student(Person):
    def __init__(self):
        Person.__init__(self)
        self.age = 12
    def getAge(self):
        return self.age

if __name__ == "__main__":
    stu = Student()
    print stu.getName()

作者:nummy
链接:http://www.jianshu.com/p/dfa189850651

非绑定方法不经常用到,上述场景却使用的比较多(即子类覆盖父类的方法)。运行时没有父类person的实例,需要显示地进行传递,但有Student的实例,可以用来进行代替。
这种方法叫做调用父类的未绑定的构造方法。在调用一个实例的方法时,该方法的self参数会被自动绑定到实例上(称为绑定方法)。但如果直接调用类的方法(比如Person.__init),那么就没有实例会被绑定。这样就可以自由的提供需要的self参数,这种方法称为未绑定unbound方法。
通过将当前的实例作为self参数提供给未绑定方法,Student类就能使用其父类构造方法的所有实现,从而name变量被设置。

def calc_add(a, b):
 return a   b
calc_add(1, 2)
>>> f=Foo('hello')
>>> f.name
'hello'
>>> f.name='world'
>>> f.name
'world'
>>> del f.name
>>> f.name
AttributeError: 'Foo' object has no attribute '_name'

filter()函数

filter()函数是 Python 内置的另一个有用的高阶函数,filter()函数接收一个函数f和一个list,这个函数f的作用是对每个元素进行判断,返回 True或 False,filter()根据判断结果自动过滤掉不符合条件的元素,返回由符合条件元素组成的新list。因此f函数定义是return返回的是一个条件,判断是true还是false。

# 请利用filter()过滤出1~100中平方根是整数的数,filter()接收的函数必须判断出一个数的平方根是否是整数,而 math.sqrt()返回结果是浮点数。
import math

def is_sqr(x):
    r = int(math.sqrt(x))
    print r
    return r*r==x #在这里判断了true还是false,r*r=x则为true,则是要找的x 

print filter(is_sqr, range(1, 101))

#要从一个list [1, 4, 6, 7, 9, 12, 17]中删除偶数,保留奇数
def is_odd(x):
    return x % 2 == 1
filter(is_odd, [1, 4, 6, 7, 9, 12, 17])
[1, 7, 9, 17]

#利用filter(),可以完成很多有用的功能,例如,删除 None 或者空字符串
def is_not_empty(s):
    return s and len(s.strip()) > 0
filter(is_not_empty, ['test', None, '', 'str', '  ', 'END'])

注意: s.strip(rm) 删除 s 字符串中开头、结尾处的 rm 序列的字符。当rm为空时,默认删除空白符(包括'n', 'r', 't', ' ')

带修饰类方法:cls做为方法的第一个参数,隐式的将类做为对象,传递给方法,调用时无须实例化。

3、python 方法解析顺序

但是现在又有新的需求,计算求和操作耗时,很简单,求和前获取一下时间,求和后再获取一次,求差即可

python2.6新增加了一个property装饰器,写起来更加的优雅。

自定义排序函数

sorted([36, 5, 12, 9, 21])
[5, 9, 12, 21, 36]
#sorted()默认是一个从小到大排序

但 sorted()也是一个高阶函数,它可以接收一个比较函数来实现自定义排序,比较函数的定义是,传入两个待比较的元素 x, y,如果 x 应该排在 y 的前面,返回 -1,如果 x 应该排在 y 的后面,返回 1。如果 x 和 y 相等,返回 0。理解:排在后面,则顺序正确则为1,排前面则反了,-1

#忽略姓名大小写的排序,要忽略大小写,就是先把两个字符串都变成大写(或者都变成小写),再比较。
def cmp_ignore_case(s1, s2):
    u1 = s1.upper()
    u2 = s2.upper()
    if u1<u2:
        return -1
    if u1>u2:
        return 1
    return 0

print sorted(['bob', 'about', 'Zoo', 'Credit'], cmp_ignore_case)

普通函数方法:self做为第一个参数,隐式的将类实例传递给方法,调用方法时,类必须实例化。

参考

上述博文具有很强的参考意义,转述如下:
在类的多继承中,方法解析顺序MRQ具有很重要的意义,比如对以下菱形继承,D的实例调用show方法,是调用A的还是C的show。

澳门新萄京官方网站 6

image.png

python解析顺序的规范化也是一个不断发展的过程,主要有以下两个阶段:

  • 2.2之前的经典类。经典类中多继承方法解析采用深度优先从左到右搜索,即D-B-A-C-A,也就是说经典类中只采用A的show方法。
  • 经典类对单层继承没有什么问题,但是对上述来说,我们显然更愿意使用C的show方法,因为他是对A的具体化,但是经典类比并不能实现,于是在2.2中引入新式类(继承自object),它仍然采用从左至右的深度优先遍历,但是如果遍历中出现重复的类,只保留最后一个。并且在定义类时就计算出该类的 MRO 并将其作为类的属性。因此新式类可以直接通过 mro 属性获取类的 MRO。
    举个例子:

澳门新萄京官方网站 7

image.png

按照深度遍历,其顺序为 [D, B, A, object, C, A, object],重复类只保留最后一个,因此变为 [D, B, C, A, object]

这样看起来好像么有问题,但是会有潜在的问题,比如破坏了单调性原则,因此在2.3中引入了 __ C3 算法__。

import datetime
def calc_add(a, b):
 start_time = datetime.datetime.now()
 result = a   b
 end_tiem = datetime.datetime.now()
 print "result:", result, "used:", (end_tiem - start_time).microseconds, "μs"
 return result
calc_add(1, 2)
class Foo(object):
    def __init__(self,name):
        self._name=name
    @property
    def name(self):
        return self._name
    @name.setter
    def name(self,value):
        self._name=value
    @name.deleter
    def name(self):
        del self._name

返回函数

Python的函数不但可以返回int、str、list、dict等数据类型,还可以返回函数!

澳门新萄京官方网站 8

返回函数讲解

返回函数可以把一些计算延迟执行。正常函数,函数一旦调用,立马得到执行结果,而返回函数只有在调用返回的结果时,才会执行函数的内容。由于可以返回函数,我们在后续代码里就可以决定到底要不要调用该函数。

澳门新萄京官方网站 9

返回函数

#延迟计算list元素的乘积
def calc_prod(lst):
    def mul():
        def mul_num(x,y):
            return x*y
        return reduce(mul_num,lst)  #没有list的求积函数,使用reduce()高阶函数
    return mul

f = calc_prod([1, 2, 3, 4])
print f()
class A():
    def func(self,x,y):
        return x * y

    @classmethod
    def cfunc(cls,x,y):
        return x * y

if __name__=="__main__":
    print A().func(5,5)
    print A.cfunc(4,5)
C3 MRQ

我们把类 C 的线性化(MRO)记为 L[C] = [C1, C2,…,CN]。其中 C1 称为 L[C] 的头,其余元素 [C2,…,CN] 称为尾。如果一个类 C 继承自基类 B1、B2、……、BN,那么我们可以根据以下两步计算出 L[C]:
1、L[object] = [object]
2、L[C(B1…BN)] = [C] merge(L[B1]…L[BN], [B1]…[BN])
这里的关键在于 merge,其输入是一组列表,按照如下方式输出一个列表:
检查第一个列表的头元素(如 L[B1] 的头),记作 H。
若 H 未出现在其它列表的尾部,则将其输出,并将其从所有列表中删除,然后回到步骤1;否则,取出下一个列表的头部记作 H,继续该步骤。
重复上述步骤,直至列表为空或者不能再找出可以输出的元素。如果是前一种情况,则算法结束;如果是后一种情况,说明无法构建继承关系,Python 会抛出异常。

举例:

澳门新萄京官方网站 10

image.png

根据C3,计算过程为:

澳门新萄京官方网站 11

image.png

现在呢,函数calc_diff(a, b),计算a-b,也想计算减法操作的时间差,很好办,把那段代码复制过去.但是假如我们现在想编的是一个数学函数库,各种函数都想计算其执行耗时,总不能一个一个复制代码,想个更好的办法.

首先使用@property装饰器和相关方法将属性name设置为可读,后面的@name.setter和@name.deleter装饰器将其他方法与name属性上的设置和

python中的闭包

在函数内部定义的函数和外部定义的函数是一样的,只是他们无法被外部访问,如f函数中定义g函数,并且返回g。把g定义在内部可以防止被其他函数调用。

澳门新萄京官方网站 12

闭包例子

闭包的特点是返回的函数还引用了外层函数的局部变量,所以,要正确使用闭包,就要确保引用的局部变量在函数返回后不能变。

# 希望一次返回3个函数,分别计算1x1,2x2,3x3:
def count():
    fs = []
    for i in range(1, 4):
        def f():
             return i*i
        fs.append(f)
    return fs

f1, f2, f3 = count()  #函数变量赋值
print f1(), f2(), f3() #打印函数调用结果

# fs为一个列表,列表里面是可以放各种对象的,这里存放的是三个函数对象,fs.append(f)在后面追加的是f函数名,而不是f()函数值,所以count()的返回结果是一个存放三个函数的列表。

原因就是当count()函数返回了3个函数时,这3个函数所引用的变量i的值已经变成了3。即可以说闭包中的内部函数延迟加载,在调用外部函数返回的函数时才执行,此时才执行内部的内容,所以此时i为3。

#改写为没有循环变量的,增添新的内部函数
def count():
    fs = []
    for i in range(1, 4):
        def f(j):
            def g():
                return j*j
            return g
        r=f(i)
        fs.append(r)
    return fs

f1, f2, f3 = count()
print f1(), f2(), f3()

 

4、python定制类和魔法方法

我们知道,在Python中函数也是被视为对象的,可以作为参数传递,那么假如把计算耗时的独立为一个单独的函数calc_spend_time(),然后把需要计算耗时的函数例如calc_add的引用传递给它,在calc_spend_time中调用calc_add,这样所有的需要计算耗时的函数都不用修改自己的代码了.

删除操作相关联。实际的name值存储在属性_name中。实际存储属性的名称无需遵循任何约定,只需要与特性名称不同即可。

匿名函数

高阶函数可以接收函数做参数,有些时候,我们不需要显式地定义函数,直接传入匿名函数更方便。

关键字lambda 表示匿名函数,冒号前面的 x 表示函数参数。匿名函数有个限制,就是只能有一个表达式,不写return,返回值就是该表达式的结果。

map(lambda x: x * x, 澳门新萄京官方网站python自带的八个装饰器,python进阶学习笔记。[1, 2, 3, 4, 5, 6, 7, 8, 9]) [1, 4, 9, 16, 25, 36, 49, 64, 81]

澳门新萄京官方网站 13

匿名函数例子

3、@staticmethod  修饰类的方式

参考学习

形如__xxx__的变量或者函数名要注意,这些在Python中是有特殊用途。常见的就是__inint__()函数了,在对象创建后用来初始化,类似的还有__new()__ 和__del__函数。用的不是很多,不做细节深入。

def calc_spend_time(func, *args, **kargs):
 start_time = datetime.datetime.now()
 result = func(*args, **kargs)
 end_tiem = datetime.datetime.now()
 print "result:", result, "used:", (end_tiem - start_time).microseconds, "μs"
def calc_add(a, b):
 return a   b
calc_spend_time(calc_add, 1, 1)
# calc_spend_time(calc_add, a=1, b=2)

特性的使用遵循统一访问原则。如果没有特性,将会以简单属性的形式访问属性,而其他属性将以方法的形式访问。费力去了解何时添加额外的()会带来不必要的混淆。

decrator装饰器

什么是装饰器:问题:我们定义了一个函数,想在运行时动态增加代码,又不像改动函数本身代码。

  1. 方法1:直接修改原函数,在原函数内添加打印的语句。
![](https://upload-images.jianshu.io/upload_images/5355764-28657a6ebefe73e0.png)

方法1
  1. 使用高阶函数,高阶函数可以接收函数作为参数,可以返回函数,那就可以接收一个函数,并对其包装,然后返回一个新的函数。这样就可以动态的把一个函数的功能增强。

澳门新萄京官方网站 14

方法2

定义了一个new_fn这个函数,来装饰原函数,返回一个增强功能后的函数。首先这个装饰器函数的参数为函数,(调用时实参为原来想要增强的函数),由于要返回一个增强后的新的函数,则用到闭包,返回内部的新的函数,在内部函数中就写入了增加的功能并且调用原来预增强功能的函数。第二种调用方法,f1原本是函数变量,调用后重新复制,则将最原本的定义给覆盖了,完全隐藏了。在最终调用原始函数时使用的return而不是直接调用,原因是作为函数返回,而不是调用执行。

def add(x,y):
    return x y

def new_fn(f):
    def f1(x,y):
        print 'add is called'
        return f(x,y)  #如果去掉f(x,y),则无法获得add(2,3)的结果到下面调用的地方,只是在这里运行
    return f1

a = new_fn(add)
print a(1,2)

澳门新萄京官方网站 15

装饰器@语法

澳门新萄京官方网站 16

装饰器的作用

1)是把函数嵌入到类中的一种方式,函数就属于类,同时表明函数不需要访问这个类

__澳门新萄京官方网站python自带的八个装饰器,python进阶学习笔记。str__ 和 __rerp__
class yuan(object):
    def __init__(self):
        self.name = 'yuanqijie'
        self.age = 22
        self.ambition = 'yes'
    def __str__(self):
        return 'object name: %s'  % self.name

qijie = yuan()
print qijie

输出为:
object name: yuanqijie

若没有重写 __str__ 则输出为 <main.Student object at 0x109afb310>
但注意到,若直接输出变量而不是用print在提示符下还是上述信息,因为直接显示变量调用的不是str(),而是repr(),两者的区别是str()返回用户看到的字符串,而repr()返回程序开发者看到的字符串,也就是说,repr()是为调试服务的。可以类似上述方法进行重写,作为了解即可。

看起来也不错,负责计算的函数不用更改,只需调用的时候作为参数传给计算时间差的函数.但就是这,调用的时候形式变了,不再是clac(1, 2),而是calc_spend_time(clac_add, 1, 2),万一calc_add大规模被调用,那么还得一处一处找,然后修改过来,还是很麻烦.如果想不修改代码,就得使clac()calc_spend_time(clac)效果一样,那么可以在calc_spend_time()里把传入的clac包装一下,然后返回包装后的新的函数,再把返回的包装好的函数赋给clac,那么calc()的效果就和上例calc_spend_time(calc())效果一样.

实际上,方法本身是作为一类特性被隐式处理的。

编写无参数decrator装饰器

这里的带不带参数是指高阶装饰器函数有没有自己的参数,除了要封装的原函数f以外。
对于装饰器函数来说,这个高阶函数在内部定义fn函数是会需要说明参数,然后调用的原始的f()并且传入参数,如果参数个数不符,则报错。因此解决办法是:

要让 @log 自适应任何参数定义的函数,可以利用Python的 *args 和 **kw,保证任意个数的参数总是能正常调用。

# 请编写一个@performance,它可以打印出函数调用的时间。计算函数调用的时间可以记录调用前后的当前时间戳,然后计算两个时间戳的差。
import time

def performance(f):
    def fn(*args, **kw):
        t1=time.time()
        r = f(*args,**kw)
        t2=time.time()
        print 'call %s() in %fs' % (f.__name__, (t2 - t1))
        return r
    return fn

@performance
def factorial(n):
    return reduce(lambda x,y: x*y, range(1, n 1))

print factorial(10)

 2)使用修饰服,修饰方法,不需要实例化

5、__slots__

当定义一个类时,可以动态的给该类绑定一个属性和方法,比如:

>>> class Student(object):
...     pass

>>> s = Student()
>>> s.name = 'Michael' # 动态给实例绑定一个属性
>>> print s.name
Michael

>>> def set_age(self, age): # 定义一个函数作为实例方法
...     self.age = age
...
>>> from types import MethodType
>>> s.set_age = MethodType(set_age, s, Student) # 给实例绑定一个方法
>>> s.set_age(25) # 调用实例方法
>>> s.age # 测试结果
25

注意的是,上面是给一个实例绑定的相应的方法,也就是说当在生成一个实例时,上述增加的属性和方法就不起作用了。可以给class绑定方法:

>>> def set_score(self, score):
...     self.score = score
...
>>> Student.set_score = MethodType(set_score, None, Student)

只需将MethodType第二个参数改为None就行。

import datetime
def calc_spend_time(func):
 def new_func(a, b):
  start_time = datetime.datetime.now()
  result = func(a, b)
  end_tiem = datetime.datetime.now()
  print "result:", result, "used:", (end_tiem - start_time).microseconds, "μs"
 return new_func
def calc_add(a, b):
 return a   b
calc_add = calc_spend_time(calc_add)
calc_add(1, 2)
class Foo(object):
    def __init__(self,name):
        self.name=name
    def spam(self,x):
        print '%s.%s'%(self.name,x)

编写带参数decrator装饰器

当装饰器函数要带参数时,比如原先打印日志,是外层装饰器函数传入f,然后打印语句,加入要打印的语句视情况而定,需要根据打印日志的装饰函数传入的参数进行确定时,则需要进行三层嵌套,给最外层的装饰函数传入prefi参数。这三层不能拆开写,因为内部函数会用到外层的prefix。

澳门新萄京官方网站 17

带参数的装饰器函数

澳门新萄京官方网站 18

调用实例

# 带参数的装饰器函数
import time

def performance(unit):
    def perf_decorator(f):
        def wrapper(*args,**kw):
            t1=time.time()
            r=f(*args,**kw)
            t2=time.time()
            t = (t2-t1)*1000 if unit == 'ms' else (t2-t1)
            print 'call %s() in %f %s' % (f.__name__, t, unit)
            return r
        return wrapper
    return perf_decorator

@performance('ms')
def factorial(n):
    return reduce(lambda x,y: x*y, range(1, n 1))

print factorial(10)

 

__slots__ 用来限制属性
>>> class people(object):
...     __slots__ = ('age','name') # 用tuple定义允许绑定的属性名称
... 
>>> p = people()
>>> p.age = 20
>>> p.na = yuan
>>> p.na = 'yuan'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'people' object has no attribute 'na'
>>> p.name = 'yuan'
>>> 

语法糖

用户创建f=Foo('hello')这样的实例然后访问f.spam时,不会返回原始函数对象spam,相反会得到绑定方法。绑定方法有点类似于部分计算的函数,

偏函数

functools.partial可以把一个参数多的函数变成一个参数少的新函数,少的参数需要在创建时指定默认值,这样,新函数调用的难度就降低了。

# 偏函数使用实例,调用functools的partial方法,传入原函数和默认参数设置,使传入参数简化,例如这里要更多的计算转化int字符串为二进制,而一般默认为10进制,传入默认的base参数,构成新的函数
>>> import functools
>>> int2 = functools.partial(int, base=2)
>>> int2('1000000')
64
>>> int2('1010101')
85

#前面的排序函数,忽略大小写姓名排序,这里sorted函数默认从小到大,修改排序规则,则是传入一个新的比较函数,这是使用匿名函数,说明比较的规则。即自定义排序函数,将它进一步做成偏函数,以后就能直接使用建好的自定义排序函数
import functools

sorted_ignore_case = functools.partial(sorted, cmp=lambda s1,s2:cmp(s1.upper(),s2.upper()))

print sorted_ignore_case(['bob', 'about', 'Zoo', 'Credit'])
class A():
    def func(self,x,y):
        return x * y


    @staticmethod
    def sfunc(x,y):
        return x * y


if __name__=="__main__":

    print A.sfunc(6,5)

6、@property使用

参考
http://python.jobbole.com/80955/
由上面一节可以知道,绑定属性时,可以随意修改属性值,比如

s = Student()
s.score = 9999

很多时候都需要对属性值进行判断,比如正负,大小范围等,一般来说就需要写一个函数进行逻辑检查,比如:

class Student(object):

    def get_score(self):
        return self._score

    def set_score(self, value):
        if not isinstance(value, int):
            raise ValueError('score must be an integer!')
        if value < 0 or value > 100:
            raise ValueError('score must between 0 ~ 100!')
        self._score = value

这样就能保证能对传入的值进行逻辑约束,但是每次设置需要调用相应函数,比如s.set_score( 99 ),又显得不是很简洁,能不能像 s.score = 99一样简洁又能进行逻辑检查呢。就是@property。
@property装饰器可以将一个method变为属性,可以像属性一样简单调用,如student.get_score ,若没有装饰器,则返回的是函数地址。关于setter用法见下。

class Student(object):

    @property
    def score(self):
        return self._score

    @score.setter
    def score(self, value):
        if not isinstance(value, int):
            raise ValueError('score must be an integer!')
        if value < 0 or value > 100:
            raise ValueError('score must between 0 ~ 100!')
        self._score = value

@score.setter装饰器表示可以对该属性赋值,若没有则是一个只读的属性。

上面的例子就是装饰器的概念,包装函数的函数.事实上上面的例子还可以更精简

其中的self参数已经填入,但其他参数仍然需要在使用()调用该函数时提供。这种绑定方法是由在后台执行的特性函数静静地创建的。使用@staticmethod和

python中的模块和包

当一个文件代码越来越多,就不便于维护,因此就会分成多个文件,好处在于便于维护了,并且同一名字的变量互不影响在不同的文件中。此时一个文件就是一个模块,模块名就是文件名。
在一个模块中,引用第三方模块,使用import 模块名。引用模块中的方法,直接模块名.方法()。
此时模块多了也很容易重名,把同名模块放入不同的包中就可以解决模块名相同的问题。因为完整的模块名还是不一样。如p1.util与p2.util。引用时必须引用完整模块名,从包名开始正确写。
在python中,包就是文件夹,模块就是.py文件,如何区分包和普通目录呢,包下面有个init.py文件,包的每一层目录都要有这个文件,即使这个文件是一个空文件。

import math
# Python使用import语句导入一个模块。例如,导入系统自带的模块 math

#只希望导入用到的math模块的某几个函数,而不是所有函数,可以用下面的语句,这样就可以直接引用了,调用时前面不用再写模块名
from math import pow, sin, log

# 如果方法名冲突,若使用import引入,调用时用模块名.函数名自然不会冲突,若使用from,那么冲突解决办法就是起别名。
from math import log
from logging import log as logger   # logging的log现在变成了logger

 

7、修饰器

参考学习

import datetime
def calc_spend_time(func):
 def new_func(a, b):
  start_time = datetime.datetime.now()
  result = func(a, b)
  end_tiem = datetime.datetime.now()
  print "result:", result, "used:", (end_tiem - start_time).microseconds, "μs"
 return new_func
@calc_spend_time
def calc_add(a, b):
 return a   b
calc_add(1, 2)

@classmethod定义静态方法和类方法时,实际上就指定了使用不同的特性函数,以不同的方式处理对这些方法的访问。

动态导入模块

#同样的功能,StringIO 是纯Python代码编写的,而 cStringIO 部分函数是C写的,因此cStringIO运行速度更快。
try:
    from cStringIO import StringIO
except ImportError:
    from StringIO import StringIO

try 的作用是捕获错误,并在捕获到指定错误时执行 except 语句。

# 适应版本变化,动态加载模块,并且将不同名的取别名相同,因为内部函数签名和功能一样
try:
    import json
except ImportError:
    import simplejson as json

print json.dumps({'python':2.7})

 

示例1:
class myDecorator(object):
    def __init__(self, fn):
        print "inside myDecorator.__init__()"
        self.fn = fn

    def __call__(self):
        self.fn()
        print "inside myDecorator.__call__()"


@myDecorator
def aFunction():
    print "inside aFunction()"

print "Finished decorating aFunction()"
aFunction()

运行上述输出为:

inside myDecorator.__init__()
Finished decorating aFunction()
inside aFunction()
inside myDecorator.__call__()

@calc_spend_time就是语法糖,它的本质就是:calc_add = calc_spend_time(calc_add)

pyhton中的future模块

例子:在python2.7中,/除法是整数除法。在3.x中,/是浮点数除法,//是整数除法,要在2.7中引入3.x的除法规则:

#要“试用”某一新的特性,就可以通过导入__future__模块的某些功能来实现。
>>> from __future__ import division
>>> print 10 / 3
3.3333333333333335

Linux and python学习交流1,2群已满.

示例2:
def check_is_admin(f):
    def wrapper(*args, **kwargs):
        if kwargs.get('username') != 'admin':
            raise Exception("error occur")
        return f(*args, **kwargs)
    return wrapper

class store(object):
    @check_is_admin
    def get_food(self,username,food):
        print food

s = store()
s.get_food(username='admin',food='noodles')
print s.get_food.__name__

上述程序定义了check_is_admin的装饰器,装饰器的主要作用是调用某个函数之前执行一类通用的操作,比如日志任务,上述是执行了权限检查。
函数被装饰器修饰时,本质上函数变为
get_food = check_is_admin(get_food(self,username,food))
check_is_admin直接返回 wrapper函数地址,因此get_food也是指向wrapper函数,故print s.get_food.__name__结果是 wrapper.
因此调用s.get_food(username='admin',food='noodles')也就是
wrapper(username='admin',food='noodles')。该函数最后一定要有return f(*args, **kwargs) ,这确保原来函数被执行并返回结果。
因为装饰器使原函数指向了另一个函数(如上面的wrapper),而原函数只是该函数的一部分,该方式确实对原函数进行了扩展。但同时引入了另外的问题,原函数的属性和名字没有了,如上面s.get_food.__name__并不是get_food。functools提供了名为wraps的装饰器,会复制这些属性给装饰器函数,用法如下:

import functools
def check_is_admin(f):
    @functools.wraps(f)
    def wrapper(*args, **kwargs):
        if kwargs.get('username') != 'admin':
            raise Exception("error occur")
        #return f(*args, **kwargs)
    return wrapper

只需额外添加两行代码。
值得一提的是,**kwargs指定了字典方式传入数据,因此只支持s.get_food(username='admin',food='noodles')而不支持s.get_food('admin','noodles')。为了代码的通用性,考虑对其进行完善,使用inspect模块,最终为:

import functools
import inspect
def check_is_admin(f):
    @functools.wraps(f)
    def wrapper(*args, **kwargs):
        func_args = inspect.getcallargs(f,*args,**kwargs)
        if func_args.get('username') != 'admin':
            raise Exception("error occur")
        print 'test'
        return f(*args, **kwargs)
    return wrapper

func_args会以字典形式记录对应的key和value。意味着装饰器不用检查参数是否是基于位置的参数还是关键字参数,最终以相同的格式保存在返回字典中。

无参数的函数装饰器

如何安装python第三方模块

python内置了许多有用的模块,但是对没有内置的功能,我们可以安装第三方模块来完成。pyhton提供了两种模块的管理工具:

  1. easy_install
  2. pip(推荐,已经内置到python2.7)

在命令提示符中直接输入pip install web.py则可以安装第三方模块web.py,安装好以后再python进入,就可以import web这个模块了。

澳门新萄京官方网站 19

安装第三方模块示例

查找其他第三方模块,https://pypi.python.org
输入相关包的名字就可以搜索到内容。

Linux and python学习交流3群新开,欢迎加入,一起学习.qq 3群:563227894

import datetime
def calc_spend_time(func):
 def new_func(*args, **kargs):
  start_time = datetime.datetime.now()
  result = func(*args, **kargs)
  end_tiem = datetime.datetime.now()
  print "result:", result, "used:", (end_tiem - start_time).microseconds, "μs"
 return new_func
@calc_spend_time
def calc_add(a, b):
 return a   b
@calc_spend_time
def calc_diff(a, b):
 return a - b
calc_add(a=1, b=2)
calc_diff(1, 2)

python之面向对象编程

用类和实例来区别不同的类型以及不同的实例变量。使用class来创建类,使用xiaoming = Person()来创建一个实例变量,形式类似于函数调用。
面向对象编程中重要的一个思想:数据封装,我们在类中就可以把每一个实例的属性封装起来,不同的实例拥有相同的数据类型,但是他们拥有不同的属性。

不前进,不倒退,停止的状态是没有的.

注:

定义类并且创建实例

类通过 class 关键字定义,按照 Python 的编程习惯,类名以大写字母开头,紧接着是(object),表示该类是从哪个类继承下来的。创建实例使用 类名 (),类似函数调用的形式创建。

class Person(object):
    pass

xiaoming = Person()
xiaohong = Person()

print xiaoming
print xiaohong
print xiaohong == xiaoming

#运行结果:
<__main__.Person object at 0x7fc26d07c450>
<__main__.Person object at 0x7fc26cfbbad0>
False

一起进步,与君共勉,

*args:把所有的参数按出现顺序打包成list
**kargs:把所有的key=value形式的参数打包成一个dict

创建实例属性

让每个实例拥有各自不同的属性,由于Python是动态语言,对每一个实例,都可以直接给他们的属性赋值。即直接创建好后,通过.给不同实例创建不一样的属性以及对应的属性值。

class Person(object):
    pass

p1 = Person()
p1.name = 'Bart'

p2 = Person()
p2.name = 'Adam'

p3 = Person()
p3.name = 'Lisa'

L1 = [p1, p2, p3]
L2 = sorted(L1, lambda p1, p2: cmp(p1.name, p2.name))

print L2[0].name
print L2[1].name
print L2[2].name
# L1里面存放的三个对象,因此sorted排序时,应该自定义比较函数,比较的是对象的name属性值,并且最后打印时应是L2[index].name。

 

带参数的函数装饰器

初始化实例属性

一种类型的实例应该有相同的名字的属性,所以可以在类中通过一个特殊的init()方法,创建实例是,init()方法会被自动调用,从而在创建实例时直接在()中传入参数对属性赋值。

初学者定义init()方法常常忘记了 self 参数。init() 方法的第一个参数必须是self(也可以用别的名字,但建议使用习惯用法),创建实例时,就必须要提供除 self 以外的参数。

# **表示还可接受任意关键字参数,并把他们作为属性复制给实例。要定义关键字参数,使用 **kw;除了可以直接使用self.name='xxx'设置一个属性外,还可以通过setattr(self, 'name', 'xxx')设置属性。
class Person(object):
    def __init__(self,name,gender,birth,**kw):
        self.name=name
        self.gender=gender
        self.birth=birth
        for k,v in kw.iteritems():
            setattr(self,k,v)

xiaoming = Person('Xiao Ming', 'Male', '1990-1-1', job='Student')

print xiaoming.name
print xiaoming.job

假如我们需要知道函数的一些额外信息,例如函数作者,可以通过给装饰器函数增加参数来实现.

访问限制

一个实例可以有很多属性,如果这个属性不希望被外部访问,则可以通过属性名的设置来达成权限控制。(__)双下划线开头的属性就无法被外部访问。

以单下划线开头的属性"_xxx"虽然也可以被外部访问,但是,按照习惯,他们不应该被外部访问。如果一个属性以"_xxx_"的形式定义,那它又可以被外部访问了,以"xxx"定义的属性在Python的类中被称为特殊属性,有很多预定义的特殊属性可以使用。

class Person(object):
    def __init__(self, name):
        self.name = name
        self._title = 'Mr'
        self.__job = 'Student'
p = Person('Bob')
print p.name
# => Bob
print p._title
# => Mr
print p.__job
# => Error
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Person' object has no attribute '__job'

class Person(object):
    def __init__(self, name, score):
        self.name = name
        self.__score = score

p = Person('Bob', 59)

print p.name
try:
    print p.__score
except AttributeError:
    print 'attributeError'
import datetime
def calc_spend_time(author):
 def first_deco(func):
  def new_func(*args, **kargs):
   start_time = datetime.datetime.now()
   result = func(*args, **kargs)
   end_tiem = datetime.datetime.now()
   print author, "result:", result, "used:", (end_tiem - start_time).microseconds, "μs"
  return new_func
 return first_deco
@calc_spend_time('author_1')
def calc_add(a, b):
 return a   b
@calc_spend_time('author_2')
def calc_diff(a, b):
 return a - b
calc_add(a=1, b=2)
calc_diff(1, 2)

创建类属性

实例属性每个实例各自拥有,互相独立,而类属性有且只有一份。
理解:类本身是一个对象,如果在类上绑定属性,则所有实例都可以访问类的属性,并且访问的都是用一个。这个就叫做类属性。

#类属性定义:
class Person(object):
    address = 'Earth'
    def __init__(self, name):
        self.name = name

#访问类属性不需要创建实例,就可以直接访问
print Person.address
# => Earth

# 由于Python是动态语言,类属性也是可以动态添加和修改的,因为类属性只有一份,所以,当Person类的address改变时,所有实例访问到的类属性都改变了。
Person.address = 'China'
print p1.address
# => 'China'
print p2.address
# => 'China'

class Person(object):
    count = 0  # 相当于一个类的静态变量,每次修改后值都会保存
    def __init__(self, name):
        Person.count = Person.count 1
        self.name=name

p1 = Person('Bob')
print Person.count

p2 = Person('Alice')
print Person.count

p3 = Person('Tim')
print Person.count

Python内置装饰器

实例属性和类属性同名冲突

当实例属性和类属性重名时,实例属性优先级高,它将屏蔽掉对类属性的访问。例如:

class Person(object):
    address = 'Earth'
    def __init__(self, name):
        self.name = name

p1 = Person('Bob')
p2 = Person('Alice')

print 'Person.address = '   Person.address
#这一步打印的是p1访问的类属性地球
p1.address = 'China'
print 'p1.address = '   p1.address
#这一步试图修改类属性,但是并没有,而是给p1这个对象绑定了一个新的实例属性,地址为中国,两个冲突,此时访问到的是实例属性的中国

print 'Person.address = '   Person.address
#这里类属性仍然是地球
print 'p2.address = '   p2.address
#通过p2访问类属性,为earth

澳门新萄京官方网站 20

实例属性和类属性冲突

class Person(object):
    # 类属性设置为__两个下弧线的私有的,则还是不能被访问的
    __count = 0

    def __init__(self, name):
        Person.__count = Person.__count   1
        self.name = name
        print Person.__count

p1 = Person('Bob')
p2 = Person('Alice')

try:
    print Person.__count
except AttributeError:
    print 'attributeError'

Python内置的装饰器有三个:staticmethodclassmethodproperty

定义实例方法

一个实例的私有属性就是以__开头的属性,无法被外部访问,但是,从类的内部是可以访问的。除了可以定义实例的属性外,还可以定义实例的方法。

实例的方法就是在类中定义的函数,它的第一个参数永远是 self,指向调用该方法的实例本身,其他参数和一个普通函数是完全一样的。实例方法中self变量不需要显示传入

澳门新萄京官方网站 21

实例方法

staticmethod:把类中的方法定义为静态方法,使用staticmethod装饰的方法可以使用类或者类的实例对象来调用,不需要传入self

python中方法也是属性

在class中定义的实例方法其实也是属性,它实际上是一个函数对象

class Person(object):
    def __init__(self, name, score):
        self.name = name
        self.score = score
    def get_grade(self):
        return 'A'

p1 = Person('Bob', 90)
print p1.get_grade
# => <bound method Person.get_grade of <__main__.Person object at 0x109e58510>>
print p1.get_grade()
# => A

# p1.get_grade 返回的是一个函数对象,但这个函数是一个绑定到实例的函数,p1.get_grade() 才是方法调用

因为方法也是属性,所以可以动态的添加到实例上。只需要types.MethodType()把一个函数变为一个方法,但是这个方法只对动态创建时的那个对象有用,其余想用类的对象无用

import types
def fn_get_grade(self):
    if self.score >= 80:
        return 'A'
    if self.score >= 60:
        return 'B'
    return 'C'

class Person(object):
    def __init__(self, name, score):
        self.name = name
        self.score = score

p1 = Person('Bob', 90)
p1.get_grade = types.MethodType(fn_get_grade, p1, Person)
print p1.get_grade()
# => A
p2 = Person('Alice', 65)
print p2.get_grade()
# ERROR: AttributeError: 'Person' object has no attribute 'get_grade'
# 因为p2实例并没有绑定get_grade
class Human(object):
 """docstring for Human"""
 def __init__(self):
  super(Human, self).__init__()
 @staticmethod
 def say(message):
  if not message:
   message = 'hello'
  print 'I say %s' % message
 def speak(self, message):
  self.say(message)
Human.say(None)
human = Human()
human.speak('hi')

定义类方法

和属性类似,方法也分实例方法和类方法。
在class中定义的全部是实例方法,实例方法第一个参数self是实例本身。

# 将count计数设为私有变量,但是可以通过公共类方法进行访问,因为类方法是在类上调用,而不是实例上,因此类方法无法获得任何实例变量,只能获得类的引用。
class Person(object):
    __count = 0
    @classmethod
    def how_many(cls):
        return cls.__count
    def __init__(self, name) :
        self.name = name
        Person.__count = Person.__count   1

print Person.how_many()

p1 = Person('Bob')

print Person.how_many()

输出:

类的继承

继承是个is关系,子类也是一个父类,但父类不一定是子类。
has关系是组合关系,因此应该作为一个作为一个属性出现。

澳门新萄京官方网站 22

has关系

pyhton继承的特点,首先都是从一个类开始继承,如果没有合适的类,都是从object开始继承。最后不要忘记调用super().__init()f方法,这是方法是用来初始化父类的。如果没有这个方法,父类的属性可能不会被正确的初始化。

澳门新萄京官方网站 23

python中的继承

I say hello
I say hi

判断类型

函数isinstance()可以判断一个变量的类型,既可以用在Python内置的数据类型如str、list、dict,也可以用在我们自定义的类,它们本质上都是数据类型。
测试前面继承的类,这说明在继承链上,一个父类的实例不能是子类类型,因为子类比父类多了一些属性和方法
isinstace(t,Teacher),前面参数为对象,后面参数为判断的类型

classmethod:把类中的方法定义为类方法,使用classmethod装饰的方法可以使用类或者类的实例对象来调用,并将该class对象隐式的作为第一个参数传入

多态

多态是指在继承中,父类和子类都有相同的方法,子类不仅继承有父类,还可以自己对继承来的方法进行重写修改。最后都可以调用该方法。

澳门新萄京官方网站 24

多态理解

class Human(object):
 """docstring for Human"""
 def __init__(self):
  super(Human, self).__init__()
  self.message = '111'
 def say(message):
  if not message:
   message = 'hello'
  print 'I say %s' % message
 @classmethod
 def speak(cls, message):
  if not message:
   message = 'hello'
  cls.say(message)
human = Human()
human.speak('hi')

多继承

多重继承的目的是从两种继承树中分别选择并继承出子类,以便组合功能使用。

class A(object):
    def __init__(self, a):
        print 'init A...'
        self.a = a

class B(A):
    def __init__(self, a):
        super(B, self).__init__(a)
        print 'init B...'

class C(A):
    def __init__(self, a):
        super(C, self).__init__(a)
        print 'init C...'

class D(B, C):
    def __init__(self, a):
        super(D, self).__init__(a)
        print 'init D...'

>>> d = D('d')
init A...
init C...
init B...
init D...

输出同上例

获取对象信息

  1. 用isinstance()判断它是否是某种类型的实例外,还可以获取其他更多信息。
  2. 可以用 type() 函数获取变量的类型,它返回一个 Type 对象
>>> s = Student('Bob', 'Male', 88)
>>> type(s)
<class '__main__.Student'>
  1. 可以用 dir() 函数获取变量的所有属性
>>> dir(123)   # 整数也有很多属性...
['__abs__', '__add__', '__and__', '__class__', '__cmp__', ...]

>>> dir(s)
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'gender', 'name', 'score', 'whoAmI']
#注意whoAmI这个函数变量也是student学生类的属性

dir()返回的属性是字符串列表,如果已知一个属性名称,要获取或者设置对象的属性,就需要用 getattr() 和 setattr( )函数了。

>>> getattr(s, 'name')  # 获取name属性
'Bob'

>>> setattr(s, 'name', 'Adam')  # 设置新的name属性

>>> s.name
'Adam'

>>> getattr(s, 'age')  # 获取age属性,但是属性不存在,报错:
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Student' object has no attribute 'age'

>>> getattr(s, 'age', 20)  # 获取age属性,如果属性不存在,就返回默认值20:
20

property:把方法变成属性

python的特殊方法

python如何把任意变量都变成一个字符串的呢,因为每个那个数据类型的实例都有一个特殊方法,str(),如果自己给一个类写这个方法,那么打印时候就可以按自定义的方式打印出来效果了。
python的特殊方法,特殊方法定义在class中,不需要直接调用,python的某些函数和操作符会调用对应的特殊方法。

class Human(object):
 """docstring for Human"""
 def __init__(self, value):
  super(Human, self).__init__()
  self._age = value
 @property
 def age(self):
  return self._age
human = Human(20)
print human.age

str()和repr()

# 如果要把一个类的实例变成 str,就需要实现特殊方法__str__()
class Person(object):
    def __init__(self, name, gender):
        self.name = name
        self.gender = gender
    def __str__(self):
        return '(Person: %s, %s)' % (self.name, self.gender)
#若直接输入p,结果为说明是什么类型变量以及地址
#因为 Python 定义了__str__()和__repr__()两种方法,__str__()用于显示给用户,而__repr__()用于显示给开发人员。

更多关于Python相关内容可查看本站专题:《Python数据结构与算法教程》、《Python Socket编程技巧总结》、《Python函数使用技巧总结》、《Python字符串操作技巧汇总》及《Python入门与进阶经典教程》

cmp()

#请修改 Student 的 __cmp__方法,让它按照分数从高到底排序,分数相同的按名字排序。
class Student(object):

    def __init__(self, name, score):
        self.name = name
        self.score = score

    def __str__(self):
        return '(%s: %s)' % (self.name, self.score)

    __repr__ = __str__

    def __cmp__(self, s):
        if self.score>s.score:
            return -1
        if self.score<s.score:
            return 1
        if self.score == s.score:
            if(self.name<s.name):
                return -1
            if(self.name>s.name):
                return 1
            return 0

L = [Student('Tim', 99), Student('Bob', 88), Student('Alice', 99)]
print sorted(L)

#对于一个列表中有相同的数据类型的数据对象,那么可以使用sorted排序,并且有默认的比较方法,如果需要定义的排序比较办法,则可以重写特殊方法,再调用sorted()会自动调用。

希望本文所述对大家Python程序设计有所帮助。

len()

如果一个类表现得像一个list,要获取有多少个元素,就得用 len() 函数。要让 len() 函数工作正常,类必须提供一个特殊方法len(),它返回元素的个数。

澳门新萄京官方网站 25

例题

class Fib(object):

    def __init__(self, num):
        a,b,L=0,1,[]
        for n in range(num):
            L.append(a)
            a,b=b,a b  #这里很巧妙
        self.numbers=L


    def __str__(self):
        return str(self.numbers)

    __repr__=__str__


    def __len__(self):
        return len(self.numbers)

f = Fib(10)
print f
print len(f)

#[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
#10

您可能感兴趣的文章:

  • python如何定义带参数的装饰器
  • 介绍Python的@property装饰器的用法
  • Python中的各种装饰器详解
  • 深入理解python中的闭包和装饰器
  • Python装饰器的函数式编程详解
  • 详解Python中的装饰器、闭包和functools的教程
  • 巧用Python装饰器 免去调用父类构造函数的麻烦
  • Python中的多重装饰器
  • python重试装饰器示例
  • 实例讲解Python编程中@property装饰器的用法
  • Python自定义装饰器原理与用法实例分析

自定义类型的数据加减乘除

add() sub() mul() div()

类型转换

class Rational(object):
    def __init__(self, p, q):
        self.p = p
        self.q = q
    def __int__(self):
        return self.p // self.q


#如果要把 Rational 转为 int:
r = Rational(12, 5)  #这里是把有理数对象记为r,再把r传入int进行强制转化
n = int(r)

#要让int()函数正常工作,只需要实现特殊方法__int__()

class Rational(object):
    def __init__(self, p, q):
        self.p = p
        self.q = q

    def __int__(self):
        return self.p // self.q

    def __float__(self):
        return float(self.p)/self.q

print float(Rational(7, 2))
print float(Rational(1, 3))

# python2.7 是整数除法,\仍然是,3.x里面\是整数除法,是浮点数除法

@property

若采用动态设置属性的方法,可能出现值修改异常,无法检测修改的值是否符合条件,若用set和get的方法设置属性值,又没有直接对象.属性进行设置方便。于是出现了@property这个装饰器函数。

具体是一组,@property是只读属性,方法名直接使用属性名,返回想要获取的属性值,对应的有@属性.setter,再定义属性名相同的函数,并且传入self和对应属性值进行设置。

#使用set get设置和获得属性值
class Student(object):
    def __init__(self, name, score):
        self.name = name
        self.__score = score
    def get_score(self):
        return self.__score
    def set_score(self, score):
        if score < 0 or score > 100:
            raise ValueError('invalid score')
        self.__score = score

澳门新萄京官方网站 26

python中的@property

#获取值以及设置都跟普通设置属性一样了
>>> s = Student('Bob', 59)
>>> s.score = 60
>>> print s.score
60
>>> s.score = 1000
Traceback (most recent call last):
  ...
ValueError: invalid score

slot()

由于Python是动态语言,任何实例在运行期都可以动态地添加属性。如果要限制添加的属性,例如,Student类只允许添加 name、gender和score 这3个属性,就可以利用Python的一个特殊的slots来实现。

#__slots__是指一个类允许的属性列表,__slots__的目的是限制当前类所能拥有的属性,如果不需要添加任意动态的属性,使用__slots__也能节省内存。
class Student(object):
    __slots__ = ('name', 'gender', 'score')
    def __init__(self, name, gender, score):
        self.name = name
        self.gender = gender
        self.score = score

#继承下的扩展课设置属性列表
class Person(object):

    __slots__ = ('name', 'gender')

    def __init__(self, name, gender):
        self.name = name
        self.gender = gender

class Student(Person):

    __slots__ = ('score')

    def __init__(self,name,gender,score):
        super(Student,self).__init__(name,gender)

        #语法为super(子类名,self).__init__(其余属性),其余属性中不写self,因为不用显示传入
        self.score=score

s = Student('Bob', 'male', 59)
s.name = 'Tim'
s.score = 99
print s.score

call()

在python中,函数也是一个对象,因此实例这个对象也可以像函数一样直接调用,只要在实例的类中声明了call()方法。

澳门新萄京官方网站 27

实例像函数一样调用的例子

#定义一个斐波那契数列,使用__call__()特殊方法,让调用更简单,这里因为使用实例直接调用,是直接调用call函数,不会再经过__init__()函数,因此初始化应该写在call函数里面
class Fib(object):
    def __call__(self,num):
        a,b,L=0,1,[]
        for n in range(num):
            L.append(a)
            a,b=b,a b
        return L

f = Fib()
print f(10)

本文由澳门新萄京官方网站发布于www.8455.com,转载请注明出处:澳门新萄京官方网站python自带的八个装饰器,p

关键词: