http://www.cnblogs.com/elie/p/5876210.html
http://www.360doc.com/content/14/0811/11/16044571_400987060.shtml
Python中3种方式定义类方法, 常规方式, @classmethod修饰方式, @staticmethod修饰方式.
class A(object):
def foo(self, x):
print("executing foo(%s,%s)" % (self, x))
print('self:', self)
@classmethod
def class_foo(cls, x):
print("executing class_foo(%s,%s)" % (cls, x))
print('cls:', cls)
@staticmethod
def static_foo(x):
print("executing static_foo(%s)" % x)
a = A()
普通的类方法foo()需要通过self参数隐式的传递当前类对象的实例。 @classmethod修饰的方法class_foo()需要通过cls参数传递当前类对象。@staticmethod修饰的方法定义与普通函数是一样的。
self和cls的区别不是强制的,只是PEP8中一种编程风格,slef通常用作实例方法的第一参数,cls通常用作类方法的第一参数。即通常用self来传递当前类对象的实例,cls传递当前类对象。
foo方法绑定对象A的实例,class_foo方法绑定对象A,static_foo没有参数绑定。
>>> print(a.foo)
>
>>> print(a.class_foo)
>
>>> print(a.static_foo)
foo可通过实例a调用,类对像A直接调用会参数错误。
>>> a.foo(1)
executing foo(<__main__.A object at 0x0278B170>,1)
self: <__main__.A object at 0x0278B170>
>>> A.foo(1)
Traceback (most recent call last):
File "", line 1, in
TypeError: foo() missing 1 required positional argument: 'x'
但foo如下方式可以使用正常,显式的传递实例参数a。
>>> A.foo(a, 1)
executing foo(<__main__.A object at 0x0278B170>,1)
self: <__main__.A object at 0x0278B170>
class_foo通过类对象或对象实例调用。
>>> A.class_foo(1)
executing class_foo(,1)
cls:
>>> a.class_foo(1)
executing class_foo(,1)
cls:
static_foo通过类对象或对象实例调用。
>>> A.static_foo(1)
executing static_foo(1)
>>> a.static_foo(1)
executing static_foo(1)
class B(A):
pass
b = B()
b.foo(1)
b.class_foo(1)
b.static_foo(1)
# executing foo(<__main__.B object at 0x007027D0>,1)
# self: <__main__.B object at 0x007027D0>
# executing class_foo(,1)
# cls:
# executing static_foo(1)
问题:@staticmethod修饰的方法函数与普通的类外函数,为什么不直接使用普通函数?
@staticmethod是把函数嵌入到类中的一种方式,函数就属于类,同时表明函数不需要访问这个类。通过子类的继承覆盖,能更好的组织代码。
@就是python中的修饰器,装饰器(Decorators)是 Python 的一个重要部分。简单地说:他们是修改其他函数的功能的函数。他们有助于让我们的代码更简短,也更Pythonic(Python范儿)。简而言之,修饰器封装一个函数,并且用这样或者那样的方式来修改它的行为,使得在这个函数运行之前或者之后执行某些动作。
详细解读见:https://blog.csdn.net/xiaojiajia007/article/details/96433150
def minus(f):
print 'minus'
f()
def plus(f):
print 'plus'
f()
def test(a):
if a > 3 :return plus
else: return minus
@test(5)
def xxx():
print 'ok'
# 解释器 首先会解释 @符号后面的代码,如果和上面的代码类似,那么test(5)将会被执行,因为5>3,所以
#会返回一个函数指针plus, plus将下一行的函数指针xxx当作参数传入,直到执行完成。最后输出:
# plus ok
def minus(f):
print 'minus'
f()
@minus
def xxx():
print 'ok'
# minus本身就已经是一个函数指针,所以会直接以xxx作为参数传入,结果会输出
# minus,ok
一个例子如下,下面是一个property class:
class Parrot:
def __init__(self):
self._voltage = 100000
@property
def voltage(self):
"""Get the current voltage."""
return self._voltage
The @property decorator turns the voltage() method into a “getter” for a read-only attribute with the same name, and it sets the docstring for voltage to “Get the current voltage.” 也就是说这么做,就可以生成一个变量名为voltage,且值为100000的只读(read-only)属性(attribute)。若实例化一个 p = Parrot(), 则p.voltage=100000,不能改变,若需要改变,需要使用setter.
转载自:https://www.cnblogs.com/Lambda721/p/6132206.html
考察 Student 类:
class Student(object):
def __init__(self, name, score):
self.name = name
self.score = score
当我们想要修改一个 Student 的 scroe 属性时,可以这么写:
s = Student('Bob', 59)
s.score = 60
但是也可以这么写:
s.score = 1000
显然,直接给属性赋值无法检查分数的有效性。
如果利用两个方法:
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
这样一来,s.set_score(1000) 就会报错。
这种使用 get/set 方法来封装对一个属性的访问在许多面向对象编程的语言中都很常见。
但是写 s.get_score() 和 s.set_score() 没有直接写 s.score 来得直接。
有没有两全其美的方法?----有。
因为Python支持高阶函数,可以用装饰器函数把 get/set 方法“装饰”成属性调用:
class Student(object):
def __init__(self, name, score):
self.name = name
self.__score = score
@property
def score(self):
return self.__score
@score.setter
def score(self, score):
if score < 0 or score > 100:
raise ValueError('invalid score')
self.__score = score
注意: 第一个score(self)是get方法,用@property装饰,第二个score(self, score)是set方法,用@score.setter装饰,@score.setter是前一个@property装饰后的副产品。
现在,就可以像使用属性一样设置score了:
>>> s = Student('Bob', 59)
>>> s.score = 60
>>> print s.score
60
>>> s.score = 1000
Traceback (most recent call last):
...
ValueError: invalid score
说明对 score 赋值实际调用的是 set方法。
另一个例子 点击打开链接
注意到这个神奇的@property,我们在对实例属性操作的时候,就知道该属性很可能不是直接暴露的,而是通过getter和setter方法来实现的。
还可以定义只读属性,只定义getter方法,不定义setter方法就是一个只读属性。
下面的birth是可读写属性,而age就是一个只读属性,因为age可以根据birth和当前时间计算出来。
class Student(object):
@property
def birth(self):
return self._birth
@birth.setter
def birth(self, value):
self._birth = value
@property
def age(self):
return 2014 - self._birth
@property广泛应用在类的定义中,可以让调用者写出简短的代码,同时保证对参数进行必要的检查,这样,程序运行时就减少了出错的可能性。