学习python类

类:
Python 类提供了面向对象编程的所有基本特征: 允许多继承的类继承机制, 派生类可以重写它父类的任何方法, 一个方法可以调用父类中重名的方法. 对象可以包含任意数量和类型的数据成员. 作为模块, 类也拥有 Python 的动态特征: 他们可以被动态创建, 并且可以在创建之后被修改.
名称和对象:对象都具有个别性, 多个名称(在多个作用域中) 可以被绑定到同一个对象上. 这就是其他语言中所谓的别名。
作用域和命名空间:
命名空间 是从名称到对象的映射。命名空间是在不同时刻创建的,并且有着不同的生命期。
看了半天没有理解到!!!!感觉一脸懵X.然后翻了一下地球,找到了基本能理解的东东:
#python 中的函数传值还是传引用
# a = 1
# def setvalue(arg):
# arg = 100
# print(arg)
# setvalue(a)
# print(a)
# #会发现最后打印出的 a 仍然是 1 ,看起来像是传值调用
# a = [1]
# def setvalue(arg):
# arg[0] = 100
# print(arg[0])
# setvalue(a)
# print(a[0])
#结果 a 中的数值已经修改成了 100
# a = 1 #1
# a = 2 #2
# b = a #3
# del a
# 正确的理解是 a 引用了 1 这个对象或者将 a 绑定给了 1 ,
# ,而不是将 1 这个值赋给 a 。
# 深入点说,就是 1 这个对象的所有属性包括值都只存在自身,
# a 只是在 1 上打了个标签,并没有将实际的数据拷贝到自身!
# 你只是可以通过命名 a 能够访问到 1 这个对象的信息。
# 而如果执行了上面语句 4 ,
# 含义就是在对象上删掉 a 这个标签,
# 在通过 a 访问时就会报a命名未定义的错误
# 语句 2 会删除掉a在1上的标签,
# 触发python的垃圾回收机制,
# 然后语句 3 会将 b 也绑定到2这个对象上。
#
# 再回到最先的例子中,用刚谈到的对象概念去重新理解。
# 例子1中,在调用函数 setvalue 时,
# 只是将参数 arg 也绑定到 a 所引用的对象 1,
# 但是在 setvalue 函数中,删除掉了 arg 在对象 1 上的标签,
# 重新绑定到了对象 100 上,对 a 是没有影响的。
# 在例子2中,arg 也绑定到 [0] 这个列表对象上。
# 函数中的操作仍然是对 a[0] 这个对象的操作,
# 所以结果肯定是同时影响到已经绑定到 a[0] 上的所有变量的。
# 最后回到开始的问题,到底是传值还是传引用呢?其实都不是,python中可以理解为传对象。
# a = 1
#
#
# def setvalue():
# global a
# a = 100
#
#
# setvalue()
# print(a)
# 简单的解释一下,因为在第一个例子中,函数中的 a 是局部变量,作用域只在函数内,所以不影响函数外的命名空间。
# 第二个例子中,使用了 global 关键字,作用是将函数内对 a 的操作影响扩展到全局,所以函数外的结果收到了影响。
# 名字空间
# 命名空间的定义:变量到对象的映射集合。一般都是通过字典来实现的。主要可以分为三类:
# 内置命名空间
# 函数的本地命名空间
# 模块的全局命名空间
# 对于模块的全局命名空间,因为有着模块名的前缀,所以互相是没有影响的。
# 比如模块A和B都有c变量,那么通过A.c和B.c来使用是不冲突的。
# 这三种命名空间也有着自己的生存周期,
# 除了第二个函数的本地命名空间生存周期只在函数的调用开始到结束,
# 其他两个的生存周期都是可以看做持续到解释器退出的。
# 作用
#
# 命名空间的作用:程序在直接访问变量时,会在当前的命名空间内查找。
# 这里稍微拓展一下,import导入模块的本质,就是将其他模块的类、函数、变量等对象加入到程序的命名空间。
# 再谈的深一点,python 中类的继承也是通过命名空间来实现的!这个下次笔记再说。。跑偏了
#
# 作用域 就是一个 Python 程序可以直接访问命名空间的正文区域。
# 也可以理解是多种层级命名空间的叠加作用。
# 在一个python程序中,直接访问一个变量,
# 会从内到外依次访问所有的作用域直到找到,
# 否则会报未定义的错误。可以具体分为以下四个作用域:
#
# Local(innermost)
# 包含局部变量,比如一个函数/方法内部。
# Enclosing
# 包含了非局部(non-local)也非全局(non-global)的变量。
# 比如两个嵌套函数,内层函数可能搜索外层函数的namespace,但该namespace对内层函数而言既非局部也非全局。
# Global(next-to-last)
# 当前脚本的最外层,比如当前模块的全局变量。
# Built-in(outtermost)
# Python builtin 模块。包含了内建的变量/关键字等。
# 一个命名的作用域在它初次定义的时候确定,
# 如果在当前作用域找不到命名时,
# 会到外层作用域中寻找相应的命名,最后回到全局作用域和内置作用域中寻找。
# 也就是按照LEGB的顺序来寻找一个命名对应的对象。
# def test():
# b = 200
# def test2():
# b = 100
# print(b)
# test2()
# print(b)
# b = 300
# print(b)
# 函数 test2() 中访问b时,在本地作用域率先找到 b=100 这条语句,
# 所以由100这个对象起作用。在 test() 中,它的本地作用域中b的引用为200,不会去 test2() 中去搜索。
# 如果删除掉 test2() 中 b=100的语句,那么test2函数调用时,在本地作用域找不到b的引用,会向上级enclosing作用域寻找,
# 成功找到b的引用200,所以200在test2函数中生效!
# def test():
# print a
# a = 100
# a = 200
# test()
# 这个例子会报错,因为在 test() 函数中,因为本地作用域有命名a的引用操作,
# 所以 print a 会优先使用本地作用域的命名。但是定义在使用之后,所以会报错。
#
# 事实上,所有引入新命名的操作都作用于局部作用域。
#
# 官方文档这句话的意思,这里的局部作用域要以相对角度去理解
# global、nonlocal
#
# 通过 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)
# Globals() Locals()
# 这两个方法是关于返回作用域的函数,
# 前者返回全局作用域。后者返回当前的本地作用域。
# 用这两个函数可以帮助理解namespace和scope,直接贴上我写的一段代码:
import os
from sys import argv
class test:
pass
def test2(arg1,arg2):
print(locals())
return arg1 + arg2
def test3():
b = 2
def test4():
b = 200
return b
test4()
print(locals())
a = 1
b = 100
test2(a,b)
test3()
print(globals())
# 第一个字典记录的是test2()函数的本地作用域,可以看到只有两个参数的命名。
# 第二个字典是test3()函数的本地作用域,有一个函数对象和一个命名。
# 第三个是这个py文件的全局作用域信息,除了py文件中定义的函数、类、变量等,
# 还有一些特殊变量__name__ __doc__ 内置模块 __builtins__
# 我们引入的 os 模块也是作为一个模块对象,但是不同的是通过 form sys import argv
# 来引入的 argv 已经和原模块脱离联系,我们已经在本py文件中重新拷贝了一份
总结:
命名空间就是一个集合,变量到对象的集合,程序在访问变量的时候,在那个区域里面找,这个区域就是命名空间,可以是内置的命名空间,函数本地的空间,模块的全局空间,x=a就是在当前
的命名空间中增加x到a的映射.

posted on 2017-08-28 16:02  Jt00  阅读(152)  评论(0编辑  收藏  举报

导航