pyobject 1.2.9.2__tar.gz → 1.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. {pyobject-1.2.9.2/pyobject.egg-info → pyobject-1.3.0}/PKG-INFO +6 -3
  2. {pyobject-1.2.9.2 → pyobject-1.3.0}/README.rst +5 -2
  3. {pyobject-1.2.9.2 → pyobject-1.3.0}/pyobject/__init__.py +3 -3
  4. {pyobject-1.2.9.2 → pyobject-1.3.0}/pyobject/examples/test_inject.py +3 -3
  5. {pyobject-1.2.9.2 → pyobject-1.3.0}/pyobject/objproxy/__init__.py +197 -207
  6. {pyobject-1.2.9.2 → pyobject-1.3.0}/pyobject/objproxy/builtin_hook.py +2 -20
  7. {pyobject-1.2.9.2 → pyobject-1.3.0}/pyobject/tests/test_objproxy.py +21 -1
  8. {pyobject-1.2.9.2 → pyobject-1.3.0/pyobject.egg-info}/PKG-INFO +6 -3
  9. {pyobject-1.2.9.2 → pyobject-1.3.0}/pyobject.egg-info/SOURCES.txt +0 -1
  10. pyobject-1.2.9.2/pyobject/objproxy/dynobj.py +0 -190
  11. {pyobject-1.2.9.2 → pyobject-1.3.0}/LICENSE +0 -0
  12. {pyobject-1.2.9.2 → pyobject-1.3.0}/MANIFEST.in +0 -0
  13. {pyobject-1.2.9.2 → pyobject-1.3.0}/pyobject/browser.py +0 -0
  14. {pyobject-1.2.9.2 → pyobject-1.3.0}/pyobject/code.py +0 -0
  15. {pyobject-1.2.9.2 → pyobject-1.3.0}/pyobject/examples/README.md +0 -0
  16. {pyobject-1.2.9.2 → pyobject-1.3.0}/pyobject/examples/__init__.py +0 -0
  17. {pyobject-1.2.9.2 → pyobject-1.3.0}/pyobject/examples/empty_cp37.pyc +0 -0
  18. {pyobject-1.2.9.2 → pyobject-1.3.0}/pyobject/examples/pyc_zipper_unpack.py +0 -0
  19. {pyobject-1.2.9.2 → pyobject-1.3.0}/pyobject/examples/pyc_zipper_zlib.py +0 -0
  20. {pyobject-1.2.9.2 → pyobject-1.3.0}/pyobject/images/back.gif +0 -0
  21. {pyobject-1.2.9.2 → pyobject-1.3.0}/pyobject/images/codeobject.gif +0 -0
  22. {pyobject-1.2.9.2 → pyobject-1.3.0}/pyobject/images/dict.gif +0 -0
  23. {pyobject-1.2.9.2 → pyobject-1.3.0}/pyobject/images/empty_dict.gif +0 -0
  24. {pyobject-1.2.9.2 → pyobject-1.3.0}/pyobject/images/empty_list.gif +0 -0
  25. {pyobject-1.2.9.2 → pyobject-1.3.0}/pyobject/images/empty_tuple.gif +0 -0
  26. {pyobject-1.2.9.2 → pyobject-1.3.0}/pyobject/images/forward.gif +0 -0
  27. {pyobject-1.2.9.2 → pyobject-1.3.0}/pyobject/images/function.gif +0 -0
  28. {pyobject-1.2.9.2 → pyobject-1.3.0}/pyobject/images/list.gif +0 -0
  29. {pyobject-1.2.9.2 → pyobject-1.3.0}/pyobject/images/number.gif +0 -0
  30. {pyobject-1.2.9.2 → pyobject-1.3.0}/pyobject/images/python.gif +0 -0
  31. {pyobject-1.2.9.2 → pyobject-1.3.0}/pyobject/images/python.ico +0 -0
  32. {pyobject-1.2.9.2 → pyobject-1.3.0}/pyobject/images/refresh.gif +0 -0
  33. {pyobject-1.2.9.2 → pyobject-1.3.0}/pyobject/images/string.gif +0 -0
  34. {pyobject-1.2.9.2 → pyobject-1.3.0}/pyobject/images/tuple.gif +0 -0
  35. {pyobject-1.2.9.2 → pyobject-1.3.0}/pyobject/objproxy/optimize.py +0 -0
  36. {pyobject-1.2.9.2 → pyobject-1.3.0}/pyobject/objproxy/utils.py +0 -0
  37. {pyobject-1.2.9.2 → pyobject-1.3.0}/pyobject/other/browser_chs_locale.py +0 -0
  38. {pyobject-1.2.9.2 → pyobject-1.3.0}/pyobject/pyobj_extension.c +0 -0
  39. {pyobject-1.2.9.2 → pyobject-1.3.0}/pyobject/search.py +0 -0
  40. {pyobject-1.2.9.2 → pyobject-1.3.0}/pyobject/tests/test_code.py +0 -0
  41. {pyobject-1.2.9.2 → pyobject-1.3.0}/pyobject/tests/test_objproxy_perf.py +0 -0
  42. {pyobject-1.2.9.2 → pyobject-1.3.0}/pyobject.egg-info/dependency_links.txt +0 -0
  43. {pyobject-1.2.9.2 → pyobject-1.3.0}/pyobject.egg-info/requires.txt +0 -0
  44. {pyobject-1.2.9.2 → pyobject-1.3.0}/pyobject.egg-info/top_level.txt +0 -0
  45. {pyobject-1.2.9.2 → pyobject-1.3.0}/setup.cfg +0 -0
  46. {pyobject-1.2.9.2 → pyobject-1.3.0}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pyobject
3
- Version: 1.2.9.2
3
+ Version: 1.3.0
4
4
  Summary: A multifunctional all-in-one utility tool for managing internal Python objects, compatible with nearly all Python 3 versions. 一个多功能合一的提供操作Python对象底层工具的Python包, 支持几乎所有Python 3版本。
5
5
  Home-page: https://github.com/qfcy/pyobject
6
6
  Author: qfcy
@@ -394,11 +394,12 @@ Python内部的字节码对象\ ``CodeType``\ ,如\ ``func.__code__``\ ,是
394
394
  lst调用多次==运算符(``__eq__``)相比,
395
395
  本函数直接比较对象的指针,提高了效率。
396
396
 
397
- **``pyobject``\ 当前版本**: 1.2.9.2
397
+ **``pyobject``\ 当前版本**: 1.3.0
398
398
 
399
399
  更新日志:
400
400
  ---------
401
401
 
402
+ | 2025-6-6(v1.3.0):性能优化,提升了pyobject.objproxy模块的性能。
402
403
  | 2025-4-30(v1.2.9):改进和增强了子模块pyobject.objproxy,重命名子模块pyobject.code_为pyobject.code。
403
404
  | 2025-3-31(v1.2.8):将pyobject.super_proxy重命名为pyobject.objproxy,并正式发布;修改了pyobject.pyobj_extension模块。
