带下划线的变量和函数的意义
- 变量(函数类似)
- 前带单下划线'_'的变量,是一个'私有变量'(语义化),只用于类内部使用,实例还是可以访问到这个变量
- 前带双下划线'__'的变量,是一个'私有变量'(真正的),只用于类内部使用,实例不可以访问到这个变量
- 其实如果想强行访问,也是可以的...
- '__xxx__':属于python底层代码,一般无需理会
- 测试
class Demo(object):
# 定义两个私有属性
_test = '123'
__number = 456
d = Demo()
print(d._test) # 正常访问
print(d.__number) # 报错
python 另类写法
- obj.dict: 把 init()中的赋值,打包成dict
class MyResponse():
def __init__(self):
self.status = 200
self.msg = None
@property
def get_dict(self):
return self.__dict__
res = MyResponse()
print(res.get_dict) # {'status': 200, 'msg': None}
py解释器阅读的顺序自上而下
- 例子1,不会报错,因为bar已经被加载了
def foo():
print('from foo')
bar()
def bar(): # 已经被解释器自上而下,加载到内存
print('from bar')
foo() # 不会报错
- 例子2,会报错,因为bar还没加载到内存
def foo():
print('from foo')
bar()
foo() # 报错
def bar():
print('from bar')
nonlocal 关键字
-
在嵌套函数中,修改上层函数的变量值
-
在函数内部定义的变量,默认只在当前函数内部生效
而无法影响外层函数的变量 -
使用 nonlocal 关键字,就可以修改外层函数的变量
-
def myfunc1():
x = "Bill"
def myfunc2():
# nonlocal x
x = "hello"
myfunc2()
return x
print(myfunc1()) # Bill(内层函数变量此时无法修改外层)
def myfunc1():
x = "Bill"
def myfunc2():
nonlocal x
x = "hello"
myfunc2()
return x
print(myfunc1()) # hello(外层函数的变量值被修改了)
什么是闭包函数
- 闭 : 指的是定义在函数内部的函数
- 包 : 闭函数引用了一个来自外层函数的变量
- '总结一句话来说' : 定义在函数内部的函数, 并且该函数包含对外部函数作用域中名字的引用,该函数就称为闭包函数
def outter():
name='egon'
def inner():
print('my name is %s' %name)
return inner #注意不能加括号
f=outter() # 返回inner对象
# 注意 : 作用域在函数定义阶段就规定死了, 与调用的位置无关
- 闭包函数内部,变量的查找顺序
- 先从闭包函数内部找,没有就从外部函数找,最后在函数外面找
- 分别注释x,测试效果
x = 100
def outter():
x = 2
def inner():
x=1
print('from inner', x)
return inner
demo = outter()
demo()
- 功能-获取网页源码演示
### 普通写法: 将"url"以参数的形式传入(也是最常用)
import requests
def get(url):
response=requests.get(url)下载
if response.status_code == 200:
print(response.text)
get('https://www.baidu.com')
get('https://www.python.org')
### 闭包写法
import requests
def outter(url):
def get(): # 内层函数引用外层函数的参数,该参数就称为'包'
response=requests.get(url)
if response.status_code == 200:
print(response.text)
return get
baidu = outter('https://www.baidu.com')
baidu()
- 闭包的用途: 为装饰器作'预备',即不影响原函数的逻辑的前提下,再添加新的功能
import requests
def outter(url):
def get(): # 内层函数引用外层函数的参数,该参数就称为'包'
response=requests.get(url)
if response.status_code == 200:
print(response.text)
'''
这里可以添加判断,比如url若不符合url正则表达式,就抛异常,从而不再返回 get函数对象
达到阻止执行get()的逻辑
'''
return get
baidu = outter('https://www.baidu.com')
baidu()
什么是装饰器
- 器 : 就是工具
- 装饰 : 就是添加新功能
- '总结一句话来说' : 就是定义一个函数, 用该函数去为其他函数添加新功能
- 应用场景: 不修改原函数的源码,不修改原函数的调用方式
在此基础上,给该函数增加新功能
- 它是闭包函数的升级版...
- 无参数装饰器写法(在闭包里面,return func函数的计算结果)
def outter(func):
def wrapper(*args,**kwargs):
res=func(*args,**kwargs)
return res
return wrapper
@outter # 把 test函数对象当参数,传入
def test():
print('我是test方法里面的内容')
return '我是test方法最终返回的内容'
wrapper_func_obj = outter(test) # 返回内层函数对象
print(wrapper_func_obj()) # 执行内层函数逻辑: 我是test方法里面的内容 我是test方法最终返回的内容
- 计算程序执行时间示例
import time
def timmer(func):
print('装饰器正在执行')
def wrapper(*args,**kwargs):
start_time=time.time() #开始时间
res=func(*args,**kwargs)
stop_time=time.time() #结束时间
print(stop_time-start_time) #使用时间
return res
return wrapper
@timmer
def index():
time.sleep(1)
print('welcome to index page')
return 122
index() # 调用该怎么调还是怎么调
'''
- 执行结果:
装饰器正在执行
welcome to index page
1.0059232711791992
'''
类
继承需注意的Meta
问题
-
当子类继承的时候,如果重写
Meta
配置项,所有的配置项都会被刷新,没写的项并不会继承父类意思就是,该项就没有掉了,程序不会再从父类去找
class Foo(object):
class Meta:
xxx = 123
yyy = 456
class Bar(Foo): # 继承
class Meta:
xxx = 100
f = Foo() # f 有 xxx,yyy两个配置项,值分别为 123 和 456
b = Bar() # b 只有 xxx配置项,值为 100;'yyy'配置项是不存在的
print('程序运行结束!')
assert 的用法
- 通俗理解: 把
assert
看成if
,若条件成立,则正常执行后续代码;否则触发AssertionError
异常(可以自定义异常消息)
def test_case(x):
# 如果条件成立,则执行正常执行后续的语句,不会触发异常
assert x > 0, "x is not greater than 0"
return x * 2
print(test_case(6)) # 12
def test_case(x):
# 如果条件不成立,触发异常
assert x > 0, "x is not greater than 0"
return x * 2
print(test_case(-1)) # AssertionError: x is not greater than 0