• 概述:类的特点
  • 作用域和命名空间。
  • 类的详解:(python官方教程摘录)

概述特性

Python在oop方面思想和Ruby一样。同样包括数据封装,继承和多态三大特点。

Python的类提供了面向对象编程的所有标准特性:

  • 类继承机制允许多个基类, ⚠️这点和Ruby不一样,Ruby要求继承的关系是只能有一个父类。
  • 派生类可以覆盖它基类的任何方法,一个方法可以调用基类中相同名称的的方法。
  • 对象可以包含任意数量和类型的数据。
  • 在运行时创建,也可以在创建后修改。

例子:

class Student(object):
"""docstring for Student.""" def __init__(self, name, score):
super(Student, self).__init__()
self.name = name
self.score = score def print_score(self):
print('%s %s' % (self.name, self.score)) bart = Student('Bart Simpson', 59)
lisa = Student('Lisa Simpson', 87)
bart.print_score()
lisa.print_score()
  • 第一行 class Student(object)表示类Student从object继承过来。用的是括号。object类是一切类的父类。
  • 实例一个Student对象的代码类似调用一个函数。⚠️这点和Ruby的写法不一样。(Ruby用到了new关键字)

上面的例子实例对象有两个变量name,score:

>>> bart.name = 'Bart Simpson'
>>> bart.name
'Bart Simpson'

⚠️又和Ruby不同, ruby必须提供name的读方法和写方法。Python不用。

  • __int__方法是类定义的初始化方法,第一个参数self代表类的实例。
  • 类中定义的实例方法,第一个参数永远是self。调用时,无需传递该参数。

数据封装

类内部定义的方法可以访问类实例的数据,无需类的外部调用一个方法来读取数据,这就是数据封装。这些封装数据的函数就是类的方法。

上面的print_score就是类的方法,调用时无需传递参数。

⚠️Python的类的实例对象可以绑定任何外部数据:

>>> bart = Student('Bart Simpson', 59)
>>> lisa = Student('Lisa Simpson', 87)
>>> bart.age = 8 #age并不是类中定义的属性。
>>> bart.age
8
>>> lisa.age
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Student' object has no attribute 'age'

访问限制

用__作为变量前缀的变量,不能被外部直接读取。会报告错误❌。⚠️是两个下划线。

⚠️__xx__这是特殊变量没有访问限制

例子:实例变量.__name

只能通过类内定义一个读取变量的方法来实现。

原理:

python会自动把__xxx这类私有变量,的名字转化为_类名__xxx.所有直接访问是不行的。

⚠️不要在外部直接修改私有变量!!!

实例的方法/函数

内置函数,用于操作实例对象。

  • hasattr(object, name)   参数有2个。如果对象的属性中有name这个字符串, 则返回True。
  • getattr()
  • setattr()

类属性

>>> class Student(object):
... name = 'Student'
>>> s = Student() # 创建实例s
>>> print(s.name) # 打印name属性,因为实例并没有name属性,所以会继续查找class的name属性
Student

⚠️Ruby中定义类属性用@@,例子:@@name。实例变量用@, 例子@xxx。


Python的作用域和命名空间

标签:scope rules,高级Python程序员。

定义

namespace is a mapping from names to objects.

命名空间是一个从名字到对象的映射(指向,明确的路径)。

Most namespaces are currently implemented as Python dictionaries。

大部分都是由字典dict(其他语言也称为hash)实现。

命名空间namespace例子:

  • 内置函数名字和内置表达式名字的集合。
  • 模块中的global names
  • 一次函数调用内的local names
  • 一个对象的属性集合也是一种namespace

注意:不同namespace内的名称之间没有任何关系。

创建命名空间和lifetimes生命周期

在不同的情况下,命名空间被创建并有了各不相同的生命周期。例子;

  • 包括内建函数的命名空间会在Python interpreter启动时创建,并且永远不被删除。
  • 一个模块的全局命名空间在这个模块定义被读入的时候创建。一般会持续到解释器退出。
  • 一个函数的local namespace在函数被调用时创建,在函数返回或抛出一个不在函数内处理的错误时被删除。