404
405
  | 2025-3-6(v1.2.7):为pyobject.browser新增了\ ``dir()``\ 中不存在的类属性(如\ ``__flags__``,
@@ -886,11 +887,13 @@ Python call “obj in lst” that invokes the “==” operator (``__eq__``)
886
887
  multiple times, this function directly compares the pointers to improve
887
888
  efficiency.
888
889
 
889
- **Current Version of ``pyobject``**: 1.2.9.2
890
+ **Current Version of ``pyobject``**: 1.3.0
890
891
 
891
892
  Change Log
892
893
  ----------
893
894
 
895
+ | 2025-6-6(v1.3.0): Optimized the performance of the pyobject.objproxy
896
+ module.
894
897
  | 2025-4-30(v1.2.9): Improved and enhanced the sub-module
895
898
  ``pyobject.objproxy``, and renamed the sub-module ``pyobject.code_``
896
899
  to ``pyobject.code``.
@@ -377,11 +377,12 @@ Python内部的字节码对象\ ``CodeType``\ ,如\ ``func.__code__``\ ,是
377
377
  lst调用多次==运算符(``__eq__``)相比,
378
378
  本函数直接比较对象的指针,提高了效率。
379
379
 
380
- **``pyobject``\ 当前版本**: 1.2.9.2
380
+ **``pyobject``\ 当前版本**: 1.3.0
381
381
 
382
382
  更新日志:
383
383
  ---------
384
384
 
385
+ | 2025-6-6(v1.3.0):性能优化,提升了pyobject.objproxy模块的性能。
385
386
  | 2025-4-30(v1.2.9):改进和增强了子模块pyobject.objproxy,重命名子模块pyobject.code_为pyobject.code。
386
387
  | 2025-3-31(v1.2.8):将pyobject.super_proxy重命名为pyobject.objproxy,并正式发布;修改了pyobject.pyobj_extension模块。
387
388
  | 2025-3-6(v1.2.7):为pyobject.browser新增了\ ``dir()``\ 中不存在的类属性(如\ ``__flags__``,
@@ -869,11 +870,13 @@ Python call “obj in lst” that invokes the “==” operator (``__eq__``)
869
870
  multiple times, this function directly compares the pointers to improve
870
871
  efficiency.
871
872
 
872
- **Current Version of ``pyobject``**: 1.2.9.2
873
+ **Current Version of ``pyobject``**: 1.3.0
873
874
 
874
875
  Change Log
875
876
  ----------
876
877
 
878
+ | 2025-6-6(v1.3.0): Optimized the performance of the pyobject.objproxy
879
+ module.
877
880
  | 2025-4-30(v1.2.9): Improved and enhanced the sub-module
878
881
  ``pyobject.objproxy``, and renamed the sub-module ``pyobject.code_``
879
882
  to ``pyobject.code``.
@@ -6,7 +6,7 @@ import sys
6
6
  from warnings import warn
7
7
  from pprint import pprint
8
8
 
9
- __version__="1.2.9.2"
9
+ __version__="1.3.0"
10
10
 
11
11
  __all__=["objectname","bases","describe","desc"]
12
12
  _ignore_names=["__builtins__","__doc__"]
@@ -97,8 +97,8 @@ try:
97
97
  "set_type_subclasses_by_cls"])
98
98
  except ImportError:warn("Failed to import pyobject.pyobj_extension.")
99
99
  try:
100
- from pyobject.objproxy import DynObj,ObjChain,ProxiedObj
101
- __all__.extend(["DynObj","ObjChain","ProxiedObj"])
100
+ from pyobject.objproxy import ObjChain,ProxiedObj,unproxy_obj
101
+ __all__.extend(["ObjChain","ProxiedObj","unproxy_obj"])
102
102
  except (ImportError, SyntaxError):
103
103
  warn("Failed to import pyobject.objproxy.") # Python 3.5及以下不支持f-string,无法使用objproxy库
104
104
 
@@ -7,7 +7,7 @@ except ImportError:
7
7
  from importlib._bootstrap import MAGIC_NUMBER
8
8
 
9
9
  MARK=b"#####MyPython####"
10
- TARGET='empty_cp37.pyc' # 需要用Python 3.7
10
+ TARGET='empty_cp37.pyc' # Python 3.7
11
11
 
12
12
  def extract_file(filename):
13
13
  # 将py,pyc文件还原为Code对象
@@ -121,10 +121,10 @@ def spread_to_mod(modname,use_pycache=True):
121
121
  if use_pycache and file.endswith('.py') or file.endswith('.pyw'):
122
122
  # 获取目标文件位置
123
123
  splited=os.path.split(file)
124
- os.makedirs(splited[0] + '\\__pycache__',exist_ok=True)
124
+ os.makedirs(splited[0] + '/__pycache__',exist_ok=True)
125
125
  pyc=os.path.splitext(splited[1])[0] + \
126
126
  '.cpython-%d%d' % (sys.version_info.major,sys.version_info.minor)
127
- target=splited[0] + '\\__pycache__\\'+pyc+'.pyc'
127
+ target=splited[0] + '/__pycache__/'+pyc+'.pyc'
128
128
  else:target=None
129
129
  co=spread(file,pycfile=target)
130
130
  return co
@@ -1,6 +1,5 @@
1
1
  import functools,itertools,types
2
2
  from pyobject import shortrepr
3
- from pyobject.objproxy.dynobj import DynObj
4
3
  from pyobject.objproxy.optimize import optimize_code
5
4
  from pyobject.objproxy.utils import *
6
5
 
@@ -24,42 +23,6 @@ def unproxy_obj(obj):
24
23
  obj = obj._ProxiedObj__target_obj
25
24
  return obj
26
25
 
27
- def unproxy_obj_recursive(obj): # 递归解除obj的代理(备用函数)
28
- while _isinstance(obj, ProxiedObj):
29
- obj = obj._ProxiedObj__target_obj
30
- # 递归处理容器
31
- if _isinstance(obj, dict):
32
- return {unproxy_obj_recursive(k): unproxy_obj_recursive(v)
33
- for k, v in obj.items()}
34
- elif _isinstance(obj, list):
35
- return [unproxy_obj_recursive(item) for item in obj]
36
- elif _isinstance(obj, tuple):
37
- return tuple(unproxy_obj_recursive(item) for item in obj)
38
- elif _isinstance(obj, set):
39
- return {unproxy_obj_recursive(item) for item in obj}
40
- else:
41
- return obj
42
- def accept_raw_obj(func,process_arg=None,process_kw=None,process_ret=None):
43
- # 装饰器,用于有target_obj时只接受原始对象而不是ProxiedObj的函数(备用)
44
- @functools.wraps(func)
45
- def inner(*args,**kw):
46
- args = unproxy_obj_recursive(args)
47
- kw = unproxy_obj_recursive(kw)
48
-
49
- if process_arg is not None:
50
- args = process_arg(args)
51
- if process_kw is not None:
52
- kw = process_kw(kw)
53
-
54
- if kw:
55
- result = func(*args,**kw)
56
- else:
57
- result = func(*args)
58
- if process_ret is not None:
59
- result = process_ret(result)
60
- return result
61
- return inner
62
-
63
26
  class _EmptyTarget:
64
27
  def __bool__(self):return False
65
28
  EMPTY_OBJ = _EmptyTarget() # 空对象的特殊值
@@ -87,7 +50,7 @@ def is_trivial_obj(obj): # 检查对象能否被repr()表示(即对象必须
87
50
  if type(obj) not in TRIVIAL_TYPES: # 不使用isinstance(由于不能是基本类型子类)
88
51
  return False
89
52
  if type(obj) in (list, tuple, dict, set):
90
- if isinstance(obj, dict):
53
+ if _isinstance(obj, dict):
91
54
  obj = itertools.chain(obj.keys(), obj.values())
92
55
  return all(is_trivial_obj(sub) for sub in obj)
93
56
  return True
@@ -104,42 +67,12 @@ def is_builtin_type(cls): # 备用函数
104
67
  # return True
105
68
  #return False
106
69
 
107
- def proxyCls(T=_EmptyTarget, chain=EMPTY_OBJ, fromvar=None):
108
- # 泛型,proxyCls(T)生成类型信息为T的继承自ProxiedObj的类
109
- if T is EMPTY_OBJ:
110
- return ProxiedObj
111
-
112
- class ProxyCls(ProxiedObj): # 创建同时从ProxiedObj与T继承的类
113
- # pylint: disable=unused-private-member
114
- __proto = T # 自身使用的原型
115
- def __new__(cls,*args,**kw):
116
- _chain = args[0] if args else kw.get("chain")
117
- if not _isinstance(_chain,ObjChain) and chain is not EMPTY_OBJ:
118
- var = chain.new_var(T.__name__)
119
- if fromvar is not None:
120
- # pylint: disable=self-cls-assignment
121
- cls = chain.add_existing_obj(T,var,f"{var} = {fromvar}.__class__",
122
- [fromvar])
123
- else:
124
- cls = chain.add_existing_obj(T,var, # pylint: disable=self-cls-assignment
125
- f"# class {var}: {shortrepr(cls,repr_func=basic_repr)}")
126
- if len(args) == 3 and isinstance(T,type):
127
- args=(args[0],tuple(unproxy_obj(cls) for cls in args[1]),args[2])
128
-
129
- if kw:return cls(*args,**kw)
130
- return cls(*args) # 返回ProxyCls
131
- else:
132
- return ProxiedObj.__new__(cls,*args,**kw)
133
-
134
- return ProxyCls
135
-
136
70
  class ObjChain:
137
71
  def __init__(self, export_funcs = None, export_attrs = None,
138
72
  export_trivial_obj = False, hook_inheritance = False,
139
73
  hook_method_call = False):
