|
|
|
|
@ -0,0 +1,113 @@
|
|
|
|
|
##什么是动态语言?
|
|
|
|
|
Dynamic Programming Language (动态语言或动态编程语言) 动态语言,准确地说,是指程序在运行时可以改变其结构:新的函数可以被引进,已有的函数可以被删除等在结构上的变化。比如众所周知的ECMAScript(JavaScript)便是一个动态语言。除此之外如Ruby、Python等也都属于动态语言,而C、C++等语言则不属于动态语言。
|
|
|
|
|
为什么说Python是一门动态语言?
|
|
|
|
|
看下面这个例子:
|
|
|
|
|
def choose_class(name):
|
|
|
|
|
if name == 'foo':
|
|
|
|
|
class Foo(object):
|
|
|
|
|
pass
|
|
|
|
|
return Foo # 返回的是类,不是类的实例
|
|
|
|
|
else:
|
|
|
|
|
class Bar(object):
|
|
|
|
|
pass
|
|
|
|
|
return Bar
|
|
|
|
|
不难看出,Python是可以实现动态类的创建类(在任意代码位置,符合正确的书写格式),或者给类增加删除属性。因为类也是对象,你可以在运行时动态的创建它们,就像其他任何对象一样。你可以在函数中创建类,使用class关键字即可。
|
|
|
|
|
可能你觉得还不够动态,因为你仍然需要自己编写整个类的代码。由于类也是对象,所以它们必须是通过什么东西来生成的才对。当你使用class关键字时,Python解释器自动创建这个对象。但就和Python中的大多数事情一样,Python仍然提供给你手动处理的方法。内建函数中有一个名叫type的内建函数,这个内建函数古老但强大的函数, 它能够让你知道一个对象的类型是什么,就像这样:
|
|
|
|
|
|
|
|
|
|
>>> MyShinyClass = type('MyShinyClass', (), {}) # 返回一个类对象
|
|
|
|
|
>>> print MyShinyClass<class '__main__.MyShinyClass'
|
|
|
|
|
>>>> print MyShinyClass() # 创建一个该类的实例
|
|
|
|
|
<__main__.MyShinyClass object at 0x8997cec>另附type使用方法:
|
|
|
|
|
#type(类名, 父类的元组(针对继承的情况,可以为空),包含属性的字典(名称和值))
|
|
|
|
|
|
|
|
|
|
##如何动态添加属性?
|
|
|
|
|
###2.1 添加对象属性
|
|
|
|
|
class Obj(object):
|
|
|
|
|
def __init__(self):
|
|
|
|
|
self.name = '张亚飞'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
obj = Obj()
|
|
|
|
|
obj.age = 23
|
|
|
|
|
print(obj.age)
|
|
|
|
|
obj2 = Obj()
|
|
|
|
|
print(obj2.age)
|
|
|
|
|
由以上代码可知,Obj类有两个属性:name和age。通过[对象名.属性名]给类对象obj动态添加了对象属性addr,而Obj的另一个类对象obj2却不能调用这个属性。
|
|
|
|
|
注:通过对象名添加的对象属性,只有这个对象能使用
|
|
|
|
|
###2.2 添加类属性
|
|
|
|
|
Obj.score = 100
|
|
|
|
|
print(obj.score)
|
|
|
|
|
print(obj2.score)
|
|
|
|
|
由以上代码可知,通过[类名.属性名]给类Obj动态添加了类属性addr,Obj的类对象obj和obj2都能调用这个属性
|
|
|
|
|
注:通过类名添加的类属性,这个类的所有对象都能使用
|
|
|
|
|
|
|
|
|
|
##如何动态添加方法?
|
|
|
|
|
类中有三种方法,实例方法,静态方法和类方法,三种方法的区别如下:
|
|
|
|
|
实例方法:需要绑定要一个对象上,第一个参数默认使用self,会把对象作为第一个参数传递进来
|
|
|
|
|
静态方法:使用装饰器@staticmethod进行定义,类和对象都可以调用,不需要默认参数
|
|
|
|
|
类方法:使用装饰器@classmethod进行定义,类和对象都可以调用,第一个参数默认使用cls,会把类作为第一个参数传递进来
|
|
|
|
|
from types import MethodType
|
|
|
|
|
|
|
|
|
|
class Obj(object):
|
|
|
|
|
# __slots__ = ('name', 'age')
|
|
|
|
|
|
|
|
|
|
def __init__(self):
|
|
|
|
|
self.name = '张亚飞'
|
|
|
|
|
|
|
|
|
|
def set_score(self, score):
|
|
|
|
|
self.score = score
|
|
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
|
def static_func():
|
|
|
|
|
print('static_func')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
|
def class_func(cls):
|
|
|
|
|
print('class_method')
|
|
|
|
|
类中有三种方法,实例方法,静态方法和类方法,三种方法的区别如下:
|
|
|
|
|
实例方法:需要绑定要一个对象上,第一个参数默认使用self,会把对象作为第一个参数传递进来
|
|
|
|
|
静态方法:使用装饰器@staticmethod进行定义,类和对象都可以调用,不需要默认参数
|
|
|
|
|
类方法:使用装饰器@classmethod进行定义,类和对象都可以调用,第一个参数默认使用cls,会把类作为第一个参数传递进来
|
|
|
|
|
# 动态添加实例方法
|
|
|
|
|
obj = Obj()
|
|
|
|
|
obj.set_score = MethodType(set_score, obj)
|
|
|
|
|
obj.set_score(99)
|
|
|
|
|
print(obj.score) # 99
|
|
|
|
|
obj2.set_score(99) # AttributeError: 'Obj' object has no attribute 'set_score'
|
|
|
|
|
由以上代码可知,Obj类有一个方法:eat()方法。通过[types.MethodType(方法名, 对象名)]给类对象zhangsan动态添加了对象方法run(),同理,Obj的另一个类对象lisi不能调用这个方法
|
|
|
|
|
注:通过对象名添加的对象方法,只有这个对象能使用
|
|
|
|
|
|
|
|
|
|
# 添加静态方法
|
|
|
|
|
Obj.static_func = static_func
|
|
|
|
|
Obj.static_func()
|
|
|
|
|
obj.static_func()
|
|
|
|
|
obj2.static_func()
|
|
|
|
|
由以上代码可知,通过[类名.静态方法名]给类Obj动态添加了静态方法static_func(),Obj类的Obj对象和obj2对象都能调用这个方法
|
|
|
|
|
注:通过类名添加的静态方法,这个类及这个类的所有对象都能使用
|
|
|
|
|
# 添加类方法
|
|
|
|
|
Obj.class_func = class_func
|
|
|
|
|
Obj.class_func()
|
|
|
|
|
obj.class_func()
|
|
|
|
|
obj2.class_func()
|
|
|
|
|
由以上代码可知,通过[类名.类方法名]给类Obj动态添加了类方法class_func(),Obj类的obj对象和obj2对象都能调用这个方法
|
|
|
|
|
注:通过类名添加的类方法,这个类及这个类的所有对象都能使用
|
|
|
|
|
##__slots__的使用
|
|
|
|
|
通过以上内容,我们知道如何动态的添加属性和方法。但是,如果我们想要限制class的属性该怎么办?例如:只允许Obj实例添加name和age属性。为了达到这个目的,Python允许在定义class的时候,定义一个特殊变量__slots__来限制该class能添加的属性。
|
|
|
|
|
class Obj(object):
|
|
|
|
|
__slots__ = ('name', 'age')
|
|
|
|
|
|
|
|
|
|
obj = Obj()
|
|
|
|
|
obj.name = 'zhangyafei'
|
|
|
|
|
obj.age = 23
|
|
|
|
|
obj.score = 99 # AttributeError: 'Obj' object has no attribute 'score'
|
|
|
|
|
Obj.score = 100
|
|
|
|
|
print(obj.score) # 100
|
|
|
|
|
obj.score = 99 # AttributeError: 'Obj' object attribute 'score' is read-only
|
|
|
|
|
通过以上代码可知,__slots__对Obj类的动态添加没有限制,而Obj类对象obj不能再动态添加对象属性和方法。
|
|
|
|
|
对于__slot__有以下几个需要注意的地方:
|
|
|
|
|
__slots__只对类对象进行限制,不对类进行限制
|
|
|
|
|
__slots__不仅限制类对象的属性,还限制类对象的方法
|
|
|
|
|
__slots__仅对当前类起作用,对继承的子类不起作用
|
|
|
|
|
在子类中定义__slots__,子类允许定义的属性就是自身的__slots__加上父类的__slots__
|
|
|
|
|
|