作用域

scope is a textual region of a Python program where a namespace is directly accessible.

一个作用域是一个Python程序的文本区域,这个区域的namespace是可以直接访问的。

在执行中,有几种内嵌作领域的命名空间可以被直接访问:

  • 最内部的作用于,它被首先搜索,它包括了local names
  • 任何闭包函数的作用领域,它会被从最近的封闭作用领域开始搜索,包括non-local,也包括non-global names.
  • the next-to-last scope, 包括当前模块的全局名称
  • 最外面的作用领域,被最后搜索,这个命名空间包括内建函数。

命名空间的查找顺序:

 Local首先搜索,包含局部名字的最内层(innermost)作用域,如函数/方法/类的内部局部作用域;

 Enclosing根据嵌套层次从内到外搜索,包含非局部(nonlocal)非全局(nonglobal)名字的任意封闭函数的作用域。如两个嵌套的函数,内层函数的作用域是局部作用域,外层函数作用域就是内层函数的 Enclosing作用域;

 Global倒数第二次被搜索,包含当前模块全局名字的作用域;

 Built-in最后被搜索,包含内建名字的最外层作用域。

Python按照以上LEGB的顺序依次在四个作用域搜索名字,没有搜索到时,Python抛出NameError异常。

用一个类比来理解命名空间与作用域:

  四种作用域相当于我们生活中的国家(Built-in)、省(Global)、市(Enclosing)、县(Local),命名空间相当于公务员花名册,记录着哪个职位是哪个人。国家级公务员服务于全国