140
74
  # ObjChain()的export_funcs和export_attrs作用于当前链的所有对象
141
75
  self.codes = []
142
- self.indent = 0 # 代码缩进格数(暂未使用)
143
76
  self.scope = {} # 上次执行的命名空间
144
77
  self.export_funcs = {} # 哪些函数需要导出(键为对象的变量名,值为属性名的列表,属性名可用"."分隔)
145
78
  self.export_attrs = {} # 哪些属性需要导出(键为对象的变量名)
@@ -153,19 +86,26 @@ class ObjChain:
153
86
  self._var_num = 0 # 变量序号
154
87
  self.code_vars = [] # 每行代码修改和依赖于的变量,例如[("result_var",["depend_var1",...],{}),...],{}为额外信息
155
88
  self.code_executed = [] # 代码是否已执行过(确保代码只执行一次)
89
+ self._executed_idx = 0 # 前面全部执行过的行号
156
90
  self._is_evaluating = False # 当前是否正在执行调用(用于代码的_internal信息)
157
91
  self.export_trivial_obj = export_trivial_obj # 是否不使用ProxiedObj包装基本类型(如整数、列表等)
158
92
  self.hook_inheritance = hook_inheritance # 是否继续hook从ProxiedObj包装的类继承的新类
159
93
  self.hook_method_call = hook_method_call # 是否hook实例方法的调用
160
94
  def add_code(self,code_line,result_var=None,dependency_vars=None,
161
95
  executed=True,**extra_info):
96
+ # result_var: 新变量名(每个变量对应的对象id不变,类似js的const)
97
+ # dependency_vars: 依赖的变量列表(可能会修改对象,但不会修改变量的对象id)
162
98
  if dependency_vars is None:
163
99
  dependency_vars = []
164
- self.codes.append(" "*(self.indent*INDENT)+code_line)
100
+ self.codes.append(code_line)
165
101
  if "_internal" not in extra_info:
166
102
  extra_info["_internal"] = self._is_evaluating # _internal: 是否是执行其他生成代码时,递归生成的
167
103
  self.code_vars.append((result_var,dependency_vars,extra_info))
168
104
  self.code_executed.append(executed)
105
+ def remove_last_line(self): # 删除最后一行代码
106
+ self.codes.pop()
107
+ self.code_vars.pop()
108
+ self.code_executed.pop()
169
109
  def detect_dependency_vars(self,*iterables):
170
110
  # 自动检测依赖的变量,返回变量名的列表和未知对象的列表
171
111
  result = []; unknown = []
@@ -342,11 +282,11 @@ class ObjChain:
342
282
  remove_export_type=True):
343
283
  return optimize_code(self.codes, self.code_vars, no_optimize_vars,
344
284
  remove_internal, remove_export_type)
345
- def eval_value(self,var_name=None,end_lineno=None):
285
+ def eval_value(self,var_name=None,start_lineno=None,end_lineno=None):
346
286
  # 一次性执行未执行过的代码(仅用于没有target_obj时)
347
287
  if end_lineno is None:end_lineno = len(self.codes)
348
288
 
349
- exec(self.get_code(end_lineno = end_lineno, _only_not_executed = True),
289
+ exec(self.get_code(start_lineno, end_lineno, _only_not_executed = True),
350
290
  self.scope)
351
291
  if var_name is not None:
352
292
  return self.scope[var_name]
@@ -356,23 +296,23 @@ class ObjChain:
356
296
  use_exported_obj=False):
357
297
  # 依赖于最后一行代码,要求调用之前先调用了add_code
358
298
  # var_name为None时,返回None(此时不可使用返回值)
359
- if result_getter_func is not None and var_name is None:
360
- raise ValueError("result_getter_func requires var_name")
361
-
362
299
  pre_is_evaluating = self._is_evaluating
363
300
  self._is_evaluating = True # 记录当前正在执行其他代码
364
301
 
365
302
  new_code = self.codes[-1]
366
- cur_idx = -1
303
+ cur_idx = len(self.codes) - 1
367
304
  if target_obj is not EMPTY_OBJ:
368
305
  # 一次执行完前面的全部代码
369
- self.eval_value(end_lineno = cur_idx) # 不包括最后一行新加入的代码
306
+ self.eval_value(start_lineno = self._executed_idx,
307
+ end_lineno = cur_idx) # 不包括最后一行新加入的代码
370
308
  self.code_executed[cur_idx] = True # 最后一行设为已执行过
309
+ self._executed_idx = cur_idx + 1
371
310
 
372
311
  # 实时操作对象,并返回操作结果
373
312
  if result_getter_func is not None:
374
313
  result = result_getter_func() # 从外部函数获取返回结果(比exec更快)
375
- self.scope[var_name] = result # 将结果存入为scope的变量(此时var_name不为None
314
+ if var_name is not None:
315
+ self.scope[var_name] = result # 将结果存入为scope的变量(此时var_name不为None)
376
316
  else:
377
317
  if export or use_exported_obj: # use_exported_obj: 是否在不导出时也在exec用target_obj作为变量,避免递归
378
318
  scope = {}
@@ -399,35 +339,45 @@ class ObjChain:
399
339
  self._is_evaluating = pre_is_evaluating
400
340
  return result # result须不为ProxiedObj类型
401
341
 
402
- def magic_meth_chained(fmt = None, use_newvar = True, indent_delta = 0,
403
- export = False, use_exported_obj = True, default_fmt = False):
342
+ def magic_meth_chained(fmt = None, use_newvar = True, export = False,
343
+ use_exported_obj = True, default_fmt = False,
344
+ no_exec = True, aug_assign = False):
404
345
  # fmt: 代码的格式,{_var}表示新变量,{_self}表示自身变量
405
346
  # use_newvar: 是否会生成新的返回值变量,为False时用于+=, -=等运算符
406
- # indent_delta: 缩进的变化量。export: 是否返回ProxiedObj外的其他类型
407
347
  # default_fmt: 自动生成代码的格式,此时use_target_obj总是为True
348
+ # no_exec: 不使用exec()执行动态生成的代码,用于提高性能
349
+ # aug_assign: 是否为增强赋值语句(会同时将use_newvar设为False)
350
+
408
351
  if not use_newvar and export:
409
- raise ValueError("can't disable use_newvar while export is set to True")
352
+ raise ValueError("can't disable use_newvar while export is True")
353
+ if aug_assign:
354
+ use_newvar=False # 自动将use_newvar设为False
355
+ if default_fmt or fmt is None:
356
+ raise ValueError(
357
+ "can't use default_fmt=True or fmt=None while aug_assign is True")
358
+
410
359
  def magic_meth_chained_inner(meth):
360
+ meth_name = meth.__name__ # 方法名,仅default_fmt为True时使用
411
361
  if export:
412
- DEFAULT_EXPORT_FUNCS.append(meth.__name__) # 自动生成常量DEFAULT_EXPORT_FUNCS
362
+ DEFAULT_EXPORT_FUNCS.append(meth_name) # 自动生成常量DEFAULT_EXPORT_FUNCS
413
363
  @functools.wraps(meth)
414
364
  def override(self, *args, **kw):
415
365
  nonlocal use_exported_obj
416
366
  chain = self._ProxiedObj__chain
417
- name = self._ProxiedObj__name
418
- meth_name = meth.__name__
367
+ self_name = self._ProxiedObj__name
419
368
  target_obj = self._ProxiedObj__target_obj
420
369
  no_target_obj = target_obj is EMPTY_OBJ
421
370
 
422
371
  # ReprFormatProxy:自定义!r格式化的行为
423
372
  fmt_kw = {key:ReprFormatProxy(val,chain.get_repr) for key,val in kw.items()}
424
- fmt_kw["_self"] = name
373
+ fmt_kw["_self"] = self_name
425
374
  if use_newvar:
426
375
  new_var = chain.new_var(export=export) # 申请一个新变量名
427
376
  fmt_kw["_var"] = new_var
428
377
  else:
429
378
  new_var = None
430
379
 
380
+ # 添加代码并检测依赖的变量
431
381
  depend_vars = chain._detect_var_and_add_obj((self,), args, kw.values())
432
382
  if fmt is not None:
433
383
  fmt_args = [ReprFormatProxy(arg,chain.get_repr) for arg in args]
