本文为博主原创,未经许可严禁转载。
本文链接:https://blog.csdn.net/zyooooxie/article/details/108095932
Python笔记的博客 很久很久很久没有分享过了,一是没有时间,二是懒。
最近需求不算太多,我也就继续学习、分享一篇啊。
个人博客:https://blog.csdn.net/zyooooxie
作用域
https://docs.python.org/zh-cn/3.9/tutorial/classes.html#python-scopes-and-namespaces
"""
@blog: https://blog.csdn.net/zyooooxie
"""
def test_1():
"""
作用域
:return:
"""
# 一个作用域是 一个命名空间可直接访问的Python程序的文本区域。
# 【作用域是针对变量而言,指申明的变量 在程序里的可应用范围,或者称为 变量的生效范围。】
# 虽然作用域是静态地确定的,但它们会被动态地使用。
# python解释器动态执行过程中,对遇到的变量进行解释时,是按照一条固定的作用域链 查找解释的,又称为LEGB法则。
# • Local(最内部函数)局部作用域
# • Enclosing(嵌套函数的外层函数)嵌套作用域
# • Global(模块全局)全局作用域
# • Built-in(内置)内置作用域
# 我的理解:
# • 嵌套函数的 内层函数的 作用范围;
# • 嵌套函数的 外层函数的 作用范围;
# • 全局作用域是文件级别的,或者说是模块级别的,每个py文件中处于顶层的变量 都是全局作用域范围内的变量;
# • 内置作用域是预先定义好的,在__builtins__模块中。这些名称主要是一些关键字,例如open、range、quit等;
# --------------
# 上面4个作用域的范围排序是按照从内到外,从小到大排序的。
# 内层范围可以引用外层范围的变量,外层范围不包括内层范围的变量。
# 在局部作用域中,可以看到局部作用域、嵌套作用域、全局作用域、内建作用域中 所有定义的变量。
pass
# TODO 强烈建议:使用IDE的debug功能
# TODO 强烈建议:多打断点 + 在Watches面板 观察x 、open 、 y
x = 11 # Global
def f():
# 如果一个名称被声明为全局变量,则所有引用和赋值将直接指向包含该模块的全局名称的中间作用域。
# 要重新绑定在最内层作用域以外找到的变量,可以使用nonlocal语句声明为非本地变量。如果没有被声明为非本地变量,这些变量将是只读的(尝试写入这样的变量只会在最内层作用域中创建一个新的局
# 部变量,而同名的外部变量保持不变)。
open = 90 # Enclosing
y = 8
# 如果函数内部重新赋值了一个和全局变量名称相同的变量,则这个变量是本地变量
x = 33
print("f1:", x, 'x的值') # 33
print("f1:", open, 'open的值') # 90
print("f1:", y, 'y的值') # 8
def g():
open = 40 # Local
print("g:", open, 'open的值')
print("g:", y, 'y的值') # Enclosing
print("g:", x, 'x的值')
print('g() 执行结束')
g()
print("f2:", x) # 33
print("f2:", open) # 90
print("f2:", y) # 8
out()
def out():
# 如果在函数内部引用了一个和全局变量同名的变量,且没有重新赋值,那么此变量 引用的是全局变量。
print('out:', x, 'x的值') # Global
y = 1111
print('out:', y, 'y的值')
open = 0.1111
print('out:', open, 'open的值')
print('out() 执行结束')
if __name__ == '__main__':
pass
print("main: f()执行前", x, 'x的值') # 11
f()
print("main: f()执行后", x, 'x的值') # 11
print('main', open) # <built-in function open>
global()、locals()
https://docs.python.org/zh-cn/3.9/library/functions.html#globals
https://docs.python.org/zh-cn/3.9/library/functions.html#locals
"""
@blog: https://blog.csdn.net/zyooooxie
"""
# locals() 实际上没有返回局部名字空间,它返回的是一个拷贝。所以对它进行修改,修改的是拷贝,而对实际的局部名字空间中的变量值并无影响。
# globals() 返回的是实际的全局名字空间,对 globals 所返回的字典的 任何的改动都会直接影响到全局变量的取值。
name = 'zyooooxie'
web = 'csdn'
print('在模块层级上,locals() 和 globals() 是同一个字典。')
# print(locals(), '1-locals')
# print(globals(), '1-globals')
def test_globals():
a = globals() # 这永远是当前模块的字典(在一个函数或方法内部时,这是指定义该函数或方法的模块,而不是调用该函数或方法的模块)
print(a)
# 2种方式 修改全局变量
a['name'] = 'new_zyooooxie'
print(globals()) # 修改成功
global web
web = 'new_csdn'
print(globals())
def test_locals():
# locals函数以字典的形式返回当前所在作用域的全部变量,
# 如果你在一个模块里执行locals函数,那么它返回的与globals函数返回值相同;
# 如果你在一个函数中执行locals函数,就只能返回这个函数所形成的局部作用域里的变量。
print(locals())
a = 1
print(locals(), 'a')
b = 2
print(locals(), 'b')
locals()['a'] = 11111 # 注意:更改 不会影响解释器使用的局部变量或自由变量的值。
print(locals(), '直接修改a,实际locals()没变')
def test_locals2(int1: int, str1: str, list1: list, **kwargs) -> str:
"""
locals() 的一些用法
:param int1:
:param str1:
:param list1:
:param kwargs:
:return:
"""
print(locals(), '函数内部的变量')
res = '第一,其中传入的实参值有 {}, {}'.format(int1, kwargs)
print(res)
res = '第二,其中传入的实参值有 {list1}, {kwargs}'.format(**locals())
print(res)
res = '第三,其中传入的实参值有 {kwargs}, 有 {0}, 有 {list1}, 有 {1}'.format(locals()['kwargs'], str1, **locals())
print(res, '特别留意!!!')
print('有 {kwargs}'.format(**locals()))
print('有 {1}'.format(locals()['kwargs'], str1))
res = f'第四,其中传入的实参值 有{kwargs}, 有{str1}'
print(res)
return res
if __name__ == '__main__':
pass
# test_globals()
# test_locals()
test_locals2(1, 'zyooooxie2', [3, 4.00], csdn55=('qq', '153132336'), zy6666='77777.77', xie8888='99999.99')
global语句、nonlocal语句
https://docs.python.org/zh-cn/3.9/reference/simple_stmts.html#the-global-statement
https://docs.python.org/zh-cn/3.9/reference/simple_stmts.html#the-nonlocal-statement
"""
@blog: https://blog.csdn.net/zyooooxie
"""
def test_2():
"""
global、nonlocal语句
:return:
"""
# 注意:在内部函数中不能先访问外部函数变量,之后再定义一个同名的局部变量,这样会报错。
# 函数内部只要是赋值操作 就表示声明为本地变量
# --------------
# 在一个模块内定义的函数的全局作用域就是该模块的命名空间,无论该函数从什么地方或以什么别名被调用。
# 如果不存在生效的global或nonlocal语句,则对名称的赋值总是会进入最内层作用域。
# def内部声明(赋值)的变量默认是本地变量,要想让其变成全局变量,需要使用global。
# def内部如果没有声明某变量,则引用的这个变量是全局变量。
# --------------
# global 语句可被用来表明特定变量生存于 全局作用域 并且应当在其中被重新绑定;
# nonlocal 语句表明特定变量生存于 外层作用域 并且应当在其中被重新绑定。
# --------------
# global:如果一个命名被声明为global,那么对于这个命名的所有的引用与赋值都会作用于模块的全局命名。
# 【可以在函数内声明全局变量,然后实现对全局变量的修改。】
# global可以声明一个或多个变量为全局变量,多个变量使用逗号隔开,也可以声明事先不存在的变量为全局变量。
# 不能global中直接赋值。
# 在 global 语句中列出的名称 不得在同一代码块内 该global语句之前的位置中使用【若使用的话,就将它声明为本地变量了】
# 在global语句声明后,某些变量变为全局变量,实际是 未赋值。【必须先声明 后使用】
# TODO 如果允许,应尽量不要将函数内部的变量修饰为全局变量
# --------------
# 在嵌套函数中,如果你想要在内层函数中使用 外层函数中的变量,是只可读 不可修改。
# 在内层函数 尝试修改外层函数的变量,直接赋值时 会在内层函数 重新创建一个新的局部变量,而外层函数的变量依然存在。
# nonlocal:它是用来重新绑定中间层次作用域中的变量。【在嵌套函数中,在内层函数声明nonlocal,可以实现修改外层函数的局部变量值。】
# nonlocal 语句会使得所列出的名称 指向之前在最近的包含作用域中绑定的 除全局变量以外 的变量。
# 【nonlocal默认将内层函数中的变量修饰为上一层函数的作用域范围,如果上一层函数中不存在该变量,则修饰为上上层、上上上层直到顶层函数,但不能修饰为全局作用域范围。】
# nonlocal语句 修饰多个变量的时候,需要逗号隔开。
pass
var = "123"
def scope_test():
# print('1', globals())
print('1', locals())
def do():
print('do()内部 var:', var, ';', 'var2:', var2)
print('do()', locals(), '未重新赋值时,引用得是 外层函数中的变量')
def do_2():
# print(var) # UnboundLocalError: local variable 'var' referenced before assignment
var = "do_2新赋值的var"
# print('2', globals())
print('2', locals(), '只一个新定义的局部变量')
def do_nonlocal():
# print(var) # SyntaxError: name 'var' is used prior to nonlocal declaration
nonlocal var # 没有在函数do_nonlocal()的域中创建一个变量,而是去引用到了外层的 【下面 var = "test-var"】
nonlocal var2 # 去引用 外层的【下面 var2 = 'test-var2'】
var = 'new-var'
var2 = 'new-var2'
new_var222222 = '用完就销毁'
# nonlocal new_var222222 # SyntaxError: name 'new_var222222' is assigned to before nonlocal declaration
# nonlocal false_var # SyntaxError: no binding for nonlocal 'false_var' found
nonlocal var02, var01, var03
var03 = 'do_nonlocal()中nonlocal语句声明var02, var01, var03后,只赋值var03'
print(var01, var02, var03)
print('请留意:var01 var02 没有新赋值,变量值就不会变;nonlocal没有报错')
print('3', globals(), '请观察实际全局变量的var')
print('3', locals(), '请观察实际局部变量的 var和var2')
def do_global():
# global 先声明 后使用!
# var = 1 # 若是不注释此行,下一行的 global var 会报错:SyntaxError: name 'var' is assigned to before global declaration
global var
global new_var, new_var2
var = "do_global()新赋值的var"
new_var = '新建全局new_var'
# 实际 new_var2 没有赋值
print('do_global()中global语句声明var、new_var、new_var2,没有赋值给new_var2')
# print(new_var, var, new_var2) # NameError: name 'new_var2' is not defined
print(new_var, var)
# print('请留意:var没有新赋值时,变量值就不会变;global没有报错。')
# print('请留意:var新赋值后,变量值就变;')
new_var2222222222 = '用完就销毁-新建'
print('4', globals(), '留意new_var、var')
print('4', locals())
var = "test-var"
print('scope_test函数中var:', var)
var2 = 'test-var2'
var01 = 'TEST-01'
var02 = 'TEST-02'
var03 = 'TEST-03'
print(var2, var01, var02, var03, '留意')
# print('5', globals())
print('5', locals(), locals()['var'])
do()
print("do()执行后:", var, var2)
do_2()
print("do_2()执行后:", var, var2) # 局部赋值(这是默认状态)不会改变 scope_test 对 var 的绑定。
do_nonlocal()
print("After nonlocal assignment:", var, var2, 'var、var2的值已经改变')
print('8', globals())
print('8', locals(), '实际局部var、var2、var03 已经改变')
do_global()
print('6', globals(), '实际全局var、new_var')
print('6', locals())
print("After global assignment 全局var 已改:", globals()['var'])
print("After global assignment 全局new_var 新增:", globals().get('new_var'))
# nonlocal 赋值会改变scope_test 对 var、var2 的绑定,
# 而global 赋值会改变模块层级的绑定。
if __name__ == '__main__':
pass
print("最初var:", var)
print('0', globals()) # globals()['new_var'] 报keyError
print('0', locals())
scope_test()
print("最后var:", var)
print('7', globals(), globals().get('new_var'))
print('7', locals())
# print('在模块层级上,locals() 和 globals() 是同一个字典。')
私有变量
https://docs.python.org/zh-cn/3.9/tutorial/classes.html#private-variables
"""
@blog: https://blog.csdn.net/zyooooxie
"""
def test_1():
"""
类的封装、私有属性、私有方法
:return:
"""
# 在Class内部,可以有属性和方法,而外部代码可以通过直接调用实例变量的方法来操作数据,还可以自由地修改一个实例的 属性;
# 一些属性不想被 外部访问、不想被外部操作,可以把属性的名称前加上两个下划线__。
# 在python里,如果属性和方法前面 是双下划线,那么这个属性和方法就变成了私有的属性。
# 以双下划线开头的方法,类的实例对象 无法使用,双下划线开头的属性 也同样无法访问;
# 通过这种方法,就可以将 不希望外部访问的属性和方法 隐藏起来。
# 类中的私有属性,以及私有方法只能在类的内部使用,不能被实例对象以及类对象在类外边直接调用。
# --------------
# 私有变量的本质
# 类定义的时候,如果声明一个实例变量的时候,使用双下划线,Python解释器会将其改名,转换名称为"_类名__变量名"的名称,所以用原来的名字访问不到了。
# 名称改写:任何形式为__spam 的标识符(至少带有两个前缀下划线,至多一个后缀下划线)的文本将被替换为_classname__spam,其中classname 为去除了前缀下划线的当前类名称。
# 这种改写不考虑标识符的句法位置,只要它出现在类定义内部就会进行。
# 那要如何访问 双下划线的私有属性呢?
# 既然我们知道了私有变量的新名称,就可以直接从外部访问到,并修改它。
# 因此 尽管是私有属性,我们依旧是可以对其进行更改,但建议大家不要去修改。
# --------------
# 在变量名前使用一个下划线,称为保护变量。
# 可以看出,这个_addr属性根本就没有改变名称,和普通的属性一样,解释器不做任何特殊处理。
# 这只是开发者共同的约定,看见这种变量,就如同私有变量,不要直接使用。
# --------------
# 私有方法的本质
# 单下划线的方法只是开发者之间的约定,解释器不做任何改变。
# 双下划线的方法,是私有方法,解释器会改名,改名策略和私有变量相同, 即"_类名__方法名" 。
# 在Python中使用 _单下划线 或者 __ 双下划线 来标识一个成员被保护或者被私有化隐藏起来。
# 但是,不管使用什么样的访问控制,都不能真正的阻止用户修改类的成员。 Python中没有绝对的安全的保护成员或者私有成员。
# 因此,前导的下划线只是一种警告或者提醒,请遵守这个约定。除非真有必要,不要修改或者使用保护成员或者私有成员,更不要修改它们。
# --------------
# 1.在python中实现的封装操作,不是通过权限限制,而是通过改名(name mangling 改名策略)实现的,名字变了找不到而已。
# 2.可以使用 __dict__ 可以查看属性(包括私有属性)的值,在类的内部使用私有属性,python内部会自动进行转换成 _类名__属性名。
# 在类的外部不能给对象添加 私有属性,因为不能转换成_类名__属性名类型。
# 3.可以通过 对象名._类名__方法名 访问到(但禁止这么干)。
# 可以使用 _类名__私有属性名来获取值。但是一般情况下不要使用,了解即可。
pass
"""
@blog: https://blog.csdn.net/zyooooxie
"""
class Animal(object):
def __init__(self, age, name):
# 类的私有属性,只能在类的内部进行访问,不能在类的外部直接访问到。
self.__a_age = age
self.__a_name = name
self._a_addr = 'sz'
self._a_hobby = '吃人'
def __func_run(self):
print('{}在{}跑步'.format(self.__a_name, self._a_addr))
def _func_eat(self):
print('{}岁啊 就喜欢{}'.format(self.__a_age, self._a_hobby))
def run(self):
self.__func_run()
def eat(self):
self._func_eat()
# 在python中,一般定义函数名‘get_xx’来获取私有属性,定义‘set_xx’来修改私有属性。
def set_age(self, age):
if isinstance(age, int) is False:
raise Exception('类型有误')
self.__a_age = age
def get_age(self):
return self.__a_age
def get_hobby(self):
return self._a_hobby
"""
@blog: https://blog.csdn.net/zyooooxie
"""
if __name__ == '__main__':
pass
a = Animal(1, '刚1岁的小猫')
print(a.__dict__)
a.age = 100.12
# age属性 若是暴露出来了,别人在使用时就可能会犯这样的错误,
# 属性隐藏起来,并非不让外部使用,而是在使用时 要受到控制。
print(a.__dict__)
print(a.age, '刚设置的age')
print(a.get_age(), '查看实际的_Animal__a_age')
# a.set_age(100.12) # Exception: 类型有误
a.set_age(90)
print(a.get_age(), '新设置后的_Animal__a_age')
print(Animal.__dict__)
"""
@blog: https://blog.csdn.net/zyooooxie
"""
if __name__ == '__main__':
pass
print(Animal.__dict__)
# ani = Animal(33, '33岁的小猫')
# print(dir(ani)) # 返回 所有属性的列表 list of strings
# print(ani.__dict__) # 一个字典,键为属性名,值为属性值;an object’s (writable) attributes
#
# # dir()用来寻找一个对象的所有属性,包括__dict__中的属性,__dict__是dir()的子集
#
# print()
an = Animal(5, '5岁的小猫')
print(an.__dict__) # {'_Animal__a_age': 5, '_Animal__a_name': '5岁的小猫', '_a_addr': 'sz', '_a_hobby': '吃人'}
print(an._Animal__a_age) # 不要直接使用
print(an._Animal__a_name) # 不要直接使用
an._Animal__a_age = 100.01 # 绕过,直接设置了
an._Animal__a_name = '新的name'
print(an._Animal__a_age)
print(an._Animal__a_name)
print(an.__dict__, '直接设置后')
setattr(an, '_Animal__a_age', 9.99)
setattr(an, '_Animal__a_name', '新的name在在在')
print(an.__dict__, 'setattr()重新赋值1')
print()
print(an._a_addr) # 不要直接使用
print(an._a_hobby) # 不要直接使用
setattr(an, '_a_addr', '换个地方')
setattr(an, '_a_hobby', '换个喜好')
print(an.__dict__, 'setattr()重新赋值2')
print(an._a_addr)
print(an._a_hobby)
an._a_addr = 'zai换个地方'
an._a_hobby = 'zai换个喜好'
print(an.__dict__, '直接赋值2')
an._addr = '新新新添加个保护_addr' # 新增
print(an._addr)
print(an.__dict__)
an.__a_name = '新新新添加个私有__a_name' # 新增
print(an.__a_name)
# 表面上看,外部代码“成功”地设置了 __a_name,但实际上这个 __a_name 和class内部的 __a_name 不是一个变量!
# 内部的__a_name 已经被Python解释器自动改成了 _Animal__a_name,而外部代码给an新增了一个 __a_name。
print(an.__dict__, an.__dict__['_Animal__a_name'], an.__dict__['__a_name'])
# print(an.__age) # AttributeError: 'Animal' object has no attribute '__age'
# print(an.__like) # AttributeError: 'Animal' object has no attribute '__like'
print()
# an.__func_run() # AttributeError: 'Animal' object has no attribute '__func_run'
# print(an.__a_age) # AttributeError: 'Animal' object has no attribute '__a_age'
# __func_run()方法是以双下划线开头的;这样的方法,类的对象无法使用,双下划线开头的属性也同样无法访问,
# 通过这种方法,就可以将不希望外部访问的属性和方法隐藏起来。
an._func_eat() # 不要直接使用
an._Animal__func_run() # 不要直接使用
an.eat()
an.run()
print(an.get_hobby())
print(an.get_age())
@property
https://docs.python.org/zh-cn/3.9/library/functions.html#property
"""
@blog: https://blog.csdn.net/zyooooxie
"""
def test_0():
"""
属性装饰器 -- 把 get/set 方法“装饰”成属性调用。
:return:
"""
# 我们自定义get_age和set_age方法操作属性,的确可以实现私有变量的管理。那有没有简单的方式呢?
# @property可以把一个实例方法 变成 其同名属性,以支持.号访问,它亦可标记设置限制,加以规范。
# Decorators make defining new properties or modifying existing ones easy:
#
# class C(object):
# @property
# def x(self):
# "I am the 'x' property."
# return self._x
# @x.setter
# def x(self, value):
# self._x = value
# @x.deleter
# def x(self):
# del self._x
# 使用property装饰器的时候这三个方法同名。
# property装饰器必须在前,setter,deleter装饰器在后。
# property装饰器:后面跟的函数名是以后的属性名。它就是getter。这个必须有,有了它至少是只读属性。
# setter装饰器:与属性名同名,且接收2个参数,第一个self,第二个是将要赋值的值。有了它,属性可写。
# deleter装饰器:可以控制是否删除属性,很少用。
pass
私有实例属性使用property装饰器
"""
@blog: https://blog.csdn.net/zyooooxie
"""
class Person2(object):
"""
property装饰器 可以用调用属性的形式来调用方法 [这个方法就变成了一个属性] ,后面不需要加()。
把实例的某些属性保护起来,不让外部直接访问;外部使用getter读取属性和setter方法设置属性。
"""
def __init__(self, name, age=18):
self.p_name = name
self.__p_age = age
self.__p_birthday = '0101'
@property # 把一个getter方法变成属性,只需要加上@property就可以了
def age(self):
"""Person2-这是 __doc__ """
return self.__p_age
# 以上 @property 装饰器会将 age() 方法转化为一个具有相同名称的只读属性的 "getter",
# 并将 age 的文档字符串设置为 "Person2-这是 __doc__ "
# 特征属性对象具有 getter, setter 以及 deleter 方法,它们可用作装饰器来创建该特征属性的副本,并将相应的访问函数设为所装饰的函数。
# 用户进行属性调用的时候,直接调用 age 即可,而不用知道属性名 __p_age,因此用户无法更改属性,从而保护了类的属性。
@age.setter # 负责把一个setter方法变成属性赋值
def age(self, new_age):
if not isinstance(new_age, int):
raise ValueError('age must be an integer!')
if new_age < 0 or new_age > 100:
print('不能设置成功,但不报错')
return
self.__p_age = new_age
@age.deleter
def age(self):
del self.__p_age
@property # 还可以定义只读属性,只定义getter方法,不定义setter方法就是一个只读属性【这个属性可以让用户使用,但没办法随意修改】
def birthday(self):
return self.__p_birthday
# 要特别注意:属性的方法名 不要和 属性 重名!
"""
@blog: https://blog.csdn.net/zyooooxie
"""
if __name__ == '__main__':
pass
print(Person2.__dict__) # 'age': <property object>
p1 = Person2('zy1111', 1111)
print(p1.age, '这是age')
print(p1.__dict__)
# p1.age = 10.7 # ValueError: age must be an integer!
# print(p1.age)
p1.age = 999 # 不符合,故而 设置不成功
print(p1.age, '那')
print(p1.__dict__)
p1.age = 28 # 符合,设置成功
print(p1.age, '符合,设置成功后的新值')
print(p1.__dict__)
p1._Person2__p_age = 111222.333 # 绕过了
print(p1.age, '绕过去了')
print(p1.__dict__)
del p1.age
print(p1.__dict__, '实际删除的是 _Person2__p_age ')
print()
print(p1.birthday)
# p1.birthday = '0202' # AttributeError: can't set attribute
# del p1.birthday # AttributeError: can't delete attribute
p1._Person2__p_birthday = ['0202', '0303'] # 绕过了
print(p1.__dict__)
print(Person2.__dict__) # 'age': property object,未变
"""
@blog: https://blog.csdn.net/zyooooxie
"""
if __name__ == '__main__':
pass
print(Person2.__dict__) # 'age': <property object>
print(Person2.age, Person2.age.__doc__)
print()
p2 = Person2('zy2222', 22)
print(p2.__dict__)
print(dir(p2))
print(p2.age, '看清楚')
print()
# 千万不要随意修改类属性 (尤其是 值为 property object 的)
Person2.age = '2sss' # 修改类属性 'age': property object 变为 'age': '2sss'
print(Person2.__dict__)
p = Person2('zy', 11)
print(p.__dict__)
print(dir(p))
# 实例是没有这个age属性(实例是有_Person2__p_age),用了 类属性age
print(p.age, '看清楚')
print(p.p_name, p.age, p._Person2__p_age)
print(p.__dict__)
p.age = '8888zy' # 给了实例属性
print(p.p_name, p.age, p._Person2__p_age)
print(p.__dict__, p.__dict__['_Person2__p_age'], p.__dict__['age'])
del Person2.age
print(Person2.__dict__)
# 和 birthday 做个对比 'birthday': <property object>
# p.birthday = '0808' # 实际报错 AttributeError: can't set attribute
del p.birthday # AttributeError: can't delete attribute
私有类属性使用property装饰器
"""
@blog: https://blog.csdn.net/zyooooxie
"""
import random
import string
from xxx_use.import_external_coupon import ImportExternalCoupon
from user_log import Log
class ImportExternalCouponNew(object):
__EXCEL_PATH = r'D:\project_python\excel_folder'
def __init__(self, start_num: str, middle_num: str, end_num: str, num: int = 100, beginning_letter: str = None,
mixture_repeat_number: int = None):
"""
num是Excel生成的数量;beginning_letter是 是否添加字母;mixture_repeat_number是 混合生成Excel时 重复的条数;
:param start_num:
:param middle_num:
:param end_num:
:param num:
:param beginning_letter:
:param mixture_repeat_number:
"""
Log.info('每次生成 {} 条'.format(num))
Log.info('start_num = {}'.format(start_num))
Log.info('middle_num = {}'.format(middle_num))
Log.info('end_num = {}'.format(end_num))
self.__start_num = start_num
self.__middle_num = middle_num
self.__end_num = end_num
self.__beginning_letter = beginning_letter
self.__mixture_repeat_number = mixture_repeat_number
self.__num = num
@property
def EXCEL_PATH(self):
return self.__EXCEL_PATH
@EXCEL_PATH.setter
def EXCEL_PATH(self, new_path):
if isinstance(new_path, int):
raise Exception('搞错了。。。{}'.format(new_path))
self.__EXCEL_PATH = new_path
@property
def num(self):
return self.__num
@num.setter
def num(self, new_num):
if isinstance(new_num, int) and new_num > 0:
self.__num = new_num
else:
Log.info('传参有误,{}'.format(new_num))
raise
"""
@blog: https://blog.csdn.net/zyooooxie
"""
if __name__ == '__main__':
print(ImportExternalCouponNew.__dict__)
iecn = ImportExternalCouponNew('123', '456', '789', 200)
print(iecn.__dict__)
print(dir(iecn))
print(iecn.EXCEL_PATH)
# iecn.EXCEL_PATH = 123456 # Exception: 搞错了。。。123456
print()
iecn.EXCEL_PATH = r'D:\project_python\zy'
print(iecn.EXCEL_PATH, '新赋值')
# 上面对iecn.EXCEL_PATH 重新赋值后,
# 特别看下:实例对象的 _ImportExternalCouponNew__EXCEL_PATH 的值 和 类对象的 _ImportExternalCouponNew__EXCEL_PATH 的值 是不同的!
print(iecn.__dict__) # '_ImportExternalCouponNew__EXCEL_PATH': 'D:\\project_python\\zy'
print(ImportExternalCouponNew.__dict__) # '_ImportExternalCouponNew__EXCEL_PATH': 'D:\\project_python\\excel_folder'
# 'EXCEL_PATH': property object 未改变
一个错误的示例 如下:
"""
@blog: https://blog.csdn.net/zyooooxie
"""
if __name__ == '__main__':
pass
# ImportExternalCouponNew._ImportExternalCouponNew__EXCEL_PATH = r'D:\project_python\202112' # 修改成功;未修改 EXCEL_PATH:property object
# print(ImportExternalCouponNew.__dict__)
# ---------------------------
print(ImportExternalCouponNew.__dict__)
# 'EXCEL_PATH': <property object > ,使用property
# 'num': <property object >
ImportExternalCouponNew.EXCEL_PATH = r'D:\project_python\202201' # 修改了原本的 property object;但是 _ImportExternalCouponNew__EXCEL_PATH的值是 没变
print(ImportExternalCouponNew.__dict__)
print()
en = mn = sn = random.randint(100000, 999999)
iecn = ImportExternalCouponNew(str(sn), str(mn), str(en), num=100)
print(iecn.__dict__)
print(iecn.EXCEL_PATH)
iecn.EXCEL_PATH = r'D:\project_python\zy' # 实例对象.EXCEL_PATH是 覆盖 类对象的.EXCEL_PATH
# iecn.num = 500.22 # 传参有误,500.22 实际报错:RuntimeError: No active exception to reraise
print(iecn.EXCEL_PATH, iecn.num, '刚刚新赋值')
iecn.EXCEL_PATH = 123456 # 没有报错!!!
print(iecn.EXCEL_PATH)
print()
print(iecn.__dict__) # 留意 EXCEL_PATH
print(ImportExternalCouponNew.__dict__) # 留意 EXCEL_PATH
本文链接:https://blog.csdn.net/zyooooxie/article/details/108095932
交流技术 欢迎+QQ 153132336 zy
个人博客 https://blog.csdn.net/zyooooxie