类
与其他编程语言相比,Python 的类机制用最少的新的语法和语义引入了类。它是 C++ 和 Modula-3 类机制的混合。Python 的类提供了面向对象编程的所有标准功能: 类继承机制允许多重继承,派生类可以覆盖其基类的任意方法或嵌套类,方法能够以相同的名称调用基类中的方法。对象可以包含任意数量和种类的数据。就像模块一样,类也具有Python的动态特性:它们在运行时创建,并且可以在创建后进一步修改。
class ClassName():
# init
# methods
名称和对象
对象是单个的,多个名称(在多个范围中)可以绑定到同一个对象。这在其他语言中称为别名。第一眼看Python,这种特性并不讨喜,当处理不可变的基本类型(数字,字符串,元组)时可以安全地忽略。然而,它对于涉及可变对象(例如列表,字典和大多数其他类型)的Python代码的语义可能有令人惊讶的影响。这通常用于程序的本身的方便,因为别名在某些方面表现得像指针。例如,传递一个对象的开销是很小的,因为在实现上只是传递了一个指针;如果函数修改了参数传递的对象,调用者也将看到变化 —— 这就避免了类似 Pascal 中需要两个不同参数的传递机制。
Python作用域和命名空间
命名空间 是从名称到对象的映射。大多数命名空间目前实现为Python字典,但通常不会以任何方式(性能除外)引人注意,并且它可能会在将来更改。以下有一些命名空间的例子:内置名称集(包括函数名列如 abs() 和内置异常的名称);模块中的全局名称;函数调用中的局部名称。在某种意义上的一组对象的属性也形成一个命名空间。关于命名空间需要知道的重要一点是不同命名空间的名称绝对没有任何关系;例如,两个不同模块可以都定义函数 maximize 而不会产生混淆 —— 模块的使用者必须以模块名为前缀引用它们。
作用域 是 Python 程序中可以直接访问一个命名空间的代码区域。这里的“直接访问”的意思是用没有前缀的引用在命名空间中找到的相应的名称。
虽然作用域是静态确定的,但是使用它们时是动态的。程序执行过程中的任何时候,至少有三个嵌套的作用域,它们的命名空间是可以直接访问的:
- 搜索最内层包含局部命名的作用域
- 从最近的封闭范围开始搜索的任何封闭函数的作用域都包含非本地名称,但也包含非全局名称
- 倒数第二个作用域包含当前模块的全局名称
- 做好搜索的作用域是最外面包含内置命名的命名空间
name = 'zz'
def f1():
name = 'gg'
def f2():
name = 'hh'
print(name)
f2()
f1()
上面的嵌套函数,相信学过函数的人都知道,最后会输出'hh',当Python中有作用域链时,变量会由内往外找。
Python的一个特别之处在于——如果没有使用 global 语法——其赋值操作总是在最里层的作用域。赋值不会复制数据——只是将命名绑定到对象。删除也是如此: del x 只是从局部作用域的命名空间中删除命名 x 。事实上,所有引入新命名的操作都作用于局部作用域:特别是 import 语句和函数定义将模块名或函数绑定于局部作用域。
global 语句可以用来指明某个特定的变量位于全局作用域并且应该在那里重新绑定; nonlocal 语句表示否定当前命名空间的作用域,寻找父函数的作用域并绑定对象。
def scope_test():
def do_local():
spam = "local spam"
def do_nonlocal():
nonlocal spam
spam = "nonlocal spam"
def do_global():
global spam
spam = "global spam"
spam = "test spam"
do_local()
print("After local assignment:", spam)
do_nonlocal()
print("After nonlocal assignment:", spam)
do_global()
print("After global assignment:", spam)
scope_test()
print("In global scope:", spam)
After local assignment: test spam
After nonlocal assignment: nonlocal spam
After global assignment: nonlocal spam
In global scope: global spam
注意,local 的赋值(默认行为)没有改变 scope_test 对spam 的绑定。nonlocal 赋值改变了 scope_test 对 spam 的绑定, global 赋值改变了模块级别的绑定。
你也可以看到在 global 语句之前没有对 spam 的绑定。
Python类的特性
- 每个类可以实例化多个对象。经由类创建的新对象都能获得自己的命名空间,能独立存放数据。
- 经由集成扩充类的属性。自定义类之后,可建立命名空间的分层架构,在类外部重新定义其属性来扩充此类,定义多项行为是更优于其他工具。
- 运算符重载(overload)。经由特定的协议来定义类的对象,响应内置类型的运算,如切片、索引等。
一般来说,绑定(Binding)会牵引方法的调用。简单地说,当实例去调用方法时才有绑定的操作。根据Python程序设计语言使用的惯例,定义方法的第一个参数必须是自己,习惯上使用self来表示,代表创建类后实例化的对象。self类似其他面向对象语言例如java中的this,指向对象本身。
class Car:
def createCar(self, name, color):
self.name = name
self.color = color
def getInfo(self):
print('名字:{0}, 颜色:{1}'.format(self.name,self.color))
car = Car()
car.createCar('Benz', 'blue')
car.getInfo()
跟java很像的,懂得自然懂。
先构造再初始化对象
通常,可以在定义类的过程中将类初始化。其他的程序设计语言会将构造和初始化用一个步骤来完成,通常采用构造函数(Constructor)。Python程序设计语言则稍微有些不同,它维持两个步骤来实现:
- __new__()方法创建对象
- __init__()方法初始化对象
class newClass:
def __new__():
return object.__new__()
def __init__():
#init
设置、检查对象属性
BIF | 说明 |
getattr() | 存取对象属性 |
hasattr(obj, name) | 检查某属性是是否存在 |
setattr() | 设置属性 |
delattr(obj, name) | 删除一个属性 |
类与修饰器
修饰器(Decorator)是指经过定义的函数或类,Python程序以@decorator语法来支持修饰器。
首先一个很重要的一点:函数在Python中是一等公民。函数在Python中也视为对象。
下面举一个简单的例子:
def discount(price):
if price() >= 50.0:
return lambda : price() * 0.9
else:
return lambda : price()
@discount
def price():
return 100.0
print(price())
>>>90.0
另一个例子:
def output(func):
def inputN(x, y):
x, y = eval(input('Two numbers:'))
return func(x, y)
return inputN
@output
def plus(x, y):
return x**2 + y**2
@output
def minus(x, y):
return x**2 - y**2
a, b = 0, 0
print('平方和:', plus(a, b))
print('平方差:', minus(a, b))
含参修饰器
- functools模块提供的函数
为了避免函数引发相关的异常,可以借助functools模块的3个函数进行处理。
- partial()函数
- update_wrapper()函数
- wraps()函数
import time, functools
def Records(some_func):
@functools.wraps(some_func)
def wrapper(*args, **kw):
print('调用了:{}()'.format(some_func.__name__))
return some_func(*args, **kw)
return wrapper
@Records
def AtOnce():
return time.strftime('%Y-%b-%d %H:%M:%S',time.localtime())
print('登录时间:',AtOnce())
调用了:AtOnce()
登录时间: 2018-Apr-13 20:40:31