@@ -435,28 +385,32 @@ def magic_meth_chained(fmt = None, use_newvar = True, indent_delta = 0,
435
385
  chain.add_code(new_code, new_var, depend_vars, _export_type = export,
436
386
  executed = not no_target_obj) # 加入新的一行代码
437
387
  elif default_fmt: # 自动生成格式
438
- use_exported_obj = True # 此时use_target_obj总是为True
388
+ fmt_args = None
389
+ use_exported_obj = True # 此时use_exported_obj总是为True
439
390
  if use_newvar:
440
391
  new_code = "{} = {}.{}({})".format(
441
- new_var,name,meth_name,format_func_call(args,kw,chain.get_repr))
392
+ new_var,self_name,meth_name,format_func_call(args,kw,chain.get_repr))
442
393
  else:
443
394
  new_code = "{}.{}({})".format(
444
- name,meth_name,format_func_call(args,kw,chain.get_repr))
395
+ self_name,meth_name,format_func_call(args,kw,chain.get_repr))
445
396
  chain.add_code(new_code, new_var, depend_vars, _export_type = export,
446
397
  executed = not no_target_obj)
447
398
  else:
448
- pass #new_code = ""
449
-
450
- chain.indent += indent_delta # 变化缩进
399
+ new_code = fmt_args = None
451
400
 
401
+ getter_func = (lambda:meth(target_obj,
402
+ *((unproxy_obj(arg) for arg in args) if use_exported_obj else args))) \
403
+ if no_exec and not no_target_obj else None # no_exec为True时,不使用关键字参数kw
452
404
 
453
405
  # 不使用use_exported_obj时,result总是为None
454
406
  result = chain._get_new_targetobj(target_obj,new_var,
455
407
  export=export,
456
- use_exported_obj=use_exported_obj)
408
+ use_exported_obj=use_exported_obj,
409
+ result_getter_func=getter_func)
457
410
 
458
411
  if export or (self._ProxiedObj__export_trivial_obj
459
412
  and is_trivial_obj(result)):
413
+ # 返回导出的对象
460
414
  if use_newvar:
461
415
  chain.add_exported_obj(result, new_var) # 继续追踪导出的值
462
416
  if target_obj is not EMPTY_OBJ:
@@ -467,7 +421,23 @@ def magic_meth_chained(fmt = None, use_newvar = True, indent_delta = 0,
467
421
  if use_newvar:
468
422
  return proxyCls(type(result),self._ProxiedObj__chain,new_var)(chain,new_var,
469
423
  result,export_trivial_obj=self._ProxiedObj__export_trivial_obj)
470
- return self
424
+ if aug_assign:
425
+ if result is target_obj:return self
426
+ else:
427
+ result_var = chain.new_var() # 新变量的名称
428
+ chain.scope[result_var] = result
429
+ chain.remove_last_line() # 回退已生成的代码,重新加入
430
+ fmt_kw["_self"] = result_var
431
+ chain.add_code(f"{result_var} = {self_name}",result_var,[self_name])
432
+ new_code = fmt.format(*fmt_args, **fmt_kw)
433
+ # 需加入self_name,由于可能会修改self_name的对象
434
+ chain.add_code(new_code, None, [result_var, self_name],
435
+ _export_type = export, executed = not no_target_obj)
436
+ return proxyCls(type(result),self._ProxiedObj__chain,result_var)(
437
+ chain,result_var,result,
438
+ export_trivial_obj = \
439
+ self._ProxiedObj__export_trivial_obj)
440
+ return None
471
441
 
472
442
  return override
473
443
  return magic_meth_chained_inner
@@ -486,7 +456,7 @@ class ProxiedObj:
486
456
  self.__name=name
487
457
  self.__export_call=_export_call
488
458
  if not _export_call and self.__chain.hook_method_call \
489
- and isinstance(target_obj,types.MethodType):
459
+ and _isinstance(target_obj,types.MethodType):
490
460
  obj = target_obj.__self__
491
461
  if id(obj) in self.__chain.proxies:
492
462
  target_obj = types.MethodType(target_obj.__func__,
@@ -522,7 +492,7 @@ class ProxiedObj:
522
492
  self.__chain.add_exported_obj(result, new_var)
523
493
  return result # 直接返回结果,不继续返回ProxiedObj
524
494
 
525
- if isinstance(self.__target_obj,type) and isinstance(result,self.__target_obj):
495
+ if _isinstance(self.__target_obj,type) and _isinstance(result,self.__target_obj):
526
496
  # 自身是类且result为自身的实例化对象,则实例使用类的导出函数、属性
527
497
  if self.__name in self.__chain.export_attrs:
528
498
  self.__chain.export_attrs[new_var] = self.__chain.\
@@ -535,26 +505,22 @@ class ProxiedObj:
535
505
 
536
506
  #@magic_meth_chained("{_var} = {_self}.{}")
537
507
  def __getattr__(self,attr):
538
- if "_ProxiedObj__chain" not in object.\
539
- __getattribute__(self,"__dict__"): # self尚未初始化
540
- return object.__getattribute__(self,attr)
541
508
  if attr in NOCODE_EXPORT_ATTRS and self.__target_obj is not EMPTY_OBJ:
542
- return getattr(self.__target_obj, attr) # 不留下代码的直接导出属性
509
+ return _getattr(self.__target_obj, attr) # 不留下代码的直接导出属性
543
510
 
544
511
  new_var=self.__chain.new_var()
545
512
  new_code = f"{new_var} = {self.__name}.{attr}"
546
513
  self.__chain.add_code(new_code, new_var, [self.__name],
547
514
  executed = self.__target_obj is not EMPTY_OBJ)
548
515
 
549
- export = self.__chain.is_export_attr(attr, self.__name)
516
+ is_export = self.__chain.is_export_attr(attr, self.__name)
550
517
  result = self.__chain._get_new_targetobj(
551
- self.__target_obj,new_var,lambda:getattr(self.__target_obj,attr),
552
- export = export) # 获取结果对象
553
- if export:
518
+ self.__target_obj,new_var,lambda:_getattr(self.__target_obj,attr),
519
+ export = is_export) # 获取结果对象
520
+ if is_export:
554
521
  return result
555
522
 
556
- if self.__export_trivial_obj and is_trivial_obj(result)\
557
- or self.__chain.is_export_attr(attr,self.__name):
523
+ if self.__export_trivial_obj and is_trivial_obj(result) or is_export:
558
524
  self.__chain.add_exported_obj(result, new_var)
559
525
  return result # 直接返回结果,不继续返回ProxiedObj
560
526
  else:
@@ -564,25 +530,27 @@ class ProxiedObj:
564
530
  self.__chain,new_var,result,
565
531
  self.__chain.is_export_func(attr,self.__name),
566
532
  self.__export_trivial_obj)
567
- @magic_meth_chained("{_var} = str({_self})",export=True)
568
- def __str__(self): pass
569
- @magic_meth_chained("{_var} = repr({_self})",export=True)
570
- def __repr__(self): pass
571
- @magic_meth_chained("{_var} = dir({_self})",export=True)
572
- def __dir__(self): pass
573
- @magic_meth_chained("{_self}.{} = {!r}", False)
574
- def __setattr_override(self,attr,value):pass
575
- def __setattr__(self,attr,value):
533
+
534
+ #@magic_meth_chained("{_var} = str({_self})",export=True)
535
+ #def __str__(self): return str(self)
536
+ # 优化函数调用开销
537
+ __str__ = magic_meth_chained("{_var} = str({_self})",export=True)(str)
538
+ __repr__ = magic_meth_chained("{_var} = repr({_self})",export=True)(repr)
539
+ __dir__ = magic_meth_chained("{_var} = dir({_self})",export=True)(dir)
540
+ __setattr_override = magic_meth_chained("{_self}.{} = {!r}", False)(setattr)
541
+
542
+ def __setattr__(self,attr,value): # 仅用于__no_self_attr
576
543
  dct = object.__getattribute__(self,"__dict__")
577
544
  if not dct.get("_ProxiedObj__no_self_attr",False):
578
545
  object.__setattr__(self,attr,value)
579
546
  else:
580
547
  self.__setattr_override(attr,value)
581
- def __getattribute__(self,attr):
548
+ def __getattribute__(self,attr): # 仅用于__no_self_attr
582
549
  result = object.__getattribute__(self,attr)