民众(全国老百姓都可以喊他办事),省级公务员只服务于本身民众(国家层面的人或者其他省的人我不管),市(Enclosing)、县(Local)也是一个道理。当我们要找某一类领导(例如想找
个警察帮我打架)时(要访问某个名称),如果我是在县(Local)里头,优先在县里的领导花名册中找(优先在自己作用域的命名空间中找),县里花名册中没警察没有就去市里的花名册找(往
上一层作用域命名空间找),知道找到国家级都还没找到,那就会报错。如果省级民众想找个警察帮忙大家,不会找市里或者县里的,只会找自己省里的(其它省都不行),或者找国家级的。国家、
省、市、县肯定一直都在那里,可不会移动(作用域是静态的);领导可以换届,任期移到就换人(命名空间是动态的,每次调用函数都会新的命名空间,函数执行

Python的特殊之处

如果不存在生效的 global 语句 -- 对名称的赋值总是进入最内层作用域。

赋值不会复制数据 --- 它们只是将名称绑定到对象。 删除也一样,del x会从局部命名空间的引用中删除对x的绑定。

所有引入的新名称的操作都使用局部作用领域。import声明和函数定义,会在local scope中绑定module或函数名称。

#gloal 用于表示变量生存在全局作用域,并且应当被重新绑定。顶层的绑定。
#nonlocal 表示变量生存在当前作用域的外部,并且应当在其中被重新绑定。

glocal与nonlocal的区别

第一,两者的功能不同。

global关键字修饰变量后标识该变量是全局变量,对该变量进行修改就是修改全局变量,而nonlocal关键字修饰变量后标识该变量是上一级函数中的局部变量,如果上一级函数中不存在该局部变量,nonlocal位置会发生错误。

def f1():
# i = 1
def f2():
nonlocal i
print(i)
i = 2
f2()
print(i) f1()
# SyntaxError: no binding for nonlocal 'i' found

第二,两者使用的范围不同。

  • global关键字可以用在任何地方,包括最上层函数中和嵌套函数中,即使之前未定义该变量,global修饰后也可以直接使用。
  • nonlocal关键字只能用于嵌套函数中,并且外层函数中定义了相应的局部变量,否则会发生错误。
i = 0
def f1():
i = 1
def f2():
global i #重新绑定
print("global", i)
i = 2
f2()
print("local",i) f1()
# 输出:
# global 0
# local 1

作用域是按字面文本来确定的:

  • 在一个模块内定义的函数的全局作用域就是该模块的命名空间,无论该函数从什么地方或以什么别名被调用。
  • 即在函数定义时,就已经确认作用域了。和函数调用时的位置无关!

几个例子:

i = 1

def f1():
print(i) def f2():
i = 2
f1() f2() print(i) #输出
#1
#1

解释:这个例子,说明了函数的外部作用域,是函数定义时的外部代码。

if True:

  i = 1

print(i) # 可以正常输出i的值1,不会报错

解释:这说明了if语句不产生新的作用域, 只有函数/类才会产生新作用域。

for i in range(10):

  pass

print(i) #输出结果是9,而不是NameError

解释: 无关作用域,i被声明,并被赋值。

def test():

    print(i)

  i= 2

i = 0

test()

解释:会报告错误,UnboundLocalError: local variable 'i' referenced before assignment。i已经被占用了。所以不能再被重新声明。

class A(object):

    a = 2

    def fun(self):

        print(a)

new_class = A()

new_class.fun()
#NameError: name 'a' is not defined

解释:还不理解。fun函数的外部作用域中,没有a。


类的详解

类定义

  1. 当进入类定义,创建一个命名空间,作为局部变量和函数的局部作用域。
  2. 离开类定义,会创建一个类对象。a class object。
  3. 类名称和这个类对象绑定在一起。

Class Object

类对象有2种操作,属性引用和实例化。类变量和函数都是属性。

Instance Object

可以对实例对象进行实例属性引用,有2种:

  • data attributes: 在其他语言叫做实例变量instance variables(Ruby, Smalltalk)/ data members(C++)
  • methods:就是从属于一个对象的函数。

例子:

class MyClass:
i = 12345 def f(self):
return 'hello world'
x = MyClass()

x是类的实例对象,x.f是一个method object。具体来说是一个绑定:

<bound method Myclass.f of <__main__.Myclass object at 0x10c6f26d0>>

而MyClass.f是一个function object。<function Myclass.f at 0x10c759c10>

Python的类的实例对象调用方法,会把自身作为第一个参数传入。

解释一下什么是方法对象method object

比如本例子

x.f()
  1. 首先,实例x的类会在自身作用域搜索Myclass.f,如果f是一个函数对象,则
  2. 创建一个method object:它是通过把实例对象x和函数对象f打包到一起后产生的一个抽象的对象。
  3. 当x.f()被调用,会产生一个新的参数list,这个list会提供给Myclass.f。

私有变量和名称改写name mangling

Any identifier of the form __spam (at least two leading underscores, at most one trailing underscore) is textually replaced with _classname__spam, where classname is the current class name with leading underscore(s) stripped.

任何形式为 __spam 的标识符(至少带有两个前缀下划线,至多一个后缀下划线)的文本将被替换为 _classname__spam,其中 classname 为去除了前缀下划线的当前类名称。

请注意,改写规则的设计主要是为了避免意外冲突;

再谈迭代器

for element in [1, 2, 3]:
print(element)

解释:

实际上for语句把[1,2,3]作为参数,传入iter()方法。返回一个定义了__next__()方法的对象,叫做iterator object。

每次使用next(),会返回一个容器中的元素。知道元素用尽,引发StopIteration异常。

类可以通过定义__iter__和__next__函数,就可以对类的实例对象进行定制化了。例子:

class Reverse:
def __init__(self, data):
self.data = data
self.index = len(data) def __iter__(self):
return self def __next__(self):
if self.index == 0:
raise StopIteration
self.index = self.index - 1
return self.data[self.index] rev = Reverse('spam') for char in iter(rev):
print(char)

Python:类的更多相关文章

  1. Python类中super()和__init__()的关系

    Python类中super()和__init__()的关系 1.单继承时super()和__init__()实现的功能是类似的 class Base(object): def __init__(sel ...

  2. LightMysql:为方便操作MySQL而封装的Python类

    原文链接:http://www.danfengcao.info/python/2015/12/26/lightweight-python-mysql-class.html mysqldb是Python ...

  3. python 类属性与方法

    Python 类属性与方法 标签(空格分隔): Python Python的访问限制 Python支持面向对象,其对属性的权限控制通过属性名来实现,如果一个属性有双下划线开头(__),该属性就无法被外 ...

  4. python 类以及单例模式

    python 也有面向对象的思想,则一切皆对象 python 中定义一个类: class student: count = 0         books = [] def __init__(self ...

  5. Python类的特点 (1):构造函数与方法

    Python中,类的特点: #encoding:utf-8 class Parent(object): x=1 #x是Parent类的属性(字段) def __init__(self): print ...

  6. Python类属性,实例属性

    1.Python类数据属性:定义在类里面但在函数外面的变量,它们都是静态的. #一段很简单的代码,但反应了很多 >>> class A(): a=1 #一个类里面有个属性a > ...

  7. python类及其方法

    python类及其方法 一.介绍 在 Python 中,面向对象编程主要有两个主题,就是类和类实例类与实例:类与实例相互关联着:类是对象的定义,而实例是"真正的实物",它存放了类中 ...

  8. python类的定义和使用

    python中类的声明使用关键词class,可以提供一个可选的父类或者说基类,如果没有合适的基类,那就用object作为基类. 定义格式: class 类名(object): "类的说明文档 ...

  9. Python类的探讨

    我们下面的探讨基于Python3,我实际测试使用的是Python3.2,Python3与Python2在类函数的类型上做了改变 1,类定义语法  Python类定义以关键字class开头,一个类定义例 ...

  10. python - 类成员修饰符

    在java,c#类的成员修饰符包括,公有.私有.程序集可用的.受保护的. 对于python来说,只有两个成员修饰符:公有成员,私有成员 成员修饰符是来修饰谁呢?当然是修饰成员了.那么python类的成 ...

随机推荐

  1. Django-DRF(路由与扩展功能)

    一. 视图集与路由的使用 使用视图集ViewSet,可以将一系列逻辑相关的动作放到一个类中: list() 提供一组数据 retrieve() 提供单个数据 create() 创建数据 update( ...

  2. 【VS开发】CFormView

    原文地址:CFormView作者:罗纳尔多 CFormView是MFC使用无模式对话框的一个典型例子.CFormView是基于对话框模板创建的视,它的直接基类是CSrcollView,CSrcollV ...

  3. MySQL_数据库命令

    Mysql基础命令 开启MySQL服务:net start mysql 关闭MySQL服务:net stop musql 进入mysql:mysql -h localhost -u root -p 1 ...

  4. ZOJ Problem Set - 1009

    1.参考 http://blog.csdn.net/xiaogugood/article/details/17922105 这篇博客对算法介绍的很详细,我看这道题的时候,将题目理解出错,所以进入了一个 ...

  5. Infix to Postfix Expression

    Example : Infix : (A+B) * (C-D) ) Postfix: AB+CD-* 算法: 1. Scan the infix expression from left to rig ...

  6. (5.3.2)数据库迁移——SSIS包批量导出

    SSIS连接出错 原因 :    ssms 工具 不是 admin 权限 打开的  SSIS包批量导出代码 use msdb go IF OBJECT_ID('msdb.dbo.usp_ExportS ...

  7. python列表一

    1.列表数据类型 列表是一个值,它包含多个值构成,也可包含其他列表,其内的表项用逗号分隔 列表值:作为一个值可以保存在变量中,或传递给函数,像所有其他值一样.  #不是指括号内的值 表项:列表中的值, ...

  8. Oracle创建表空间、创建用户,给用户分配表空间以及可操作权限

    创建表空间一共可分为四个步骤 具体脚本如下: 第1步:创建临时表空间 create temporary tablespace yd_temp       tempfile 'D:\oracledata ...

  9. hdu 6601 区间条件极值 - 区间 最大 三角形周长

    题目传送门//res tp hdu 目的 对长度为n的区间,给定q个子区间,求其元素能构成三角形的最大周长.有多组测试. n 1e5 q 1e5 ai [1,1e9] (i∈[1,n]); 数据结构 ...

  10. django初步了解2

    目录 django初步了解2 表的字段增删改查 数据的增删改查 反向解析和分组 路由分发 名称空间 伪静态 虚拟环境 django初步了解2 表的字段增删改查 新增的字段 1.直接提供默认值 defa ...