英文:
Apply an additional function to direct instance methods
问题
以下是您要翻译的代码段:
假设我有一些类:
class MyBaseClass:
def method1(self):
print('Hello 1')
class MyClass2:
def __init__(self, inp):
self.old_class = inp
def __getattr__(self, item):
if hasattr(self, item):
print('Hello!')
return getattr(self, item)
else:
return getattr(self.old_class, item)
def method2(self):
print('Hello 2')
我想要做的是,在直接作为该类的一部分定义的方法被调用时打印“Hello”。例如:
MyBaseClass().method1()
'Hello 1'
MyClass2(MyBaseClass()).method1()
'Hello 1'
MyClass2(MyBaseClass()).method2()
'Hello!'
'Hello 2'
我也意识到我的问题是__getattr__
只有在__getattribute__
失败时才会被调用。我的问题要么是:
- 如何定义
__getattribute__
以实现这一点,而不会遇到递归错误。
或者 2) 有没有其他东西可以替代__getattribute__
来实现这一点。
我不想在MyClass2中定义的方法中添加print('Hello!')
(例如,我想要一种可以推广到多个方法而不是在每个方法中都加入print('Hello!')
的方法)。
英文:
Suppose I have a couple of classes:
class MyBaseClass:
def method1(self):
print('Hello 1')
class MyClass2:
def __init__(self, inp):
self.old_class = inp
def __getattr__(self, item):
if hasattr(self, item):
print('Hello!')
return getattr(self,item)
else:
return getattr(self.old_class, item)
def method2(self):
print('Hello 2')
What I want to do is print "Hello" when the method called is defined directly as part of that class. For example:
MyBaseClass().method1()
'Hello 1'
MyClass2(MyBaseClass()).method1()
'Hello 1'
MyClass2(MyBaseClass()).method2()
'Hello!'
'Hello 2'
I am also aware that my issue is that __getattr__
isn't called unless __getattribute__
fails. My question is either:
- How can I define
__getattribute__
to achieve this without running into recursion errors.
or 2) Is there something I can use instead of __getattribute__
to achieve this.
I don't want to add print('Hello!')
to the method defined in MyClass2 (e.g. I would like something that generalises to multiple methods without putting print('Hello!')
inside each of them.
答案1
得分: 1
Sounds like your code design/architecture is not so smart as it may be.
class Base:
def base_method(self):
print("base")
class Sub(Base)
pass
# 将打印 `base`
Sub().base_method()
如果你想动态地为新类分配新方法,可以使用type
:
class A:
pass
def extra_method(self):
print(self)
B = type("B", (A,), {"extra_method": extra_method})
# 将打印 `<__main__.B object at 0x7f0924521630>`
B().extra_method()
但假设你完全理解你想要实现的内容,代码设计的方式在你的问题中是一种可能的正确方式。
在这种情况下,你需要实现__getattribute__
,如下所示:
class MyBaseClass:
def method1(self):
print('Hello 1')
class MyClass2:
def __init__(self, inp):
self.old_class = inp
# 只有在要调用未在类内定义的属性时才会使用`__getattr__`(在你的情况下是`method1`)
# 但是你希望在调用现有属性(`method2`)时打印`Hello!`,因此应该使用`__getattribute__`
# `__getattribute__`将在任何情况下都会被调用
def __getattribute__(self, item):
# 这里为什么要调用`super()`?
# 如果我们在当前类中调用`__getattribute__`,那么它会调用`__getattribute__`,然后再次调用`__getattribute__`
# ...再次无限递归
# 因此,我们可以使用父类的默认`__getattribute__`方法(父类是`object`)来避免递归
my_attr = super().__getattribute__(item)
# 为什么需要这个`if`?
# 当我们在异常情况下调用`self.old_class()`时
# 会再次在底层调用`__getattribute__`,因为`old_class`是`self`的属性
# 我们不希望每次调用`old_class`时都打印`Hello!`,对吗?
# 这就是这个`if`的目的
if item != 'old_class':
print('Hello!')
# 最后,如果存在所需的属性,就返回它
return my_attr
def method2(self):
print('Hello 2')
英文:
Sounds like your code design/architecture is not so smart as it may be.
Usually inheritance and mixins are using to extend classes:
class Base:
def base_method(self):
print("base")
class Sub(Base)
pass
# will print `base`
Sub().base_method()
If you want to assign new methods to new classes dynamically you may use type
:
class A:
pass
def extra_method(self):
print(self)
B = type("B", (A,), {"extra_method": extra_method})
# will print <__main__.B object at 0x7f0924521630>
B().extra_method()
But let's suppose that you are completelly understanding what you want to implement and design of code in your question is one possible correct way.
In this case you have to implement __getattribute__
like:
class MyBaseClass:
def method1(self):
print('Hello 1')
class MyClass2:
def __init__(self, inp):
self.old_class = inp
# `__getattr__` is using only when you want to call attribute that is not defined inside the class (`method1` in your case)
# however you want to print `Hello!` on calling existant attribute (`method2`) so `__getattribute__` should be used
# `__getattribute__` will be called in any case
def __getattribute__(self, item):
# hasattr can't be used here
# because hasattr is using `__getattribute__` under the hood
# and `__getattribute__` is calling `hasattr` that is using `__getattribute__`
# ...endless recursion
# to solve this problem we may try to assign method to variable without checking is it exists or not
# if it not exists internal method will be assigned
# if not - AttributeError will be raised and method of another class will be called
try:
# why we call `super()` here?
# if we call `__getattribute__` of current class that is calling `__getattribute__` that is calling `__getattribute__`
# ... endless recursion again
# So we may use default `__getattribute__` method of parent class (and parent class is `object`) to be able avoid recursion
my_attr = super().__getattribute__(item)
except AttributeError:
# in other way default `__getattribute__` of `old_class`s instance will be called
# that is simple
return self.old_class().__getattribute__(item)
# why we need this `if`?
# when we calling `self.old_class()` on exception
# `__getattribute__` is calling under the hood again because `old_class` is an attribute of `self`
# we don't need to print `Hello!` every time when `old_class` is called, right?
# and that is purpose of this `if`
if item != 'old_class':
print('Hello!')
# finally return desired attribute if it exists
return my_attr
def method2(self):
print('Hello 2')
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论