583
550
  if object.__getattribute__(self,"__dict__").get(
584
551
  "_ProxiedObj__no_self_attr",False) \
585
552
  and not attr.startswith("_ProxiedObj"):
553
+ #return type(self).__getattr__(self,attr)
586
554
  raise AttributeError # 改用__getattr__
587
555
  return result
588
556
  def __new__(cls,*args,**kw):
@@ -598,160 +566,182 @@ class ProxiedObj:
598
566
 
599
567
  # 算术运算符
600
568
  @magic_meth_chained("{_var} = {_self} + {!r}")
601
- def __add__(self, other): pass
569
+ def __add__(self, other): return self + other
602
570
  @magic_meth_chained("{_var} = {_self} - {!r}")
603
- def __sub__(self, other): pass
571
+ def __sub__(self, other): return self - other
604
572
  @magic_meth_chained("{_var} = {_self} * {!r}")
605
- def __mul__(self, other): pass
573
+ def __mul__(self, other): return self * other
606
574
  @magic_meth_chained("{_var} = {_self} / {!r}")
607
- def __truediv__(self, other): pass
575
+ def __truediv__(self, other): return self / other
608
576
  @magic_meth_chained("{_var} = {_self} // {!r}")
609
- def __floordiv__(self, other): pass
577
+ def __floordiv__(self, other): return self // other
610
578
  @magic_meth_chained("{_var} = {_self} % {!r}")
611
- def __mod__(self, other): pass
579
+ def __mod__(self, other): return self % other
612
580
  @magic_meth_chained("{_var} = {_self} ** {!r}")
613
- def __pow__(self, other): pass
581
+ def __pow__(self, other): return self ** other
614
582
  @magic_meth_chained("{_var} = {_self} << {!r}")
615
- def __lshift__(self, other): pass
583
+ def __lshift__(self, other): return self << other
616
584
  @magic_meth_chained("{_var} = {_self} >> {!r}")
617
- def __rshift__(self, other): pass
585
+ def __rshift__(self, other): return self >> other
618
586
  @magic_meth_chained("{_var} = {_self} & {!r}")
619
- def __and__(self, other): pass
587
+ def __and__(self, other): return self & other
620
588
  @magic_meth_chained("{_var} = {_self} ^ {!r}")
621
- def __xor__(self, other): pass
589
+ def __xor__(self, other): return self ^ other
622
590
  @magic_meth_chained("{_var} = {_self} | {!r}")
623
- def __or__(self, other): pass
591
+ def __or__(self, other): return self | other
624
592
 
625
593
  # 反向算术运算符
594
+ @magic_meth_chained("{_var} = {!r} + {_self}")
595
+ def __radd__(self, other): return other + self
626
596
  @magic_meth_chained("{_var} = {!r} - {_self}")
627
- def __radd__(self, other): pass
628
- @magic_meth_chained("{_var} = {!r} - {_self}")
629
- def __rsub__(self, other): pass
597
+ def __rsub__(self, other): return other - self
630
598
  @magic_meth_chained("{_var} = {!r} * {_self}")
631
- def __rmul__(self, other): pass
599
+ def __rmul__(self, other): return other * self
632
600
  @magic_meth_chained("{_var} = {!r} / {_self}")
633
- def __rtruediv__(self, other): pass
601
+ def __rtruediv__(self, other): return other / self
634
602
  @magic_meth_chained("{_var} = {!r} // {_self}")
635
- def __rfloordiv__(self, other): pass
603
+ def __rfloordiv__(self, other): return other // self
636
604
  @magic_meth_chained("{_var} = {!r} % {_self}")
637
- def __rmod__(self, other): pass
605
+ def __rmod__(self, other): return other % self
638
606
  @magic_meth_chained("{_var} = {!r} ** {_self}")
639
- def __rpow__(self, other): pass
607
+ def __rpow__(self, other): return other ** self
640
608
  @magic_meth_chained("{_var} = {!r} << {_self}")
641
- def __rlshift__(self, other): pass
609
+ def __rlshift__(self, other): return other << self
642
610
  @magic_meth_chained("{_var} = {!r} >> {_self}")
643
- def __rrshift__(self, other): pass
611
+ def __rrshift__(self, other): return other >> self
644
612
  @magic_meth_chained("{_var} = {!r} & {_self}")
645
- def __rand__(self, other): pass
613
+ def __rand__(self, other): return other & self
646
614
  @magic_meth_chained("{_var} = {!r} ^ {_self}")
647
- def __rxor__(self, other): pass
615
+ def __rxor__(self, other): return other ^ self
648
616
  @magic_meth_chained("{_var} = {!r} | {_self}")
649
- def __ror__(self, other): pass
617
+ def __ror__(self, other): return other | self
650
618
 
651
619
  # 增量赋值
652
- @magic_meth_chained("{_self} += {!r}", False)
653
- def __iadd__(self, other): pass
654
- @magic_meth_chained("{_self} -= {!r}", False)
655
- def __isub__(self, other): pass
656
- @magic_meth_chained("{_self} *= {!r}", False)
657
- def __imul__(self, other): pass
658
- @magic_meth_chained("{_self} /= {!r}", False)
659
- def __itruediv__(self, other): pass
660
- @magic_meth_chained("{_self} //= {!r}", False)
661
- def __ifloordiv__(self, other): pass
662
- @magic_meth_chained("{_self} %= {!r}", False)
663
- def __imod__(self, other): pass
664
- @magic_meth_chained("{_self} **= {!r}", False)
665
- def __ipow__(self, other): pass
666
- @magic_meth_chained("{_self} <<= {!r}", False)
667
- def __ilshift__(self, other): pass
668
- @magic_meth_chained("{_self} >>= {!r}", False)
669
- def __irshift__(self, other): pass
670
- @magic_meth_chained("{_self} &= {!r}", False)
671
- def __iand__(self, other): pass
672
- @magic_meth_chained("{_self} |= {!r}", False)
673
- def __ior__(self, other): pass
674
- @magic_meth_chained("{_self} ^= {!r}", False)
675
- def __ixor__(self, other): pass
620
+ @magic_meth_chained("{_self} += {!r}", aug_assign=True)
621
+ def __iadd__(self, other): self += other; return self
622
+ @magic_meth_chained("{_self} -= {!r}", aug_assign=True)
623
+ def __isub__(self, other): self -= other; return self
624
+ @magic_meth_chained("{_self} *= {!r}", aug_assign=True)
625
+ def __imul__(self, other): self *= other; return self
626
+ @magic_meth_chained("{_self} /= {!r}", aug_assign=True)
627
+ def __itruediv__(self, other): self /= other; return self
628
+ @magic_meth_chained("{_self} //= {!r}", aug_assign=True)
629
+ def __ifloordiv__(self, other): self //= other; return self
630
+ @magic_meth_chained("{_self} %= {!r}", aug_assign=True)
631
+ def __imod__(self, other): self %= other; return self
632
+ @magic_meth_chained("{_self} **= {!r}", aug_assign=True)
633
+ def __ipow__(self, other): self **= other; return self
634
+ @magic_meth_chained("{_self} <<= {!r}", aug_assign=True)
635
+ def __ilshift__(self, other): self <<= other; return self
636
+ @magic_meth_chained("{_self} >>= {!r}", aug_assign=True)
637
+ def __irshift__(self, other): self >>= other; return self
638
+ @magic_meth_chained("{_self} &= {!r}", aug_assign=True)
639
+ def __iand__(self, other): self &= other; return self
640
+ @magic_meth_chained("{_self} |= {!r}", aug_assign=True)
641
+ def __ior__(self, other): self |= other; return self
642
+ @magic_meth_chained("{_self} ^= {!r}", aug_assign=True)
643
+ def __ixor__(self, other): self ^= other; return self
676
644
 
677
645
  # 比较运算符
678
646
  @magic_meth_chained("{_var} = {_self} < {!r}",export=True)
679
- def __lt__(self, other): pass
647
+ def __lt__(self, other): return self < other
680
648
  @magic_meth_chained("{_var} = {_self} <= {!r}",export=True)
681
- def __le__(self, other): pass
649
+ def __le__(self, other): return self <= other
682
650
  @magic_meth_chained("{_var} = {_self} == {!r}",export=True)
