- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我想了解 Python 类和对象的工作原理。在 Perl 中它非常简单,在 package
中定义的每个 sub
都可以作为静态、类或对象方法调用(CLASS::func
, CLASS->func
或 $obj->func
)。乍一看,Python 类看起来像带有 bless
哈希(Python 类中的 __dict__
属性)的 Perl 类。但是在 Python 中我有点困惑。因此,为了更好地理解,我尝试猴子修补一个空类,添加 3 个行为与静态、类和对象方法完全一样的属性,但我无法得到它。
首先我创建了普通类来获取基本结果:
def say(msg, x):
print('*', msg, 'x =', x, 'type(x) =', type(x))
class A():
@staticmethod
def stt_m(x):
say('stt_m', x)
@classmethod
def cls_m(x):
say('cls_m', x)
def obj_m(x):
say('obj_m', x)
然后我创建了一个函数(称为 test
),它尝试使用一个参数调用所有方法,如果失败(因为第一个参数可以是类或对象本身),则尝试再次调用none 在输出行前面打印一个“X”,然后打印检测到的类型:
def test(obj):
# Detect if obj is a class or an instantiated object
what = 'Class' if type(obj) == type else 'Object'
print()
# Try to call static, class and object method getting attributes
for a in ('stt_m', 'cls_m', 'obj_m'):
meth = getattr(obj, a)
try:
meth(111)
except:
print('X', end='')
meth()
print(' ', what, a, meth)
使用默认的 A
类及其对象调用 test
:
test(A)
test(A())
结果是:
* stt_m x = 111 type(x) = <class 'int'>
Class stt_m <function A.stt_m at 0x7fb37e63c8c8>
X* cls_m x = <class '__main__.A'> type(x) = <class 'type'>
Class cls_m <bound method A.cls_m of <class '__main__.A'>>
* obj_m x = 111 type(x) = <class 'int'>
Class obj_m <function A.obj_m at 0x7fb37e63c9d8>
* stt_m x = 111 type(x) = <class 'int'>
Object stt_m <function A.stt_m at 0x7fb37e63c8c8>
X* cls_m x = <class '__main__.A'> type(x) = <class 'type'>
Object cls_m <bound method A.cls_m of <class '__main__.A'>>
X* obj_m x = <__main__.A object at 0x7fb37e871748> type(x) = <class '__main__.A'>
Object obj_m <bound method A.obj_m of <__main__.A object at 0x7fb37e871748>>
因此,使用类或对象前缀调用 staticmethod
,它们的行为与普通(命名空间)函数一样(接受 1 个参数)。无论使用哪种方式调用 classmethod
,传递的第一个参数都是类对象。从类调用 objectmethod
的行为与普通函数一样,如果从对象调用,则第一个参数是对象本身。这后来看起来有点奇怪,但我可以接受。
现在,让我们尝试猴子修补一个空类:
class B():
pass
B.stt_m = lambda x: say('stt_m', x)
B.cls_m = types.MethodType(lambda x: say('cls_m', x), B)
B.obj_m = types.MethodType(lambda x: say('obj_m', x), B())
test(B)
test(B())
结果是:
* stt_m x = 111 type(x) = <class 'int'>
Class stt_m <function <lambda> at 0x7fbf05ec7840>
X* cls_m x = <class '__main__.B'> type(x) = <class 'type'>
Class cls_m <bound method <lambda> of <class '__main__.B'>>
X* obj_m x = <__main__.B object at 0x7fbf0d7dd978> type(x) = <class '__main__.B'>
Class obj_m <bound method <lambda> of <__main__.B object at 0x7fbf0d7dd978>>
X* stt_m x = <__main__.B object at 0x7fbf06375e80> type(x) = <class '__main__.B'>
Object stt_m <bound method <lambda> of <__main__.B object at 0x7fbf06375e80>>
X* cls_m x = <class '__main__.B'> type(x) = <class 'type'>
Object cls_m <bound method <lambda> of <class '__main__.B'>>
X* obj_m x = <__main__.B object at 0x7fbf0d7dd978> type(x) = <class '__main__.B'>
Object obj_m <bound method <lambda> of <__main__.B object at 0x7fbf0d7dd978>>
根据这种模式,stt_m
的行为类似于普通类的对象方法,cls_m
和 obj_m
的行为类似于普通类的类方法普通类。
我可以用这种方式对静态方法进行猴子修补吗?
最佳答案
您可以将方法猴子修补到一个类上,但它是这样完成的:
B.stt_m = staticmethod(lambda x: say('stt_m', x))
B.cls_m = classmethod(lambda x: say('cls_m', x))
B.obj_m = lambda x: say('obj_m', x)
您的 B.cls_m
版本没问题,但是您的 B.stt_m
创建了一个普通方法,而您的 B.obj_m
附加了一个新创建的 B()
的实例方法,但是 B()
被丢弃了,你测试一个新的 B()
没有额外的方法。
在 Python 中通常不需要使用 types.MethodType
:
types.MethodType(function, object_)
相当于
function.__get__(object_)
虽然也很少见,但要好一些。
此外(无关紧要但更简洁),在新版本的 Python 中,您的
print('*', msg, 'x =', x, 'type(x) =', type(x))
可以写成
print(f"* {msg} {x = } {type(x) = }")
关于python-3.x - Monkeypatching 一个 Python 类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71197957/
问题故障解决记录 -- Java RMI Connection refused to host: x.x.x.x .... 在学习JavaRMI时,我遇到了以下情况 问题原因:可
我正在玩 Rank-N-type 并尝试输入 x x .但我发现这两个函数可以以相同的方式输入,这很不直观。 f :: (forall a b. a -> b) -> c f x = x x g ::
这个问题已经有答案了: How do you compare two version Strings in Java? (31 个回答) 已关闭 8 年前。 有谁知道如何在Java中比较两个版本字符串
这个问题已经有答案了: How do the post increment (i++) and pre increment (++i) operators work in Java? (14 个回答)
下面是带有 -n 和 -r 选项的 netstat 命令的输出,其中目标字段显示压缩地址 (127.1/16)。我想知道 netstat 命令是否有任何方法或选项可以显示整个目标 IP (127.1.
我知道要证明 : (¬ ∀ x, p x) → (∃ x, ¬ p x) 证明是: theorem : (¬ ∀ x, p x) → (∃ x, ¬ p x) := begin intro n
x * x 如何通过将其存储在“auto 变量”中来更改?我认为它应该仍然是相同的,并且我的测试表明类型、大小和值显然都是相同的。 但即使 x * x == (xx = x * x) 也是错误的。什么
假设,我们这样表达: someIQueryable.Where(x => x.SomeBoolProperty) someIQueryable.Where(x => !x.SomeBoolProper
我有一个字符串 1234X5678 我使用这个正则表达式来匹配模式 .X|..X|X. 我得到了 34X 问题是为什么我没有得到 4X 或 X5? 为什么正则表达式选择执行第二种模式? 最佳答案 这里
我的一个 friend 在面试时遇到了这个问题 找到使该函数返回真值的 x 值 function f(x) { return (x++ !== x) && (x++ === x); } 面试官
这个问题在这里已经有了答案: 10年前关闭。 Possible Duplicate: Isn't it easier to work with foo when it is represented b
我是 android 的新手,我一直在练习开发一个针对 2.2 版本的应用程序,我需要帮助了解如何将我的应用程序扩展到其他版本,即 1.x、2.3.x、3 .x 和 4.x.x,以及一些针对屏幕分辨率
为什么案例 1 给我们 :error: TypeError: x is undefined on line... //case 1 var x; x.push(x); console.log(x);
代码优先: # CASE 01 def test1(x): x += x print x l = [100] test1(l) print l CASE01 输出: [100, 100
我正在努力温习我的大计算。如果我有将所有项目移至 'i' 2 个空格右侧的函数,我有一个如下所示的公式: (n -1) + (n - 2) + (n - 3) ... (n - n) 第一次迭代我必须
给定 IP 字符串(如 x.x.x.x/x),我如何或将如何计算 IP 的范围最常见的情况可能是 198.162.1.1/24但可以是任何东西,因为法律允许的任何东西。 我要带198.162.1.1/
在我作为初学者努力编写干净的 Javascript 代码时,我最近阅读了 this article当我偶然发现这一段时,关于 JavaScript 中的命名空间: The code at the ve
我正在编写一个脚本,我希望避免污染 DOM 的其余部分,它将是一个用于收集一些基本访问者分析数据的第 3 方脚本。 我通常使用以下内容创建一个伪“命名空间”: var x = x || {}; 我正在
我尝试运行我的test_container_services.py套件,但遇到了以下问题: docker.errors.APIError:500服务器错误:内部服务器错误(“ b'{” message
是否存在这两个 if 语句会产生不同结果的情况? if(x as X != null) { // Do something } if(x is X) { // Do something } 编
我是一名优秀的程序员,十分优秀!