pyobject 1.2.9__tar.gz → 1.2.9.2__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/pyobject.egg-info → pyobject-1.2.9.2}/PKG-INFO +7 -7
  2. {pyobject-1.2.9 → pyobject-1.2.9.2}/README.rst +6 -6
  3. {pyobject-1.2.9 → pyobject-1.2.9.2}/pyobject/__init__.py +4 -4
  4. {pyobject-1.2.9 → pyobject-1.2.9.2}/pyobject/objproxy/__init__.py +78 -43
  5. {pyobject-1.2.9 → pyobject-1.2.9.2}/pyobject/objproxy/builtin_hook.py +56 -6
  6. {pyobject-1.2.9 → pyobject-1.2.9.2}/pyobject/objproxy/dynobj.py +4 -4
  7. {pyobject-1.2.9 → pyobject-1.2.9.2}/pyobject/objproxy/optimize.py +6 -5
  8. {pyobject-1.2.9 → pyobject-1.2.9.2}/pyobject/objproxy/utils.py +1 -1
  9. {pyobject-1.2.9 → pyobject-1.2.9.2}/pyobject/pyobj_extension.c +1 -1
  10. {pyobject-1.2.9 → pyobject-1.2.9.2}/pyobject/tests/test_objproxy.py +1 -1
  11. pyobject-1.2.9.2/pyobject/tests/test_objproxy_perf.py +49 -0
  12. {pyobject-1.2.9 → pyobject-1.2.9.2/pyobject.egg-info}/PKG-INFO +7 -7
  13. {pyobject-1.2.9 → pyobject-1.2.9.2}/pyobject.egg-info/SOURCES.txt +2 -1
  14. {pyobject-1.2.9 → pyobject-1.2.9.2}/LICENSE +0 -0
  15. {pyobject-1.2.9 → pyobject-1.2.9.2}/MANIFEST.in +0 -0
  16. {pyobject-1.2.9 → pyobject-1.2.9.2}/pyobject/browser.py +0 -0
  17. {pyobject-1.2.9 → pyobject-1.2.9.2}/pyobject/code.py +0 -0
  18. {pyobject-1.2.9 → pyobject-1.2.9.2}/pyobject/examples/README.md +0 -0
  19. {pyobject-1.2.9 → pyobject-1.2.9.2}/pyobject/examples/__init__.py +0 -0
  20. {pyobject-1.2.9 → pyobject-1.2.9.2}/pyobject/examples/empty_cp37.pyc +0 -0
  21. {pyobject-1.2.9 → pyobject-1.2.9.2}/pyobject/examples/pyc_zipper_unpack.py +0 -0
  22. {pyobject-1.2.9 → pyobject-1.2.9.2}/pyobject/examples/pyc_zipper_zlib.py +0 -0
  23. {pyobject-1.2.9 → pyobject-1.2.9.2}/pyobject/examples/test_inject.py +0 -0
  24. {pyobject-1.2.9 → pyobject-1.2.9.2}/pyobject/images/back.gif +0 -0
  25. {pyobject-1.2.9 → pyobject-1.2.9.2}/pyobject/images/codeobject.gif +0 -0
  26. {pyobject-1.2.9 → pyobject-1.2.9.2}/pyobject/images/dict.gif +0 -0
  27. {pyobject-1.2.9 → pyobject-1.2.9.2}/pyobject/images/empty_dict.gif +0 -0
  28. {pyobject-1.2.9 → pyobject-1.2.9.2}/pyobject/images/empty_list.gif +0 -0
  29. {pyobject-1.2.9 → pyobject-1.2.9.2}/pyobject/images/empty_tuple.gif +0 -0
  30. {pyobject-1.2.9 → pyobject-1.2.9.2}/pyobject/images/forward.gif +0 -0
  31. {pyobject-1.2.9 → pyobject-1.2.9.2}/pyobject/images/function.gif +0 -0
  32. {pyobject-1.2.9 → pyobject-1.2.9.2}/pyobject/images/list.gif +0 -0
  33. {pyobject-1.2.9 → pyobject-1.2.9.2}/pyobject/images/number.gif +0 -0
  34. {pyobject-1.2.9 → pyobject-1.2.9.2}/pyobject/images/python.gif +0 -0
  35. {pyobject-1.2.9 → pyobject-1.2.9.2}/pyobject/images/python.ico +0 -0
  36. {pyobject-1.2.9 → pyobject-1.2.9.2}/pyobject/images/refresh.gif +0 -0
  37. {pyobject-1.2.9 → pyobject-1.2.9.2}/pyobject/images/string.gif +0 -0
  38. {pyobject-1.2.9 → pyobject-1.2.9.2}/pyobject/images/tuple.gif +0 -0
  39. {pyobject-1.2.9 → pyobject-1.2.9.2}/pyobject/other/browser_chs_locale.py +0 -0
  40. {pyobject-1.2.9 → pyobject-1.2.9.2}/pyobject/search.py +0 -0
  41. {pyobject-1.2.9 → pyobject-1.2.9.2}/pyobject/tests/test_code.py +0 -0
  42. {pyobject-1.2.9 → pyobject-1.2.9.2}/pyobject.egg-info/dependency_links.txt +0 -0
  43. {pyobject-1.2.9 → pyobject-1.2.9.2}/pyobject.egg-info/requires.txt +0 -0
  44. {pyobject-1.2.9 → pyobject-1.2.9.2}/pyobject.egg-info/top_level.txt +0 -0
  45. {pyobject-1.2.9 → pyobject-1.2.9.2}/setup.cfg +0 -0
  46. {pyobject-1.2.9 → pyobject-1.2.9.2}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pyobject
3
- Version: 1.2.9
3
+ Version: 1.2.9.2
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
@@ -351,7 +351,7 @@ Python内部的字节码对象\ ``CodeType``\ ,如\ ``func.__code__``\ ,是
351
351
  unused_var = func(temp_var)
352
352
 
353
353
  | 代码中\ ``temp_var``\ 只有一条指向\ ``unused_var``\ 的边,而\ ``unused_var``\ 没有任何指出的边。
354
- | 将\ ``temp_var``\ 的值代入\ ``func(temp_var)``\ 进行内联,并去掉\ ``unused_var``\ ,优化后的代码会变成\ ``func([1,2,3])``\ 。
354
+ | 将\ ``temp_var``\ 的值代入\ ``func(temp_var)``\ 进行内联,得到\ ``unused_var = func([1,2,3])``\ ,再去掉\ ``unused_var``\ ,优化后的代码会变成\ ``func([1,2,3])``\ 。
355
355
 
356
356
  模块\ ``pyobject.pyobj_extension``
357
357
  ----------------------------------
@@ -394,7 +394,7 @@ Python内部的字节码对象\ ``CodeType``\ ,如\ ``func.__code__``\ ,是
394
394
  lst调用多次==运算符(``__eq__``)相比,
395
395
  本函数直接比较对象的指针,提高了效率。
396
396
 
397
- **``pyobject``\ 当前版本**: 1.2.9
397
+ **``pyobject``\ 当前版本**: 1.2.9.2
398
398
 
399
399
  更新日志:
400
400
  ---------
@@ -829,9 +829,9 @@ Implementation Details
829
829
 
830
830
  | Here, ``temp_var`` only has one edge pointing to ``unused_var``, while
831
831
  ``unused_var`` does not point to any other node.
832
- | By inlining the value of ``temp_var`` into ``func(temp_var)`` and
833
- removing ``unused_var``, the optimized code becomes
834
- ``func([1, 2, 3])``.
832
+ | By inlining the value of ``temp_var`` into ``func(temp_var)``, the
833
+ code becomes ``unused_var = func([1,2,3])``. After removing
834
+ ``unused_var``, the optimized code is ``func([1, 2, 3])``.
835
835
 
836
836
  Module: ``pyobj_extension``
837
837
  ---------------------------
@@ -886,7 +886,7 @@ Python call “obj in lst” that invokes the “==” operator (``__eq__``)
886
886
  multiple times, this function directly compares the pointers to improve
887
887
  efficiency.
888
888
 
889
- **Current Version of ``pyobject``**: 1.2.9
889
+ **Current Version of ``pyobject``**: 1.2.9.2
890
890
 
891
891
  Change Log
892
892
  ----------
@@ -334,7 +334,7 @@ Python内部的字节码对象\ ``CodeType``\ ,如\ ``func.__code__``\ ,是
334
334
  unused_var = func(temp_var)
335
335
 
336
336
  | 代码中\ ``temp_var``\ 只有一条指向\ ``unused_var``\ 的边,而\ ``unused_var``\ 没有任何指出的边。
337
- | 将\ ``temp_var``\ 的值代入\ ``func(temp_var)``\ 进行内联,并去掉\ ``unused_var``\ ,优化后的代码会变成\ ``func([1,2,3])``\ 。
337
+ | 将\ ``temp_var``\ 的值代入\ ``func(temp_var)``\ 进行内联,得到\ ``unused_var = func([1,2,3])``\ ,再去掉\ ``unused_var``\ ,优化后的代码会变成\ ``func([1,2,3])``\ 。
338
338
 
339
339
  模块\ ``pyobject.pyobj_extension``
340
340
  ----------------------------------
@@ -377,7 +377,7 @@ Python内部的字节码对象\ ``CodeType``\ ,如\ ``func.__code__``\ ,是
377
377
  lst调用多次==运算符(``__eq__``)相比,
378
378
  本函数直接比较对象的指针,提高了效率。
379
379
 
380
- **``pyobject``\ 当前版本**: 1.2.9
380
+ **``pyobject``\ 当前版本**: 1.2.9.2
381
381
 
382
382
  更新日志:
383
383
  ---------
@@ -812,9 +812,9 @@ Implementation Details
812
812
 
813
813
  | Here, ``temp_var`` only has one edge pointing to ``unused_var``, while
814
814
  ``unused_var`` does not point to any other node.
815
- | By inlining the value of ``temp_var`` into ``func(temp_var)`` and
816
- removing ``unused_var``, the optimized code becomes
817
- ``func([1, 2, 3])``.
815
+ | By inlining the value of ``temp_var`` into ``func(temp_var)``, the
816
+ code becomes ``unused_var = func([1,2,3])``. After removing
817
+ ``unused_var``, the optimized code is ``func([1, 2, 3])``.
818
818
 
819
819
  Module: ``pyobj_extension``
820
820
  ---------------------------
@@ -869,7 +869,7 @@ Python call “obj in lst” that invokes the “==” operator (``__eq__``)
869
869
  multiple times, this function directly compares the pointers to improve
870
870
  efficiency.
871
871
 
872
- **Current Version of ``pyobject``**: 1.2.9
872
+ **Current Version of ``pyobject``**: 1.2.9.2
873
873
 
874
874
  Change Log
875
875
  ----------
@@ -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"
9
+ __version__="1.2.9.2"
10
10
 
11
11
  __all__=["objectname","bases","describe","desc"]
12
12
  _ignore_names=["__builtins__","__doc__"]
@@ -97,10 +97,10 @@ 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,accept_raw_obj
101
- __all__.extend(["DynObj","ObjChain","ProxiedObj","accept_raw_obj"])
100
+ from pyobject.objproxy import DynObj,ObjChain,ProxiedObj
101
+ __all__.extend(["DynObj","ObjChain","ProxiedObj"])
102
102
  except (ImportError, SyntaxError):
103
- warn("Failed to import pyobject.objproxy.") # SyntaxError: Python 3.5及以下不支持f-string
103
+ warn("Failed to import pyobject.objproxy.") # Python 3.5及以下不支持f-string,无法使用objproxy库
104
104
 
105
105
  def desc_demo():
106
106
  try:
@@ -19,28 +19,32 @@ INDENT = 4
19
19
  NOCODE_EXPORT_ATTRS = ["__class__","__dict__"] # 不留下代码记录的导出属性
20
20
  DEFAULT_EXPORT_FUNCS = [] # 在magic_meth_chained中自动生成
21
21
 
22
- def unproxy_obj(obj): # 递归解除obj的代理(备用函数)
23
- while isinstance(obj, ProxiedObj):
22
+ def unproxy_obj(obj):
23
+ if _isinstance(obj, ProxiedObj):
24
24
  obj = obj._ProxiedObj__target_obj
25
+ return obj
25
26
 
27
+ def unproxy_obj_recursive(obj): # 递归解除obj的代理(备用函数)
28
+ while _isinstance(obj, ProxiedObj):
29
+ obj = obj._ProxiedObj__target_obj
26
30
  # 递归处理容器
27
- if isinstance(obj, dict):
28
- return {unproxy_obj(k): unproxy_obj(v) for k, v in obj.items()}
29
- elif isinstance(obj, list):
30
- return [unproxy_obj(item) for item in obj]
31
- elif isinstance(obj, tuple):
32
- return tuple(unproxy_obj(item) for item in obj)
33
- elif isinstance(obj, set):
34
- return {unproxy_obj(item) for item in obj}
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}
35
40
  else:
36
41
  return obj
37
-
38
42
  def accept_raw_obj(func,process_arg=None,process_kw=None,process_ret=None):
39
43
  # 装饰器,用于有target_obj时只接受原始对象而不是ProxiedObj的函数(备用)
40
44
  @functools.wraps(func)
41
45
  def inner(*args,**kw):
42
- args = unproxy_obj(args)
43
- kw = unproxy_obj(kw)
46
+ args = unproxy_obj_recursive(args)
47
+ kw = unproxy_obj_recursive(kw)
44
48
 
45
49
  if process_arg is not None:
46
50
  args = process_arg(args)
@@ -56,9 +60,9 @@ def accept_raw_obj(func,process_arg=None,process_kw=None,process_ret=None):
56
60
  return result
57
61
  return inner
58
62
 
59
- class EmptyTarget:
63
+ class _EmptyTarget:
60
64
  def __bool__(self):return False
61
- EMPTY_OBJ = EmptyTarget() # 空对象的特殊值
65
+ EMPTY_OBJ = _EmptyTarget() # 空对象的特殊值
62
66
  class ReprFormatProxy:
63
67
  def __init__(self,target_obj,repr_func):
64
68
  self.target_obj = target_obj
@@ -77,7 +81,7 @@ def basic_repr(obj):
77
81
  return object.__repr__(obj)
78
82
 
79
83
  def is_trivial_obj(obj): # 检查对象能否被repr()表示(即对象必须是基本类型)
80
- if isinstance(obj, ProxiedObj):
84
+ if _isinstance(obj, ProxiedObj):
81
85
  obj = obj._ProxiedObj__target_obj
82
86
  if obj is EMPTY_OBJ:return True
83
87
  if type(obj) not in TRIVIAL_TYPES: # 不使用isinstance(由于不能是基本类型子类)
@@ -93,21 +97,39 @@ def is_builtin_type(cls): # 备用函数
93
97
  flag = get_type_flag(cls)
94
98
  if not flag & Py_TPFLAGS_HEAPTYPE or flag & _Py_TPFLAGS_STATIC_BUILTIN:
95
99
  return True
100
+ return False
96
101
  else:
97
102
  return True
98
103
  #if cls in vars(builtins).values() or cls in vars(types).values():
99
104
  # return True
100
105
  #return False
101
106
 
102
- def proxyCls(obj=None):
107
+ def proxyCls(T=_EmptyTarget, chain=EMPTY_OBJ, fromvar=None):
103
108
  # 泛型,proxyCls(T)生成类型信息为T的继承自ProxiedObj的类
104
- if obj is None:
109
+ if T is EMPTY_OBJ:
105
110
  return ProxiedObj
106
- if not isinstance(obj,type): # obj不是类
107
- T = type(obj)
108
- else:T = obj
109
- class ProxyCls(ProxiedObj): # 创建同时从ProxiedObj与target_obj继承的类
111
+
112
+ class ProxyCls(ProxiedObj): # 创建同时从ProxiedObj与T继承的类
113
+ # pylint: disable=unused-private-member
110
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)
111
133
 
112
134
  return ProxyCls
113
135
 
@@ -148,7 +170,7 @@ class ObjChain:
148
170
  # 自动检测依赖的变量,返回变量名的列表和未知对象的列表
149
171
  result = []; unknown = []
150
172
  for obj in itertools.chain(*iterables):
151
- if isinstance(obj,ProxiedObj):
173
+ if _isinstance(obj,ProxiedObj):
152
174
  self._assert_assoc_with(obj) # 确保关联到自身
153
175
  result.append(obj._ProxiedObj__name)
154
176
  elif id(obj) in self.exported_vars:
@@ -192,8 +214,8 @@ class ObjChain:
192
214
  else:
193
215
  exec(statement,self.scope)
194
216
  result = self.scope[name]