683
- def __eq__(self, other): pass
651
+ def __eq__(self, other): return self == other
684
652
  @magic_meth_chained("{_var} = {_self} != {!r}",export=True)
685
- def __ne__(self, other): pass
653
+ def __ne__(self, other): return self != other
686
654
  @magic_meth_chained("{_var} = {_self} > {!r}",export=True)
687
- def __gt__(self, other): pass
655
+ def __gt__(self, other): return self > other
688
656
  @magic_meth_chained("{_var} = {_self} >= {!r}",export=True)
689
- def __ge__(self, other): pass
657
+ def __ge__(self, other): return self >= other
690
658
 
691
659
  # 一元运算符
692
660
  @magic_meth_chained("{_var} = -{_self}")
693
- def __neg__(self): pass
661
+ def __neg__(self): return -self
694
662
  @magic_meth_chained("{_var} = +{_self}")
695
- def __pos__(self): pass
696
- @magic_meth_chained("{_var} = abs({_self})")
697
- def __abs__(self): pass
663
+ def __pos__(self): return +self
698
664
  @magic_meth_chained("{_var} = ~{_self}")
699
- def __invert__(self): pass
665
+ def __invert__(self): return ~self
666
+ __abs__ = magic_meth_chained("{_var} = abs({_self})")(abs)
700
667
 
701
668
  # 容器/迭代器
702
- @magic_meth_chained("{_var} = len({_self})",export=True)
703
- def __len__(self): pass
669
+ __len__ = magic_meth_chained("{_var} = len({_self})",export=True)(len)
704
670
  @magic_meth_chained("{_var} = {_self}[{!r}]")
705
- def __getitem__(self, key): pass
671
+ def __getitem__(self, key): return self[key]
706
672
  @magic_meth_chained("{_self}[{!r}] = {!r}", False)
707
- def __setitem__(self, key, value): pass
673
+ def __setitem__(self, key, value): self[key] = value
708
674
  @magic_meth_chained("del {_self}[{!r}]", False)
709
- def __delitem__(self, key): pass
710
- @magic_meth_chained("{_var} = reversed({_self})",export=True)
711
- def __reversed__(self):pass
675
+ def __delitem__(self, key): del self[key]
712
676
  @magic_meth_chained("{_var} = {!r} in {_self}",export=True)
713
- def __contains__(self, item):pass
714
- @magic_meth_chained("{_var} = iter({_self})",export=True)
715
- def __iter__(self):pass
716
- @magic_meth_chained("{_var} = next({_self})",export=True)
717
- def __next__(self):pass
677
+ def __contains__(self, item): return item in self
678
+ __reversed__ = magic_meth_chained("{_var} = reversed({_self})",
679
+ export=True)(reversed)
680
+ __iter__ = magic_meth_chained("{_var} = iter({_self})",export=True)(iter)
681
+ __next__ = magic_meth_chained("{_var} = next({_self})",export=True)(next)
718
682
 
719
683
  # 类型转换
720
- @magic_meth_chained("{_var} = int({_self})",export=True)
721
- def __int__(self):pass
722
- @magic_meth_chained("{_var} = float({_self})",export=True)
723
- def __float__(self):pass
724
- @magic_meth_chained("{_var} = complex({_self})",export=True)
725
- def __complex__(self):pass
726
- @magic_meth_chained("{_var} = round({_self}, {!r})",export=True)
727
- def __round__(self, ndigits=None):pass
728
- @magic_meth_chained("{_var} = bool({_self})",export=True)
729
- def __bool__(self): pass
730
- @magic_meth_chained("{_var} = hash({_self})",export=True)
731
- def __hash__(self): pass
684
+ __int__ = magic_meth_chained("{_var} = int({_self})",export=True)(int)
685
+ __float__ = magic_meth_chained("{_var} = float({_self})",export=True)(float)
686
+ __complex__ = magic_meth_chained("{_var} = complex({_self})",
687
+ export=True)(complex)
688
+ __round__ = magic_meth_chained("{_var} = round({_self}, {!r})",
689
+ export=True)(round)
690
+ __bool__ = magic_meth_chained("{_var} = bool({_self})",export=True)(bool)
691
+ __hash__ = magic_meth_chained("{_var} = hash({_self})",export=True)(hash)
732
692
 
733
693
  # 上下文管理
734
- #@magic_meth_chained("with {_self}:",False,1)
735
694
  @magic_meth_chained(default_fmt=True)
736
- def __enter__(self): pass
737
- #@magic_meth_chained("",False,-1)
695
+ def __enter__(self): return self.__enter__()
738
696
  @magic_meth_chained(default_fmt=True,export=True)
739
- def __exit__(self, exc_type, exc_value, traceback): pass
697
+ def __exit__(self, exc_type, exc_value, traceback):
698
+ return self.__exit__(exc_type, exc_value, traceback)
740
699
 
741
700
  # 其他
742
- @magic_meth_chained(default_fmt=True,export=True)
701
+ @magic_meth_chained(default_fmt=True,export=True,no_exec=False)
743
702
  def __await__(self):pass
744
- @magic_meth_chained(default_fmt=True,export=True)
703
+ @magic_meth_chained(default_fmt=True,export=True,no_exec=False)
745
704
  def __aiter__(self):pass
746
705
  @magic_meth_chained(default_fmt=True,export=True)
747
- def __fspath__(self):pass
706
+ def __fspath__(self):return self.__fspath__()
707
+
708
+ def proxyCls(T=_EmptyTarget, chain=EMPTY_OBJ, fromvar=None):
709
+ # 泛型,proxyCls(T)生成类型信息为T的继承自ProxiedObj的类
710
+ if T is EMPTY_OBJ:
711
+ return ProxiedObj
712
+
713
+ class ProxyCls(ProxiedObj): # 创建同时从ProxiedObj与T继承的类
714
+ # pylint: disable=unused-private-member
715
+ __proto = T # 自身使用的原型
716
+ def __new__(cls,*args,**kw):
717
+ _chain = args[0] if args else kw.get("chain")
718
+ if not _isinstance(_chain,ObjChain) and chain is not EMPTY_OBJ:
719
+ var = chain.new_var(T.__name__)
720
+ if fromvar is not None:
721
+ cls_ = chain.add_existing_obj(T,var,f"{var} = {fromvar}.__class__",
722
+ [fromvar])
723
+ else:
724
+ cls_ = chain.add_existing_obj(T,var,
725
+ f"# class {var}: {shortrepr(cls,repr_func=basic_repr)}")
726
+ if len(args) == 3 and _isinstance(T,type):
727
+ args=(args[0],tuple(unproxy_obj(cls) for cls in args[1]),args[2])
728
+
729
+ if kw:return cls_(*args,**kw)
730
+ return cls_(*args) # 返回ProxyCls
731
+ else:
732
+ return ProxiedObj.__new__(cls,*args,**kw)
733
+
734
+ return ProxyCls
735
+
748
736
 
749
737
  _isinstance = isinstance
738
+ _getattr = getattr
750
739
  from pyobject.objproxy.builtin_hook import hook_builtins # pylint: disable=ungrouped-imports
751
740
  hook_builtins() # hook内置函数
752
741
 
753
742
  def proxy_demo():
754
- chain = ObjChain(export_attrs=["__array_struct__"])
743
+ chain = ObjChain(export_attrs=["__array_struct__"],
744
+ export_trivial_obj=True)
755
745
  try:
756
746
  np = chain.new_object("import numpy as np","np")
757
747
  plt = chain.new_object("import matplotlib.pyplot as plt","plt",
@@ -1,7 +1,7 @@
1
1
  # 内置函数和部分标准库函数的hook
2
2
  import sys,builtins,_collections_abc,inspect
3
3
  import collections.abc as collections_abc
4
- from pyobject.objproxy import ProxiedObj,accept_raw_obj
4
+ from pyobject.objproxy import ProxiedObj
5
5
 
6
6
  _range = type(range(0)) #range
7
7
  def range(*args):
@@ -65,11 +65,9 @@ def callable(obj):
65
65
  if _isinstance(obj, ProxiedObj):
66
66
  obj = obj._ProxiedObj__target_obj
67
67
  return _callable(obj)
68
- def getattr(*args,**kw):
68
+ def getattr(*args):
69
69
  if _isinstance(args[1],ProxiedObj):
70
70
  args = (args[0], args[1]._ProxiedObj__target_obj, *args[2:])
71
- if "name" in kw and _isinstance(kw["name"],ProxiedObj):
72
- kw["name"] = kw["name"]._ProxiedObj__target_obj
73
71
  return _getattr(*args)
74
72
 
75
73
  _pre_check_methods = _collections_abc._check_methods
@@ -138,19 +136,3 @@ def hook_builtins():
138
136
  collections_abc._check_methods = _check_methods
139
137
  inspect.signature = signature
140
138
  inspect.getattr_static = getattr_static
141
-
142
- # 内置类型的修改(备用)
143
- class CustomStr(builtins.str):
144
- __init__ = accept_raw_obj(builtins.str,lambda args:args[1:],
145
- process_ret=lambda ret:None)
146
- __new__ = accept_raw_obj(builtins.str,lambda args:args[1:])
147
-
148
- class CustomInt(builtins.int):
149
- __init__ = accept_raw_obj(builtins.int,lambda args:args[1:],
150
- process_ret=lambda ret:None)
151
- __new__ = accept_raw_obj(builtins.int,lambda args:args[1:])
152
-
153
- class CustomBytes(builtins.bytes):
154
- __init__ = accept_raw_obj(builtins.bytes,lambda args:args[1:],
155
- process_ret=lambda ret:None)
156
- __new__ = accept_raw_obj(builtins.bytes,lambda args:args[1:])
@@ -8,7 +8,7 @@ except ImportError:
8
8
  sys.path.append(path) # 加入当前pyobject库所在的目录
9
9
  from pyobject import ObjChain, ProxiedObj
10
10
 
11
- def current_func_name(level = 0):
11
+ def current_func_name(level = 0): # 获取当前函数名,便于调试输出
12
12
  frame = sys._getframe()
13
13
  for i in range(level + 1):
14
14
  if frame is None:return None
@@ -87,6 +87,26 @@ class TestObjChain(unittest.TestCase):
87
87
  class Inherited(cls):pass
88
88
  Inherited().meth()
89
89
  self.print_code(chain, print_optimized = True)
90
+ def test_aug_assign(self):
91
+ class Cls:
92
+ def __iadd__(self, inc):return inc
93
+ def __isub__(self, dec):return self
94
+
95
+ chain = ObjChain()
96
+ obj = chain.add_existing_obj(Cls(),"obj")
97
+ var1=obj; var1+=1
98
+ self.assertEqual(var1, 1)
99
+ self.print_code(chain, print_optimized = True)
100
+ def test_setattr(self):
101
+ class Cls:
102
+ def __init__(self):
103
+ self.attr = 42
104
+
105
+ chain = ObjChain()
106
+ obj = chain.add_existing_obj(Cls(),"obj")
107
+ obj.attr = 1
108
+ self.assertEqual(obj.attr, 1)
109
+ self.print_code(chain)
90
110
  def test_export(self): # 测试export_funcs和export_attrs
91
111
  class Cls:
92
112
  def __init__(self):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pyobject
3
- Version: 1.2.9.2
3
+ Version: 1.3.0
4
4
  Summary: A multifunctional all-in-one utility tool for managing internal Python objects, compatible with nearly all Python 3 versions. 一个多功能合一的提供操作Python对象底层工具的Python包, 支持几乎所有Python 3版本。
5
5
  Home-page: https://github.com/qfcy/pyobject
6
6
  Author: qfcy
@@ -394,11 +394,12 @@ Python内部的字节码对象\ ``CodeType``\ ,如\ ``func.__code__``\ ,是
394
394
  lst调用多次==运算符(``__eq__``)相比,
395
395
  本函数直接比较对象的指针,提高了效率。
396
396
 
397
- **``pyobject``\ 当前版本**: 1.2.9.2
397
+ **``pyobject``\ 当前版本**: 1.3.0
398
398
 
399
399
  更新日志:
400
400
  ---------
401
401
 
402
+ | 2025-6-6(v1.3.0):性能优化,提升了pyobject.objproxy模块的性能。
402
403
  | 2025-4-30(v1.2.9):改进和增强了子模块pyobject.objproxy,重命名子模块pyobject.code_为pyobject.code。
403
404
  | 2025-3-31(v1.2.8):将pyobject.super_proxy重命名为pyobject.objproxy,并正式发布;修改了pyobject.pyobj_extension模块。
404
405
  | 2025-3-6(v1.2.7):为pyobject.browser新增了\ ``dir()``\ 中不存在的类属性(如\ ``__flags__``,
@@ -886,11 +887,13 @@ Python call “obj in lst” that invokes the “==” operator (``__eq__``)
886
887
  multiple times, this function directly compares the pointers to improve
887
888
  efficiency.
888
889
 
889
- **Current Version of ``pyobject``**: 1.2.9.2
890
+ **Current Version of ``pyobject``**: 1.3.0
890
891
 
891
892
  Change Log
892
893
  ----------
893
894
 
895
+ | 2025-6-6(v1.3.0): Optimized the performance of the pyobject.objproxy
896
+ module.
894
897
  | 2025-4-30(v1.2.9): Improved and enhanced the sub-module
895
898
  ``pyobject.objproxy``, and renamed the sub-module ``pyobject.code_``
896
899
  to ``pyobject.code``.
@@ -35,7 +35,6 @@ pyobject/images/string.gif
35
35
  pyobject/images/tuple.gif
36
36
  pyobject/objproxy/__init__.py
37
37
  pyobject/objproxy/builtin_hook.py
38
- pyobject/objproxy/dynobj.py
39
38
  pyobject/objproxy/optimize.py
40
39
  pyobject/objproxy/utils.py
41
40
  pyobject/other/browser_chs_locale.py
@@ -1,190 +0,0 @@
1
- # 实现简单的不可变的链式求值对象(备用,也是后续ProxiedObj的原型)
2
- import functools
3
- try:from timer_tool import timer # pip install timer-tool
4
- except ImportError:timer=lambda func:func
5
- from pyobject.objproxy.utils import format_func_call
6
-
7
- ENABLE_CACHE = False
8
-
9
- def using_namespace(obj,scope,except_=[],internal=False):
10
- for name in dir(obj):
11
- if not internal and name.startswith("_"):continue
12
- if name in except_:continue
13
- scope[name]=getattr(obj,name)
14
-
15
- def unuse_namespace(obj,scope,except_=[],internal=False):
16
- # 参数应和之前调用using_namespace的一致
17
- for name in dir(obj):
18
- if not internal and name.startswith("_"):continue
19
- if name in except_:continue
20
- del scope[name]
21
-
22
- def define_enum(names,local,start=0):
23
- # names: 字符串列表,或者以","和\n分割的字符串
24
- if isinstance(names,str):
25
- ignored=str.maketrans("","","\n ")
26
- names=names.translate(ignored).split(",")
27
- for i,name in enumerate(names,start):
28
- local[name]=i
29
-
30
- class Symbol:
31
- define_enum(
32
- """ADD, SUB, MUL, DIV, MOD, POW, FLOOR_DIV,
33
- AND, OR, XOR, NOT,
34
- LT, LE, EQ, NE, GT, GE,
35
- LSHIFT, RSHIFT,
36
- BIT_AND, BIT_OR, BIT_XOR, BIT_NOT,
37
- ASSIGN,NEG,POS,
38
- PLUS_ASSIGN, MINUS_ASSIGN, MUL_ASSIGN, DIV_ASSIGN, MOD_ASSIGN, POW_ASSIGN, FLOOR_DIV_ASSIGN,
39
- LSHIFT_ASSIGN, RSHIFT_ASSIGN, AND_ASSIGN, OR_ASSIGN, XOR_ASSIGN, HIGHEST""",
40
- locals()
41
- )
42
-
43
- priority = [
44
- # 优先级最低:赋值运算符
45
- (ASSIGN, PLUS_ASSIGN, MINUS_ASSIGN, MUL_ASSIGN, DIV_ASSIGN, MOD_ASSIGN, POW_ASSIGN,
46
- FLOOR_DIV_ASSIGN, LSHIFT_ASSIGN, RSHIFT_ASSIGN, AND_ASSIGN, OR_ASSIGN, XOR_ASSIGN),
47
- # 逻辑运算符
48
- (OR, AND),
49
- # 比较运算符
50
- (LT, LE, EQ, NE, GT, GE),
51
- # 位运算符
52
- (BIT_OR,),
53
- (BIT_XOR,),
54
- (BIT_AND,),
55
- # 位移运算符
56
- (LSHIFT, RSHIFT),
57
- # 算术运算符
58
- (ADD, SUB),
59
- (MUL, DIV, MOD, FLOOR_DIV),
60
- # 幂运算符
61
- (POW,),
62
- # 一元运算符
63
- (NOT, BIT_NOT, NEG, POS),
64
- # 最高优先级的占位符
65
- (HIGHEST,),
66
- ]
67
-
68
- PRIORITY={}
69
- for level in range(len(Symbol.priority)):
70
- for symbol in Symbol.priority[level]:
71
- PRIORITY[symbol]=level
72
-
73
- using_namespace(Symbol,globals(),["priority"])
74
-
75
- def ck(obj,symbol):
76
- # 如对于x + (y * z),outer_priority为"+",inner_priority为"*"
77
- outer_priority=PRIORITY[symbol]
78
- inner_priority=PRIORITY[getattr(obj,"_DynObj__last_symbol",HIGHEST)]
79
- fmt="({!r})" if outer_priority > inner_priority else "{!r}"
80
- return fmt.format(obj)
81
-
82
- def magic_meth(meth): # 用于无法获知具体表达式的魔法方法调用(备用函数)
83
- @functools.wraps(meth)
84
- def override(self,*args,**kw):
85
- return DynObj(f"{ck(self, HIGHEST)}.{meth.__name__}") # 优先级使用默认的HIGHEST
86
- return override
87
-
88
- # 能包装表达式链式求值的对象(不可变)
89
- class DynObj:
90
- _cache = {}
91
- if ENABLE_CACHE:
92
- def __new__(cls, code, symbol=HIGHEST):
93
- if code in cls._cache:
94
- return cls._cache[code]
95
- instance = super().__new__(cls)
96
- cls._cache[code] = instance
97
- return instance
98
-
99
- def __init__(self,code,symbol=HIGHEST):
100
- self.__code=code # __code仅在__str__和__repr__使用
101
- self.__last_symbol=symbol # pylint: disable=unused-private-member
102
- def __call__(self,*args,**kw):
103
- new_code="{}({})".format(self, format_func_call(args,kw))
104
- return DynObj(new_code)
105
- def __getattr__(self,name):
106
- new_code="{}.{}".format(self,name)
107
- return DynObj(new_code)
108
- def __str__(self):
109
- return self.__code
110
- def __repr__(self):
111
- return self.__code
112
-
113
- # 算术运算符
114
- def __add__(self, other): return DynObj(f"{ck(self, ADD)} + {ck(other,ADD)}",ADD)
115
- def __sub__(self, other): return DynObj(f"{ck(self, SUB)} - {ck(other,SUB)}",SUB)
116
- def __mul__(self, other): return DynObj(f"{ck(self, MUL)} * {ck(other,MUL)}",MUL)
117
- def __truediv__(self, other):
118
- return DynObj(f"{ck(self, DIV)} / {ck(other, DIV)}", DIV)
119
- def __floordiv__(self, other):
120
- return DynObj(f"{ck(self, FLOOR_DIV)} // {ck(other, FLOOR_DIV)}", FLOOR_DIV)
121
- def __mod__(self, other): return DynObj(f"{ck(self, MOD)} % {ck(other, MOD)}", MOD)
122
- def __pow__(self, other): return DynObj(f"{ck(self, POW)} ** {ck(other, POW)}", POW)
123
- def __lshift__(self, other):
124
- return DynObj(f"{ck(self, LSHIFT)} << {ck(other, LSHIFT)}", LSHIFT)
125
- def __rshift__(self, other):
126
- return DynObj(f"{ck(self, RSHIFT)} >> {ck(other, RSHIFT)}", RSHIFT)
127
- def __and__(self, other): return DynObj(f"{ck(self, BIT_AND)} & {ck(other, BIT_AND)}", BIT_AND)
128
- def __xor__(self, other): return DynObj(f"{ck(self, BIT_XOR)} ^ {ck(other, BIT_XOR)}", BIT_XOR)
129
- def __or__(self, other): return DynObj(f"{ck(self, BIT_OR)} | {ck(other, BIT_OR)}", BIT_OR)
130
-
131
- # 反向算术运算符
132
- def __radd__(self, other): return DynObj(f"{ck(other, ADD)} + {ck(self, ADD)}", ADD)
133
- def __rsub__(self, other): return DynObj(f"{ck(other, SUB)} - {ck(self, SUB)}", SUB)
134
- def __rmul__(self, other): return DynObj(f"{ck(other, MUL)} * {ck(self, MUL)}", MUL)
135
- def __rtruediv__(self, other):
136
- return DynObj(f"{ck(other, DIV)} / {ck(self, DIV)}", DIV)
137
- def __rfloordiv__(self, other):
138
- return DynObj(f"{ck(other, FLOOR_DIV)} // {ck(self, FLOOR_DIV)}", FLOOR_DIV)
139
- def __rmod__(self, other): return DynObj(f"{ck(other, MOD)} % {ck(self, MOD)}", MOD)
140
- def __rpow__(self, other): return DynObj(f"{ck(other, POW)} ** {ck(self, POW)}", POW)
141
- def __rlshift__(self, other):
142
- return DynObj(f"{ck(other, LSHIFT)} << {ck(self, LSHIFT)}", LSHIFT)
143
- def __rrshift__(self, other):
144
- return DynObj(f"{ck(other, RSHIFT)} >> {ck(self, RSHIFT)}", RSHIFT)
145
- def __rand__(self, other): return DynObj(f"{ck(other, BIT_AND)} & {ck(self, BIT_AND)}", BIT_AND)
146
- def __rxor__(self, other): return DynObj(f"{ck(other, BIT_XOR)} ^ {ck(self, BIT_XOR)}", BIT_XOR)
147
- def __ror__(self, other): return DynObj(f"{ck(other, BIT_OR)} | {ck(self, BIT_OR)}", BIT_OR)
148
-
149
- # 比较运算符
150
- def __lt__(self, other): return DynObj(f"{ck(self, LT)} < {ck(other, LT)}", LT)
151
- def __le__(self, other): return DynObj(f"{ck(self, LE)} <= {ck(other, LE)}", LE)
152
- def __eq__(self, other): return DynObj(f"{ck(self, EQ)} == {ck(other, EQ)}", EQ)
153
- def __ne__(self, other): return DynObj(f"{ck(self, NE)} != {ck(other, NE)}", NE)
154
- def __gt__(self, other): return DynObj(f"{ck(self, GT)} > {ck(other, GT)}", GT)
155
- def __ge__(self, other): return DynObj(f"{ck(self, GE)} >= {ck(other, GE)}", GE)
156
-
157
- # 一元运算符
158
- def __neg__(self): return DynObj(f"-{ck(self, NEG)}", NEG)
159
- def __pos__(self): return DynObj(f"+{ck(self, POS)}", POS)
160
- def __abs__(self): return DynObj(f"abs({self})")
161
- def __invert__(self): return DynObj(f"~{ck(self, BIT_NOT)}", BIT_NOT)
162
-
163
- # 容器协议
164
- #def __len__(self): return DynObj(f"len({self})")
165
- def __getitem__(self, key): return DynObj(f"{self}[{key!r}]")
166
- #def __setitem__(self, key, value): return DynObj(f"{self}[{key!r}] = {value!r}")
167
- #def __delitem__(self, key): return DynObj(f"del {self}[{key!r}]")
168
- #def __contains__(self, item):pass
169
-
170
- # 类型转换 (待实现)
171
- #def __int__(self):pass
172
- #def __float__(self):pass
173
- #def __complex__(self):pass
174
- #def __round__(self, ndigits=None):pass
175
-
176
- def test():
177
- _1=DynObj("1");_2=DynObj("2")
178
- print(-(_1+_2)*_1)
179
-
180
- @timer
181
- def test_perf():
182
- def recursion(x=None,recurse=10):
183
- if recurse<=0:return x
184
- return recursion(-(x+x)*x/x//x,recurse-1)
185
-
186
- x=DynObj("x")
187
- obj=recursion(x,10)
188
- print(recursion(x,1),":",len(repr(obj)))
189
-
190
- if __name__ == "__main__":test_perf()
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes