一、python中的对象
1.字符串的函数操作
import sys
def test():
#sys.getrefcount的使用
i = 10_000_000 # 可以这样定义一个较大的整数
print(i,type(i))
print(sys.getrefcount(i)) # i指向10_000_000
print(sys.getrefcount(10_000_000)) # 到目前位置10_000_000被引用了4次
j = 10_000_000 # 令j引用10_000_000
print(sys.getrefcount(i)) # 10_000_000的引用次数增加到了5次
print(sys.path) # 获得当前的python工作路径
'''
10000000 <class 'int'>
4
4
5#\
['D:\\CODE\\demo_py\\temp', 'D:\\CODE\\demo_py', 'D:\\CODE\\demo_py\\function', 'D:\\CODE\\demo_py\\package', 'D:\\CODE\\demo_py\\crawler', 'C:\\Program Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.8_3.8.1776.0_x64__qbz5n2kfra8p0\\python38.zip', 'C:\\Program Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.8_3.8.1776.0_x64__qbz5n2kfra8p0\\DLLs', 'C:\\Program Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.8_3.8.1776.0_x64__qbz5n2kfra8p0\\lib', 'C:\\Users\\lLate\\AppData\\Local\\Microsoft\\WindowsApps\\PythonSoftwareFoundation.Python.3.8_qbz5n2kfra8p0', 'D:\\CODE\\demo_py\\venv', 'D:\\CODE\\demo_py\\venv\\lib\\site-packages']
'''
#round的使用和精度
# "values are rounded to the closest multiple of 10 to the power minus ndigits; if two multiples are equally close,/
# rounding is done toward the even choice." 如果距离两边一样远,会保留到偶数的一边。
print(1.45, round(1.45,1),round(1.46,1))
print('为了促成偶数,放弃“五入”:',round(0.5),round(-0.5),round(2.5),round(125,-1),round(1.45,1))
print('正好促成偶数,保留“五入”:',round(1.5),round(-1.5),round(1.5),round(135,-1),round(1.35,1))
# 1.45 1.4 1.5
# 为了促成偶数,放弃“五入”: 0 0 2 120 1.4
# 正好促成偶数,保留“五入”: 2 -2 2 140 1.4
print(0.1 + 0.2, 0.3 + 0.2) # 有些浮点数在计算机中保存的时候会无限循环,python因此将无限循环截断,从而使得存储的值比实际的值要大
# 0.30000000000000004 0.5
print(round(2.675, 2))
# 2.67 it’s a result of the fact that most decimal fractions can’t be represented exactly as a float,\
# 机器中保存的2.675这个数字就比实际数字要小那么一点点,而不是恰好处于中间位置
# 除非对精确度没什么要求,否则尽量避开用round()函数
print(round(31415.9265, -2), type(round(31415.9265, -2)))
print(f'{31415.9265:.2f}', type(f'{31415.9265:.2f}')) # 作为格式化字符串输出,当数据仅需要展示不需要使用的时候可以这么使用
'''
31400.0 <class 'float'>
31415.93 <class 'str'>
'''
#decimal的高精度计算,其实对浮点数才有用,整数都是可以精准定义的
# from…import *语句与import区别在于:
# import 导入模块,每次使用模块中的函数都要是定是哪个模块。
# from…import * 导入模块,每次使用模块中的函数,直接使用函数就可以了;注因为已经知道该函数是那个模块中的了。
# from decimal import *
import decimal
print(decimal.Decimal(5.55),decimal.Decimal('5.55')) # 只要使用了Decimal就会将数据的类型设置为<class 'decimal.Decimal'>,可以传入字符串
print(decimal.Decimal.from_float(5.55)) # 可以使用decimal.Decimal.from_float()传入字符串
decimal.getcontext().prec = 6 # 设置精度为6,但只对计算有用
print(decimal.Decimal(1.1))
print((decimal.Decimal(1)/decimal.Decimal(7)), "{:.6f}".format(1/7))
print(Decimal(0.8) * Decimal(3), type(Decimal('0.8') * Decimal(3)))
'''
5.54999999999999982236431605997495353221893310546875 5.55
5.54999999999999982236431605997495353221893310546875
1.100000000000000088817841970012523233890533447265625
0.142857 0.142857
2.400000000000000133226762955 2.4 #只要参与计算的Decimal有一个是传入的字符串,结果就会使原样输出
'''
# Python中,(*)会把接收到的参数形成一个元组,而(**)则会把接收到的参数存入一个字典
def f(*args, mid=None, **kwargs):
print(args) # 可以传入多个数据(可变参数),自动转换为元组
print(kwargs) # 可以自动转换为字典
f(1, 2, 3, t=1, z=2, y=3)
a, b, *c = 0, 1, 2, 3 #可以直接传入多个数
print(c)
'''
(1, 2, 3)
{'t': 1, 'z': 2, 'y': 3}
[2, 3]
'''
# *和**当作参数的时候
def test(*args): #输入参数当作元组
print(args, type(args))
def test1(**args): #输入参数当作字典
print(args, type(args))
test(1, 2, 3)
test1(a=1, b=2, c=3)
'''
(1, 2, 3) <class 'tuple'>
{'a': 1, 'b': 2, 'c': 3} <class 'dict'>
'''
#格式化字符串
print ("{} 对应的位置是 {{0}}".format("runoob")) #可以使用大括号 {} 来转义大括号
def test():
pass
print(3 ** -2, -3 ** 2) #"-" 优先级高于 "**"
import operator #可以用于比较操作
print(1 < 3,operator.le(1,3))
repr(123)
print(ord("a"),type(ord("a")),chr(97)) #ord将单个字符转换为ascii对应的数字,chr将数字转换为对应的ascii码
print(divmod(10,3)) #获得商和余数
cplx = 1 + 2j
print(cplx.real, cplx.imag, cplx.conjugate()) #conjugates是共轭复数
str_ = "hello,world!\n"
print(str(str_),repr(str_)) #repr的字符串是给解释器读的,str是给人读的
'''
0.1111111111111111 -9
True True
97 <class 'int'> a
(3, 1)
1.0 2.0 (1-2j)
hello,world!
'hello,world!\n'
'''
from decimal import Decimal
print(pow(Decimal(2),Decimal(3.1))) #pow()计算a^b
#8.574187700290345841563942401
print("abc" < "tzy") #字符串可以直接用"<"符号以ascii比较
str_ = "ppython!"
print(str_.ljust(10,"*")) #总长度为10,用"*"填充,在右边填充
print(str_.rjust(10,"+"))
print(str_.center(10)) #总长度为10,str_居中
print(str_.count("p"))
print(str_.startswith("p",1), str_.endswith("n!")) #从1开始,是否是以"p"开头,是否是以"n"结尾
print(str_.rfind("!"),str_.index("on"))
print(str_.zfill(15)) #在指定字符串的左边填充0
print("++ppython!".zfill(15)) #在"+"中间填充0
print("*/ppython!".zfill(15))
'''
True
ppython!**
++ppython!
ppython!
2
True True
7 5
0000000ppython!
+00000+ppython!
00000*/ppython
'''
#将\t转换为指定数量的空格
str_ = "USTC_tzy"
print(str_.upper(),str_.lower()) #字符串转换为全为大写或者全为小写
print(str_.title()) #将每个单词的首字母大写
str_1 = "Tzy Tzyy"
print(str_1.capitalize()) #整个字符串首字母大写
print(str_1.swapcase()) #大小写反转
'''
USTC_TZY ustc_tzy
Ustc_Tzy
Tzy tzyy
tZY tZYY
'''
str_ = "\t what is your favorate color?\n \t"
print('-'.join(str_)) #返回通过指定字符连接序列中元素后生成的新字符串。
print(str_.strip()) #Python strip() 方法用于移除字符串头尾指定的字符(默认为空格或换行符)或字符序列。
str_1 = "#DH#AL#PY#BC"
print(str_1.split("#",3)) #按照”#”最多拆分成3个子字符串
'''
- -w-h-a-t- -i-s- -y-o-u-r- -f-a-v-o-r-a-t-e- -c-o-l-o-r-?-
- - -
what is your favorate color?
['', 'DH', 'AL', 'PY#BC']
'''
import requests
import chardet
from urllib import request
response = request.urlopen("https://www.baidu.com/")
html = response.read()
print(chardet.detect(html)) #获得目标网页的编码格式
#{'encoding': 'ascii', 'confidence': 1.0, 'language': ''}
temp = '''tzy!!!'''
print("hello!,this is %s,the num %10.3f"%("tzy!",12))
2.浅拷贝和深拷贝
import copy
a = [1, 2, 3, 4, ['a', 'b']] # 原始对象
b = a # 赋值,传对象的引用
c = copy.copy(a) # 对象拷贝,浅拷贝
d = copy.deepcopy(a) # 对象拷贝,深拷贝
a.append(5) # 修改对象a
a[4].append('c') # 修改对象a中的['a', 'b']数组对象
b.append(6)
b[4].append('d')
print('a = ', a)
print('b = ', b)
print('c = ', c)
print('d = ', d)
'''
a = [1, 2, 3, 4, ['a', 'b', 'c', 'd'], 5, 6]
b = [1, 2, 3, 4, ['a', 'b', 'c', 'd'], 5, 6]
c = [1, 2, 3, 4, ['a', 'b', 'c', 'd']]
d = [1, 2, 3, 4, ['a', 'b']]
'''
l = [1,2,[3]]
p = l[:3] # 浅拷贝
print(l, p)
l[2].append(2)
print(l, p)
'''
[1, 2, [3]] [1, 2, [3]]
[1, 2, [3, 2]] [1, 2, [3, 2]]
'''
myList = [[0]] * 4 # 浅拷贝
myList[0].append(1)
print(myList)
myList = [[0] for i in range(4)] # 深拷贝
myList[0].append(1)
print(myList)
'''
[[0, 1], [0, 1], [0, 1], [0, 1]]
[[0, 1], [0], [0], [0]]
'''
1、b = a: 赋值引用,a 和 b 都指向同一个对象。
2、b = a.copy(): 浅拷贝, a 和 b 是一个独立的对象,但他们的子对象还是指向统一对象(是引用)。
b = copy.deepcopy(a): 深度拷贝, a 和 b 完全拷贝了父对象及其子对象,两者是完全独立的。
3.可变参数和关键字参数
def f(*p, **p1): # 可变参数的位置要在关键字参数位置的前面
print(p)
print(p1)
# 可变参数和关键字参数都会传入多个值,可变参数在函数中会被认为是元组,关键字参数会被认为是字典
f(1, 2, 3, 4, a=1, b=2, c=3, d=4)
'''
(1, 2, 3, 4)
{'a': 1, 'b': 2, 'c': 3, 'd': 4}
'''
4.object 和 type
1.类(class) 相当于 类型(type),因此type()和__class__相同
2.object是所有其余类的基类,type是所有类的类型(所有余是type类的实例)
3.对象分为类型对象(左边两列)和非类型对象,非类型对象无法继承或创造实例
4.实例创建的方式:继承(创建类是type类的实例) or 实例化,因此子类是父类的一个实例
因此,object是type的父类,但object也是type的一个实例(object的类型是type)
class A:
pass
class B(A):
pass
b = B()
print(A.__class__, isinstance(A, type)) # A类是type类的实例
print(isinstance(b, B), isinstance(b, A)) # 箭头向上原则(b是B的实例,B继承A,b也是A的实例)
'''
<class 'type'> True
True True
'''
print(isinstance(type, object))
print(isinstance(object, type))
print(type.__class__, object.__class__, type.__base__)
print(isinstance("abc", str))
'''
True
True
<class 'type'> <class 'type'> <class 'object'>
True
'''
class C:
pass
class A:
def __init__(self):
pass
class B(A,C):
def __init__(self):
super().__init__()
pass
print(B.__bases__, B.__class__, A.__bases__, A.__class__) # 所有类的类型都是type类型,基类都是object类型
print(type(B))
print(object) # 输出类型的名字为<class 'object'>
'''
(<class '__main__.A'>, <class '__main__.C'>) <class 'type'> (<class 'object'>,) <class 'type'>
<class 'type'>
<class 'object'>
'''
# 类(class) = 类型(type)
# 类型和非类型(或者说类和非类)都是对象,但只有类型能够被继承
# 是否还是会疑惑到底社么是类型?什么是非类型(有具体值的实例,类型对象也是type类的实例)?
# 如果一个对象,它的类型是“<class 'type'>”,那么,它是类型,否则不是
class D(type):
def __init__(self):
pass
print(D.__base__, D.__class__)
# <class 'type'> <class 'type'> 元类(type)和类实例化而来的类是类型对象
# 实例有两种意思:一通过继承产生的子类,二是通过实例化产生的具体实例。
print(isinstance(int, type)) # True int的类型是type <-> int是type的实例
print(isinstance(int, object)) # True 通过继承的实例
5.Nonetype
NoneType类型只有一个值None,表示空值,它是特殊Python对象,与0、空字符串、空列表不同
1.None在Python解释器启动时自动创建,解释器退出时销毁
2.None不支持任何运算也没有任何内建方法
3.None和任何其他的数据类型比较永远返回False
身份运算符is、is not比较的是两个变量的内存地址,而==、!=比较的是两个变量的值
Python中进行None判断时,为什么用is而不是==?
None在Python里是个单例对象,一个变量如果是None,它一定和None指向同一个内存地址。
```python
a = print("" == None, [] == None) # None不是空字符或者空列表
print(a == None) # 无返回就是返回None
'''
False False
True
'''
if []:
print("hello!")
if "":
print("hello!") # ""和[]被视为空 但和None不一样
print([] == None, "" == None, [] is None, "" is None)
'''
False False False False
'''
6.迭代器和生成器
list_ = [1,2,3,4]
c = reversed(list_) # reversed()方法会创建一个迭代器
for i in c: # 第一次已经遍历了所有迭代器内容,因此第二次时,不会再输出
print(i)
for i in c:
print(i)
‘’‘
4
3
2
1
<-输出为空,因为迭代器指针划过了所有的元素
’‘’
class A: # 把一个类作为一个迭代器使用
def __iter__(self):
self.a = 1
return self
def __next__(self):
x = self.a
self.a += 1
if x > 20:
raise StopIteration
return x
a = A()
b = iter(a)
print(a.__next__())
print(next(a))
print(b.__next__())
'''
1
2
3
'''
# 在对一系列生成有规律的数进行处理时,不需要一次性获得全部数,可以使用生成器
generator_ex = (x*x for x in range(10)) # 以列表生成式的形式来产生生成器 [] -> ()
print(generator_ex)
print(next(generator_ex))
def fib(n):
a, b = 1, 1
for i in range(n):
print(a, end=' ')
a, b = b, a+b
fib(10)
# 变成generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次被next()调用时候从上次的返回yield语句处急需执行,也就是用多少,取多少,不占内存。
def fib1(n):
a, b = 1, 1
for i in range(n):
yield a
a, b = b, a+b
g = fib1(10)
print("\n%s"%g)
print(g.__next__()) # 生成器属于迭代器,用完一个元素指针指向下一个
for each in g:
print(each, end=" ")
print()
'''
通过yield实现在单线程的情况下实现并发运算的效果(生成器函数 -> 函数名+())
一般的函数在执行完毕之后会返回一个值然后退出,但是生成器函数会自动挂起,
然后重新拾起继续执行,他会利用yield关键字挂起函数,给调用者返回一个值,
同时保留了当前的足够多的状态,可以使函数继续执行
'''
def gener(name: str):
print("this is %s"%name)
while True:
i = yield # 在第一个__next__()后,生成器会返回,并且下一次从下一条语句开始执行
print("this is the %d of %s"%(i, name))
a = gener("A")
b = gener("B")
a.__next__()
b.__next__()
for i in range(3):
a.send(i) # 可以发送数据到生成器中
b.send(i)
'''
this is A # 第一个__next__()的结果
this is B # 第一个__next__()的结果
this is the 0 of A
this is the 0 of B
this is the 1 of A
this is the 1 of B
this is the 2 of A
this is the 2 of B
'''
# 生成器函数:也是用def定义的,利用关键字yield一次性返回一个结果,阻塞,重新开始
# 生成器表达式:返回一个对象,这个对象只有在需要的时候才产生结果
def create_counter(n):
print("create_counter")
while True:
yield n
print("increment n")
n += 1
gen = create_counter(2)
print(next(gen))
print(next(gen))
'''
create_counter
2 # 第一次next()执行到此
increment n # 第二次从此开始
3
'''
'''
一个实现了iter方法的对象是可迭代的,一个实现next方法并且是可迭代的对象是迭代器。
可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator。
所以一个实现了iter方法和next方法的对象就是迭代器。
'''
# from collections import Iterator,Iterable 以后不再使用
from collections.abc import Iterable,Iterator
f = open("1.txt", "r")
print(isinstance([], Iterable), isinstance([], Iterator))
print(isinstance({}, Iterable), isinstance({}, Iterator))
print(isinstance("", Iterable), isinstance("", Iterator))
print(isinstance(f, Iterable), isinstance(f, Iterator))
f.close()
print({}.__class__)
'''
True False
True False
True False
True True # 文件是可迭代器
<class 'dict'>
'''
'''
为什么list、dict、str等数据类型不是Iterator?
列表,字典,集合,字符串都只实现了__iter__方法,都只是迭代对象
这是因为Python的Iterator对象表示的是一个数据流,Iterator对象可以被next()函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration错误。
可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()函数实现按需计算下一个数据,所以Iterator的计算是惰性的,
只有在需要返回下一个数据时它才会计算。Iterator甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的。
'''
import itertools
a = itertools.cycle("abc")
for i in range(10):
print(a.__next__())
# itertools库其他用法在 https://www.cnblogs.com/wj-1314/p/8490822.html
7.装饰器
装饰器就是装饰函数的函数,增强函数功能,起到代码复用的功能(相当于装备,装备会使函数能力变多,但效果唯一,所有函数都可以使用)
可以用于插入日志,性能检测,权限校验等
1.函数装饰器
import logging
def use_logging(func):
def wrapper(*args, **kwargs): # 若有参数,需要加上可变位置参数和可变关键字参数
#logging.warning("%s is running"%func.__name__)
print("he")
print("before")
f = func(*args, **kwargs)
print("after")
return f
return wrapper
def bar(a, b):
print("this is tzy!!%d", a+b)
bar = use_logging(bar) # 使bar被use_logging装饰
bar(1, 2)
'''
he
before
this is tzy!!%d 3
after
'''
# 带参数的函数装饰器
def para(par):
def logging_(func):
def wrapper(*args, **kwargs):
print("parameter is %s"%par)
f = func()
return f
return wrapper
return logging_
@para("HELLO WORLD") # @语法糖 相当于 f = para("HELLO WORLD")(f)
def f():
print("tzy")
f()
'''
parameter is HELLO WORLD
tzy
'''
2.内置装饰器
class Car:
def __init__(self, name, price):
self._name = name
self._price = price
@property # 能够使类方法当作属性使用
def car_name(self):
return self._name
@car_name.setter # .setter方法能够使类方法变成属性接受修改
def car_name(self, name):
self._name = name
@property
def car_price(self):
return str(self._price) + '万'
c = Car("Benz", "50")
print(c.car_name)
c.car_name = "Aston Martin"
print(c.car_name, c.car_price)
'''
Benz
Aston Martin 50万
'''
class Demo:
text = "类的属性"
def instance_method(self):
print("调用实例方法")
@classmethod
def class_method(cls):
print("调用类方法")
print("类方法访问类属性 text: {}".format(cls.text))
print("类方法访问实例方法 instance_method: {}".format(cls.instance_method()))
@staticmethod
def static_method():
print("调用静态方法")
print("类方法访问类属性 text: {}".format(Demo.text))
print("类方法访问实例方法 instance_method: {}".format(Demo.instance_method()))
if "__main__" == __name__:
d = Demo()
print(d.text)
print(d.instance_method())
print(Demo.class_method()) # 静态方法和类方法都是让类中的方法不被某一个对象单独使用而是通用的
print(Demo.static_method())
8.对象存储方式
1.小整数对象池
-5到256的数字都存在这里,当我们定义一个对象时,不会重新分配内存地址,而是指向到小整数池的一个位置;
>>> a = -6
>>> b = -6
>>> print(id(a), id(b))
2566809123216 2566809123888
>>> a = -5
>>> b = -5
>>> print(id(a), id(b))
140722332108272 140722332108272
>>> a = 256
>>> b = 256
>>> print(id(a), id(b))
140722332116624 140722332116624
>>> a = 257
>>> b = 257
>>> print(id(a), id(b))
2566809123952 2566809123216
2.大整数对象池。
说明:终端是每次执行一次,所以每次的大整数都重新创建,而在pycharm中,每次运行是所有代码都加载都内存中,属于一个整体,所以 这个时候会有一个大整数对象池,即处于一个代码块(类)的大整数是同一个对象。
>>> a = 1000
>>> b = 1000
>>> id(a)
2566809123888
>>> id(b)
2566809123952
c1 = 1000
d1 = 1000
print(c1 is d1) # True
class C1(object):
a = 100
b = 100
c = 1000
d = 1000
class C2(object):
a = 100
b = 1000
print(C1.a is C1.b)
print(C1.a is C2.a) # 小整数引用对象一样
print(C1.c is C1.d) # 同一类中大整数引用对象一样
print(C1.b is C2.b) # 不同类中大整数引用对象不一样
print(id(C1.b), id(C2.b))
'''
True
True
True
True
False
140722332111632 1998177552432
'''
3.intern 机制
用来存放一些字符串(数字、字母、下划线的组合),如果包含特殊字符,则不使用intern;
>>> str1 = "abc_123"
>>> str2 = "abc_123"
>>> print(id(str1), id(str2))
2566809435696 2566809435696
>>> str1 = "abc+123"
>>> str2 = "abc+123"
>>> print(id(str1), id(str2))
2566809435440 2566809435632
>>> str1 = "a" * 20
>>> str2 = "a" * 20
>>> print(id(str1), id(str2))
2566808967728 2566808967728
>>> s = "你好"
>>> s1 = "你好" # 不是字母数字和下划线的组合
>>> print(id(s), id(s1))
2566809004528 2566809189520
>>> str1 = "aadjfjlajfkdjalkfjldkajfldkajflak"
>>> str2 = "aadjfjlajfkdjalkfjldkajfldkajflak"
>>> print(id(str1), id(str2))
2566809189616 2566809189616
9.常见问题
1. 对象引用
1)Python中不存在传值调用,一切传递的都是对象引用,也可以认为是传址调用。即Python不允许程序员选择采用 传值或传引用 。Python参数传递采用的是“传对象引用”的方式。实际上,这种方式相当于传值和传引用的一种综合。如果函数参数收到的是一个 可变对象(比如字典或者列表) 的引用,就能修改对象的原始值——相当于通过“传引用”来传递对象。如果函数收到的是一个 不可变对象(比如数字、字符或者元组) 的引用,就不能直接修改原始对象——相当于通过"传值"来传递对象。
2)当复制列表或字典时,就复制了对象列表的引用,如果改变引用的值,则修改了原始的参数。
2. 字典为什么无序?
在说明这两个原因之前,先说个概论,字典的快是建立在用空间换时间,切记!
1)还记得之前说的,数组缺点是在创建时规定了大小,当其空白占位达到其大小的1/3时,Python会重新引入一个更大的空间,此时会将原有空间的元素一一拷贝,再将新增的元素一一拷贝进去,所以这会造成巨大的空间浪费,同时在产生新空间的同时,会同步规划元素的hash值(hash值会变得更大),此时由于hash值的不同,则可能导致键的次序不同。
2)另一个原因则是散列冲突,当添加新建的时候发现散列冲突,则新键可能会被安排到另一个位置,于是添加的元素可能就会跑到前方去了。以上就是关于无序的字典解释
3. 为什么python是动态语言
因为可以在运行时可以改变其结构,在运行时为类添加实例方法,类方法,静态方法等
参考
10.super调用父类方法
class A:
def __init__(self):
self.a = 1
def printa(self):
print("hahahahahha")
class B(A):
def __init__(self):
super(B, self).__init__() # 子类init会覆盖父类init,若要访问父类init定义的属性,需要使用super
self.b = 1
def printa(self):
super(B, self).printa()
print(self.a)
b = B()
b.printa()
'''
hahahahahha
1
'''
11.LEGB
local -> enclosed -> global -> built-in
1.应用实例
a = 'global'
def outer():
#global len # 如果取消注释,会使内部的len()函数的作用范围变成全局的,覆盖内建函数
def len(in_var):
print('called my len() function: ', end="")
l = 0
for i in in_var:
l += 1
return l
a = 'local'
def inner():
global len # 对于内嵌的函数来说,global作用域即外层函数的作用域
nonlocal a # 使嵌套函数中的数据的作用域为闭包作用域
a += ' variable'
inner()
print('a is', a)
print(len(a)) # 使用的是内嵌函数len()
outer()
print(len(a))
print('a is', a)
'''
a is local variable
called my len() function: 14
6
a is global
'''
'''
a is local variable
called my len() function: 14
called my len() function: 6
a is global
'''
2.for循环变量“泄露”
a = 1
b = [1,2]
c = (1,2)
d = {1,2}
e = {"a": 1}
for i in range(3):
b.append(1)
c = (3,4)
d.add(3)
e["b"] = 2
a = 2
if i == 2:
print(locals(), globals())
print(i, a, b, c, d, e) # for循环中的所有变量作用域都是全局作用域
a1 = 1
def f(): # 函数中是局部作用域
a1 =2
print(a1)