195
- return proxyCls(result)(self,name,target_obj=result,
196
- export_trivial_obj=export_trivial_obj)
217
+ return proxyCls(type(result),self,name)(self,name,result,
218
+ export_trivial_obj=export_trivial_obj)
197
219
  def add_existing_obj(self,obj,name,statement=None,dependency_vars=None,
198
220
  export_funcs=None,export_attrs=None,extra_info=None,
199
221
  export_trivial_obj=None,_export_call=False,
@@ -213,8 +235,8 @@ class ObjChain:
213
235
  self.custom_export_attr_check[name] = custom_export_attr
214
236
 
215
237
  self.add_code(statement,name,dependency_vars,**(extra_info or {}))
216
- self.scope[name] = proxyCls(obj)(self, name, _export_call, target_obj = obj,
217
- export_trivial_obj = export_trivial_obj)
238
+ self.scope[name] = proxyCls(type(obj),self,name)(self, name, obj, _export_call,
239
+ export_trivial_obj = export_trivial_obj)
218
240
  return self.scope[name]
219
241
  def add_exported_obj(self,obj,name): # 添加已导出的对象,仅更新exported_vars
220
242
  self.exported_vars[id(obj)] = name
@@ -232,7 +254,7 @@ class ObjChain:
232
254
  if obj._ProxiedObj__chain is not self:
233
255
  raise ValueError("chain.get_repr(obj): obj is not associated with this chain")
234
256
  def get_target(self,obj): # 获取ProxiedObj的目标对象
235
- if not isinstance(obj,ProxiedObj):
257
+ if not _isinstance(obj,ProxiedObj):
236
258
  raise TypeError("obj should be an instance of ProxiedObj")
237
259
  self._assert_assoc_with(obj)
238
260
  target = obj._ProxiedObj__target_obj
@@ -258,7 +280,7 @@ class ObjChain:
258
280
  return varname
259
281
  num += 1
260
282
  def get_repr(self,obj): # 用于代码生成中的repr,如果对象是ProxiedObj,则直接返回对应的变量名
261
- if isinstance(obj,ProxiedObj):
283
+ if _isinstance(obj,ProxiedObj):
262
284
  self._assert_assoc_with(obj)
263
285
  return obj._ProxiedObj__name
264
286
  else:
@@ -355,7 +377,7 @@ class ObjChain:
355
377
  if export or use_exported_obj: # use_exported_obj: 是否在不导出时也在exec用target_obj作为变量,避免递归
356
378
  scope = {}
357
379
  for var in self.code_vars[cur_idx][1]: # 导出时,不使用ProxiedObj执行,避免递归
358
- if isinstance(self.scope[var],ProxiedObj):
380
+ if _isinstance(self.scope[var],ProxiedObj):
359
381
  self._assert_assoc_with(self.scope[var])
360
382
  scope[var] = self.scope[var]._ProxiedObj__target_obj
361
383
  else:
@@ -443,8 +465,8 @@ def magic_meth_chained(fmt = None, use_newvar = True, indent_delta = 0,
443
465
  result = chain.eval_value(new_var) # 逐行一次性执行代码,并返回结果
444
466
  return result
445
467
  if use_newvar:
446
- return proxyCls(result)(chain,new_var,target_obj=result,
447
- export_trivial_obj=self._ProxiedObj__export_trivial_obj)
468
+ return proxyCls(type(result),self._ProxiedObj__chain,new_var)(chain,new_var,
469
+ result,export_trivial_obj=self._ProxiedObj__export_trivial_obj)
448
470
  return self
449
471
 
450
472
  return override
@@ -454,10 +476,12 @@ class ProxiedObj:
454
476
  # 代理其他对象的类(建议使用ObjChain的new_object和add_existing_obj方法,而不是实例化本类)
455
477
  # 如果有target_obj,则内部应使用泛型proxyCls(T)替代ProxiedObj类,
456
478
  # 避免isinstance检测返回False
457
- def __init__(self,chain,name,_export_call=False,
458
- target_obj=EMPTY_OBJ,export_trivial_obj=False):
479
+ def __init__(self,chain,name,target_obj=EMPTY_OBJ,
480
+ _export_call=False,export_trivial_obj=False):
459
481
  # target_obj: 要操作(代理)的目标对象,可选
460
482
  # _export_call: 当前对象的__call__是否会导出真正的结果(而不是下一个ProxiedObj)
483
+ if "_ProxiedObj__chain" in object.__getattribute__(self,"__dict__"):
484
+ return # 已经初始化过
461
485
  self.__chain=chain
462
486
  self.__name=name
463
487
  self.__export_call=_export_call
@@ -472,6 +496,7 @@ class ProxiedObj:
472
496
  self.__chain.proxies[id(target_obj)] = self
473
497
 
474
498
  self.__export_trivial_obj=export_trivial_obj
499
+ # pylint: disable=unused-private-member
475
500
  self.__no_self_attr = True # 不再使用自身的属性
476
501
  def __call__(self,*args,**kw):
477
502
  depend_vars = self.__chain._detect_var_and_add_obj((self,), args, kw.values())
@@ -490,8 +515,7 @@ class ProxiedObj:
490
515
  return self.__target_obj(*args,**kw)
491
516
  else:
492
517
  return self.__target_obj(*args) # 避免对不接收关键字参数的函数传递关键字
493
- result = self.__chain._get_new_targetobj(self.__target_obj,new_var,_getter,
494
- use_exported_obj=True)
518
+ result = self.__chain._get_new_targetobj(self.__target_obj,new_var,_getter)
495
519
 
496
520
  if self.__export_call or (self.__export_trivial_obj
497
521
  and is_trivial_obj(result)):
@@ -506,9 +530,8 @@ class ProxiedObj:
506
530
  if self.__name in self.__chain.export_funcs:
507
531
  self.__chain.export_funcs[new_var] = self.__chain.\
508
532
  export_funcs[self.__name].copy()
509
- return proxyCls(result)(self.__chain,new_var,
510
- target_obj=result,
511
- export_trivial_obj=self.__export_trivial_obj)
533
+ return proxyCls(type(result),self.__chain,self.__name)(self.__chain,new_var,
534
+ result,export_trivial_obj=self.__export_trivial_obj)
512
535
 
513
536
  #@magic_meth_chained("{_var} = {_self}.{}")
514
537
  def __getattr__(self,attr):
@@ -537,9 +560,10 @@ class ProxiedObj:
537
560
  else:
538
561
  self.__chain.update_exports(self.__name, attr, new_var)
539
562
 
540
- return proxyCls(result)(self.__chain,new_var,
541
- self.__chain.is_export_func(attr,self.__name),
542
- result,self.__export_trivial_obj)
563
+ return proxyCls(type(result),self.__chain,self.__name)(
564
+ self.__chain,new_var,result,
565
+ self.__chain.is_export_func(attr,self.__name),
566
+ self.__export_trivial_obj)
543
567
  @magic_meth_chained("{_var} = str({_self})",export=True)
544
568
  def __str__(self): pass
545
569
  @magic_meth_chained("{_var} = repr({_self})",export=True)
@@ -561,6 +585,16 @@ class ProxiedObj:
561
585
  and not attr.startswith("_ProxiedObj"):
562
586
  raise AttributeError # 改用__getattr__
563
587
  return result
588
+ def __new__(cls,*args,**kw):
589
+ if len(args) >= 3:
590
+ target_obj = args[2]
591
+ elif "target_obj" in kw:
592
+ target_obj = kw["target_obj"]
593
+ else:
594
+ target_obj = EMPTY_OBJ
595
+ if _isinstance(target_obj, ProxiedObj):
596
+ return target_obj # 避免重复包装对象,提高性能
597
+ return object.__new__(cls)
564
598
 
565
599
  # 算术运算符
566
600
  @magic_meth_chained("{_var} = {_self} + {!r}")
@@ -712,7 +746,8 @@ class ProxiedObj:
712
746
  @magic_meth_chained(default_fmt=True,export=True)
713
747
  def __fspath__(self):pass
714
748
 
715
- from pyobject.objproxy.builtin_hook import hook_builtins
749
+ _isinstance = isinstance
750
+ from pyobject.objproxy.builtin_hook import hook_builtins # pylint: disable=ungrouped-imports
716
751
  hook_builtins() # hook内置函数
717
752
 
718
753
  def proxy_demo():
@@ -1,5 +1,5 @@
1
- # 内置函数和少数标准库函数的hook
2
- import builtins,_collections_abc
1
+ # 内置函数和部分标准库函数的hook
2
+ import sys,builtins,_collections_abc,inspect
3
3
  import collections.abc as collections_abc
4
4
  from pyobject.objproxy import ProxiedObj,accept_raw_obj
5
5
 
@@ -14,7 +14,7 @@ def __build_class__(func, cls_name, *bases, metaclass=None, **kwds):
14
14
  chain = None
15
15
  dependency = []
16
16
  for i, cls in enumerate(bases):
17
- if isinstance(cls, ProxiedObj):
17
+ if _isinstance(cls, ProxiedObj):
18
18
  bases[i] = cls._ProxiedObj__target_obj
19
19
  if chain is not None and cls._ProxiedObj__chain is not chain:
20
20
  raise ValueError("base classes should be associated with the same chain")
@@ -40,7 +40,7 @@ _getattr = getattr
40
40
  def isinstance(obj, class_or_tuple):
41
41
  if _isinstance(class_or_tuple, ProxiedObj):
42
42
  class_or_tuple = class_or_tuple._ProxiedObj__target_obj
43
- if _isinstance(class_or_tuple, tuple):
43
+ elif _isinstance(class_or_tuple, tuple):
44
44
  class_or_tuple = tuple(cls._ProxiedObj__target_obj \
45
45
  if _isinstance(cls, ProxiedObj) else cls \
46
46
  for cls in class_or_tuple)
@@ -52,6 +52,8 @@ def isinstance(obj, class_or_tuple):
52
52
  return _isinstance(obj, class_or_tuple) # 重新调用_isinstance
53
53
  return result
54
54
  def issubclass(cls, class_or_tuple):
55
+ if _isinstance(cls, ProxiedObj):
56
+ cls = cls._ProxiedObj__target_obj
55
57
  if _isinstance(class_or_tuple, ProxiedObj):
56
58
  class_or_tuple = class_or_tuple._ProxiedObj__target_obj
57
59
  if _issubclass(cls, ProxiedObj):
@@ -64,9 +66,9 @@ def callable(obj):
64
66
  obj = obj._ProxiedObj__target_obj
65
67
  return _callable(obj)
66
68
  def getattr(*args,**kw):
67
- if isinstance(args[1],ProxiedObj):
69
+ if _isinstance(args[1],ProxiedObj):
68
70
  args = (args[0], args[1]._ProxiedObj__target_obj, *args[2:])
69
- if "name" in kw and isinstance(kw["name"],ProxiedObj):
71
+ if "name" in kw and _isinstance(kw["name"],ProxiedObj):
70
72
  kw["name"] = kw["name"]._ProxiedObj__target_obj
71
73
  return _getattr(*args)
72
74
 
@@ -79,6 +81,51 @@ def _check_methods(Cls, *methods):
79
81
  return _pre_check_methods(object,*methods) # ProxiedObj继承自object
80
82
  return _pre_check_methods(Cls,*methods)
81
83
 
84
+ _super=builtins.super
85
+ class super(_super):
86
+ def __init__(self,*args):
87
+ # 模拟CPython typeobject.c中super()的行为
88
+ if not args:
89
+ frame = getattr(sys._getframe(),"f_back",None)
90
+ if frame is None:
91
+ raise RuntimeError("super(): no current frame")
92
+ code = frame.f_code
93
+ if code is None:
94
+ raise RuntimeError("super(): no code object")
95
+ if code.co_argcount == 0:
96
+ raise RuntimeError("super(): no arguments")
97
+ try:
98
+ self_ = frame.f_locals[code.co_varnames[0]]
99
+ except (IndexError, KeyError):
100
+ raise RuntimeError("super(): arg[0] deleted") from None
101
+ if "__class__" not in frame.f_locals:
102
+ raise RuntimeError("super(): bad __class__ cell")
103
+ cls = frame.f_locals["__class__"]
104
+ if not isinstance(cls, type):
105
+ raise RuntimeError("super(): __class__ is not a type (%s)" \
106
+ % type(cls).__name__)
107
+ args = (cls, self_)
108
+ args = tuple(item._ProxiedObj__target_obj if _issubclass(
109
+ object.__getattribute__(item,"__class__"),
110
+ ProxiedObj) else item for item in args) # 确保不为ProxiedObj
111
+ _super.__init__(self,*args)
112
+
113
+ _signature = inspect.signature
114
+ _getattr_static = inspect.getattr_static
115
+ def signature(obj, **kw):
116
+ if _isinstance(obj, ProxiedObj):
117
+ obj = obj._ProxiedObj__target_obj
118
+ return _signature(obj, **kw)
119
+ def getattr_static(obj, attr, *args, **kw):
120
+ if _isinstance(obj, ProxiedObj):
121
+ obj = obj._ProxiedObj__target_obj
122
+ if _isinstance(attr, ProxiedObj):
123
+ attr = attr._ProxiedObj__target_obj
124
+ if kw:
125
+ return _getattr_static(obj, attr, *args, **kw)
126
+ else:
127
+ return _getattr_static(obj, attr, *args)
128
+
82
129
  def hook_builtins():
83
130
  builtins.range=range
84
131
  builtins.__build_class__ = __build_class__
@@ -86,8 +133,11 @@ def hook_builtins():
86
133
  builtins.issubclass = issubclass
87
134
  builtins.callable = callable
88
135
  builtins.getattr = getattr
136
+ builtins.super = super
89
137
  _collections_abc._check_methods = _check_methods # 修改collections.abc库
90
138
  collections_abc._check_methods = _check_methods
139
+ inspect.signature = signature
140
+ inspect.getattr_static = getattr_static
91
141
 
92
142
  # 内置类型的修改(备用)
93
143
  class CustomStr(builtins.str):
@@ -82,7 +82,7 @@ def ck(obj,symbol):
82
82
  def magic_meth(meth): # 用于无法获知具体表达式的魔法方法调用(备用函数)
83
83
  @functools.wraps(meth)
84
84
  def override(self,*args,**kw):
85
- return DynObj(f"{ck(self)}.{meth.__name__}") # 优先级使用默认的HIGHEST
85
+ return DynObj(f"{ck(self, HIGHEST)}.{meth.__name__}") # 优先级使用默认的HIGHEST
86
86
  return override
87
87
 
88
88
  # 能包装表达式链式求值的对象(不可变)
@@ -111,9 +111,9 @@ class DynObj:
111
111
  return self.__code
112
112
 
113
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)
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
117
  def __truediv__(self, other):
118
118
  return DynObj(f"{ck(self, DIV)} / {ck(other, DIV)}", DIV)
119
119
  def __floordiv__(self, other):
@@ -4,10 +4,10 @@ from pyobject.objproxy.utils import *
4
4
  MERGABLE_INFO = ["_alias_name"]
5
5
 
6
6
  class Statement: # 图节点(一条语句)
7
- def __init__(self,graph,code,var,dependency_vars,extra_info=None):
7
+ def __init__(self,graph,code,varname,dependency_vars,extra_info=None):
8
8
  self.graph = graph
9
9
  self.code = code
10
- self.var = var
10
+ self.var = varname
11
11
  self.extra_info = extra_info or {}
12
12
  self.removed = False
13
13
  self.depends = set()
@@ -39,7 +39,8 @@ class Statement: # 图节点(一条语句)
39
39
  self.var = None
40
40
  except NotAssignmentError:pass # 不是赋值语句
41
41
  if remove_internal and self.extra_info.get("_internal",False)\
42
- or remove_export_type and self.extra_info.get("_export_type",False):
42
+ or remove_export_type and self.extra_info.get("_export_type",False)\
43
+ or self.extra_info.get("_optional_stat",False):
43
44
  for dep in self.depends:
44
45
  dep.affects.remove(self)
45
46
  dep.affects_cnt -= 1
@@ -100,7 +101,7 @@ def import_optimizer(graph):
100
101
  try:
101
102
  stat.code = optimize_import(stat.code)
102
103
  except NotAnImportError:pass
103
-
104
+
104
105
  graph.clear_removed_statements()
105
106
 
106
107
  def import_alias_optimizer(graph):
@@ -153,4 +154,4 @@ unused_var = submod.func(temp_var)"""
153
154
  [("submod",[]),("temp_var",[]),
154
155
  ("unused_var",["submod","temp_var"])]), sep="")
155
156
 
156
- if __name__=="__main__":test()
157
+ if __name__=="__main__":test()
@@ -109,4 +109,4 @@ def optimize_import(source):
109
109
 
110
110
  # 构建导入语句
111
111
  alias = assign_node.targets[0].id
112
- return f"import {module_name} as {alias}"
112
+ return f"import {module_name} as {alias}"
@@ -73,7 +73,7 @@ PyDoc_STRVAR(setrefcount_nogil_doc, u8"setrefcount_nogil(obj,ref_data)\n"
73
73
  #define _PY312P /* 3.12+所有版本 */
74
74
  #endif
75
75
 
76
- // 临时在posix禁用python 3.12+特性
76
+ // TODO: 临时在posix禁用python 3.12+特性
77
77
  #ifndef _WIN32
78
78
  #ifdef _PY312
79
79
  #undef _PY312
@@ -62,7 +62,7 @@ class TestObjChain(unittest.TestCase):
62
62
  class Cls2:pass
63
63
  chain = ObjChain()
64
64
  obj = chain.add_existing_obj(Cls(),"obj")
65
- self.assertTrue(issubclass(type(obj), Cls)) # 有pyobj_extension模块时测试才成功
65
+ self.assertTrue(issubclass(type(obj), Cls))
66
66
  self.assertFalse(issubclass(type(obj), Cls2))
67
67
  self.assertTrue(isinstance(obj, Cls))
68
68
  self.assertFalse(isinstance(obj, Cls2))
@@ -0,0 +1,49 @@
1
+ from time import perf_counter
2
+ import random
3
+ try:
4
+ from pyobject import ObjChain, ProxiedObj
5
+ except ImportError:
6
+ path = __file__
7
+ for i in range(3):
8
+ path = os.path.split(path)[0]
9
+ sys.path.append(path) # 加入当前pyobject库所在的目录
10
+ from pyobject import ObjChain, ProxiedObj
11
+
12
+ REPEAT_TIMES = 20000
13
+
14
+ def test_perf(use_objchain=True):
15
+ chain = ObjChain(export_trivial_obj=False)
16
+ class Cls:
17
+ def __init__(self, value=None):
18
+ self.attr = value
19
+ def meth(self):
20
+ return self.attr
21
+ __call__ = meth
22
+ def __add__(self, other):
23
+ return Cls(other)
24
+
25
+ if use_objchain:
26
+ Cls = chain.add_existing_obj(Cls,"Cls")
27
+
28
+ obj1, obj2 = Cls(1), Cls(42)
29
+ obj1.attr, obj2.attr = obj2, obj1
30
+ start = perf_counter()
31
+ for _ in range(REPEAT_TIMES):
32
+ op = random.randint(0,3)
33
+ if op == 0:
34
+ new_obj = obj1 + obj2
35
+ obj1, obj2 = obj2, new_obj
36
+ elif op == 1:
37
+ new_obj = obj1.attr
38
+ obj1, obj2 = obj2, new_obj
39
+ elif op == 2:
40
+ new_obj = obj1() #obj1.meth()
41
+ obj1, obj2 = obj2, new_obj
42
+ elif op == 3:
43
+ obj1.attr = obj1
44
+ print(f"use_objchain={use_objchain}: {perf_counter()-start:.9f}s")
45
+
46
+ if __name__=="__main__":
47
+ print(f"REPEAT_TIMES={REPEAT_TIMES}")
48
+ test_perf(True)
49
+ test_perf(False)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pyobject
3
- Version: 1.2.9
3
+ Version: 1.2.9.2
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
@@ -351,7 +351,7 @@ Python内部的字节码对象\ ``CodeType``\ ,如\ ``func.__code__``\ ,是
351
351
  unused_var = func(temp_var)
352
352
 
353
353
  | 代码中\ ``temp_var``\ 只有一条指向\ ``unused_var``\ 的边,而\ ``unused_var``\ 没有任何指出的边。
354
- | 将\ ``temp_var``\ 的值代入\ ``func(temp_var)``\ 进行内联,并去掉\ ``unused_var``\ ,优化后的代码会变成\ ``func([1,2,3])``\ 。
354
+ | 将\ ``temp_var``\ 的值代入\ ``func(temp_var)``\ 进行内联,得到\ ``unused_var = func([1,2,3])``\ ,再去掉\ ``unused_var``\ ,优化后的代码会变成\ ``func([1,2,3])``\ 。
355
355
 
356
356
  模块\ ``pyobject.pyobj_extension``
357
357
  ----------------------------------
@@ -394,7 +394,7 @@ Python内部的字节码对象\ ``CodeType``\ ,如\ ``func.__code__``\ ,是
394
394
  lst调用多次==运算符(``__eq__``)相比,
395
395
  本函数直接比较对象的指针,提高了效率。
396
396
 
397
- **``pyobject``\ 当前版本**: 1.2.9
397
+ **``pyobject``\ 当前版本**: 1.2.9.2
398
398
 
399
399
  更新日志:
400
400
  ---------
@@ -829,9 +829,9 @@ Implementation Details
829
829
 
830
830
  | Here, ``temp_var`` only has one edge pointing to ``unused_var``, while
831
831
  ``unused_var`` does not point to any other node.
832
- | By inlining the value of ``temp_var`` into ``func(temp_var)`` and
833
- removing ``unused_var``, the optimized code becomes
834
- ``func([1, 2, 3])``.
832
+ | By inlining the value of ``temp_var`` into ``func(temp_var)``, the
833
+ code becomes ``unused_var = func([1,2,3])``. After removing
834
+ ``unused_var``, the optimized code is ``func([1, 2, 3])``.
835
835
 
836
836
  Module: ``pyobj_extension``
837
837
  ---------------------------
@@ -886,7 +886,7 @@ Python call “obj in lst” that invokes the “==” operator (``__eq__``)
886
886
  multiple times, this function directly compares the pointers to improve
887
887
  efficiency.
888
888
 
889
- **Current Version of ``pyobject``**: 1.2.9
889
+ **Current Version of ``pyobject``**: 1.2.9.2
890
890
 
891
891
  Change Log
892
892
  ----------
@@ -40,4 +40,5 @@ pyobject/objproxy/optimize.py
40
40
  pyobject/objproxy/utils.py
41
41
  pyobject/other/browser_chs_locale.py
42
42
  pyobject/tests/test_code.py
43
- pyobject/tests/test_objproxy.py
43
+ pyobject/tests/test_objproxy.py
44
+ pyobject/tests/test_objproxy_perf.py
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes