Python:类
- 概述:类的特点
- 作用域和命名空间。
- 类的详解:(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程序员。
定义
A 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在函数被调用时创建,在函数返回或抛出一个不在函数内处理的错误时被删除。
作用域
A 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。
类的详解
类定义
- 当进入类定义,创建一个命名空间,作为局部变量和函数的局部作用域。
- 离开类定义,会创建一个类对象。a class object。
- 类名称和这个类对象绑定在一起。
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()
- 首先,实例x的类会在自身作用域搜索Myclass.f,如果f是一个函数对象,则
- 创建一个method object:它是通过把实例对象x和函数对象f打包到一起后产生的一个抽象的对象。
- 当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:类的更多相关文章
- Python类中super()和__init__()的关系
Python类中super()和__init__()的关系 1.单继承时super()和__init__()实现的功能是类似的 class Base(object): def __init__(sel ...
- LightMysql:为方便操作MySQL而封装的Python类
原文链接:http://www.danfengcao.info/python/2015/12/26/lightweight-python-mysql-class.html mysqldb是Python ...
- python 类属性与方法
Python 类属性与方法 标签(空格分隔): Python Python的访问限制 Python支持面向对象,其对属性的权限控制通过属性名来实现,如果一个属性有双下划线开头(__),该属性就无法被外 ...
- python 类以及单例模式
python 也有面向对象的思想,则一切皆对象 python 中定义一个类: class student: count = 0 books = [] def __init__(self ...
- Python类的特点 (1):构造函数与方法
Python中,类的特点: #encoding:utf-8 class Parent(object): x=1 #x是Parent类的属性(字段) def __init__(self): print ...
- Python类属性,实例属性
1.Python类数据属性:定义在类里面但在函数外面的变量,它们都是静态的. #一段很简单的代码,但反应了很多 >>> class A(): a=1 #一个类里面有个属性a > ...
- python类及其方法
python类及其方法 一.介绍 在 Python 中,面向对象编程主要有两个主题,就是类和类实例类与实例:类与实例相互关联着:类是对象的定义,而实例是"真正的实物",它存放了类中 ...
- python类的定义和使用
python中类的声明使用关键词class,可以提供一个可选的父类或者说基类,如果没有合适的基类,那就用object作为基类. 定义格式: class 类名(object): "类的说明文档 ...
- Python类的探讨
我们下面的探讨基于Python3,我实际测试使用的是Python3.2,Python3与Python2在类函数的类型上做了改变 1,类定义语法 Python类定义以关键字class开头,一个类定义例 ...
- python - 类成员修饰符
在java,c#类的成员修饰符包括,公有.私有.程序集可用的.受保护的. 对于python来说,只有两个成员修饰符:公有成员,私有成员 成员修饰符是来修饰谁呢?当然是修饰成员了.那么python类的成 ...
随机推荐
- Django-DRF(路由与扩展功能)
一. 视图集与路由的使用 使用视图集ViewSet,可以将一系列逻辑相关的动作放到一个类中: list() 提供一组数据 retrieve() 提供单个数据 create() 创建数据 update( ...
- 【VS开发】CFormView
原文地址:CFormView作者:罗纳尔多 CFormView是MFC使用无模式对话框的一个典型例子.CFormView是基于对话框模板创建的视,它的直接基类是CSrcollView,CSrcollV ...
- MySQL_数据库命令
Mysql基础命令 开启MySQL服务:net start mysql 关闭MySQL服务:net stop musql 进入mysql:mysql -h localhost -u root -p 1 ...
- ZOJ Problem Set - 1009
1.参考 http://blog.csdn.net/xiaogugood/article/details/17922105 这篇博客对算法介绍的很详细,我看这道题的时候,将题目理解出错,所以进入了一个 ...
- Infix to Postfix Expression
Example : Infix : (A+B) * (C-D) ) Postfix: AB+CD-* 算法: 1. Scan the infix expression from left to rig ...
- (5.3.2)数据库迁移——SSIS包批量导出
SSIS连接出错 原因 : ssms 工具 不是 admin 权限 打开的 SSIS包批量导出代码 use msdb go IF OBJECT_ID('msdb.dbo.usp_ExportS ...
- python列表一
1.列表数据类型 列表是一个值,它包含多个值构成,也可包含其他列表,其内的表项用逗号分隔 列表值:作为一个值可以保存在变量中,或传递给函数,像所有其他值一样. #不是指括号内的值 表项:列表中的值, ...
- Oracle创建表空间、创建用户,给用户分配表空间以及可操作权限
创建表空间一共可分为四个步骤 具体脚本如下: 第1步:创建临时表空间 create temporary tablespace yd_temp tempfile 'D:\oracledata ...
- hdu 6601 区间条件极值 - 区间 最大 三角形周长
题目传送门//res tp hdu 目的 对长度为n的区间,给定q个子区间,求其元素能构成三角形的最大周长.有多组测试. n 1e5 q 1e5 ai [1,1e9] (i∈[1,n]); 数据结构 ...
- django初步了解2
目录 django初步了解2 表的字段增删改查 数据的增删改查 反向解析和分组 路由分发 名称空间 伪静态 虚拟环境 django初步了解2 表的字段增删改查 新增的字段 1.直接提供默认值 defa ...