让我们在Python中有一个示例类Foo:
class Foo:
bar = 'bar'
def access_bar(self):
return self.bar
例如,当我直接访问Foo().bar
时,是否可以打印警告,但是同时调用Foo().access_bar()
时(从类内部访问该属性)时不能打印此警告?
我尝试实现__getattribute__
方法,但是区分这些情况没有运气。
我知道这是一个很奇怪的问题,但是请不要像“您不需要此”那样回答我。
答案 0 :(得分:2)
您可以将bar
设置为一个属性,该属性可以控制访问而无需向外部显示方法调用,并且可以将属性设为私有:
class Foo:
__bar = 'bar'
@property
def bar(self):
print("direct access")
return Foo.__bar
def access_bar(self):
return self.__bar
f = Foo()
print("warn",f.bar)
print("OK",f.access_bar())
打印:
direct access
warn bar
OK bar
答案 1 :(得分:2)
这是您问题的“真实”答案,您可能不应该这样做:
import inspect
class Foo:
bar = 'bar'
def access_bar(self):
return self.bar
def __getattribute__(self, item):
if item == 'bar':
code = inspect.currentframe().f_back.f_code
if not (start_lineno <= code.co_firstlineno <= end_lineno
and code.co_filename == __file__):
print('Warning: accessing bar directly')
return super().__getattribute__(item)
lines, start_lineno = inspect.getsourcelines(Foo)
end_lineno = start_lineno + len(lines) - 1
print(1, Foo().bar)
print(2, Foo().access_bar())
如果执行此操作,则文件中只有一个名为Foo
的类很重要,否则inspect.getsourcelines(Foo)
可能无法给出正确的结果。
答案 2 :(得分:1)
我建议将值存储在受保护的(一个下划线)或私有的(两个下划线)属性中,并将bar
设置为可以安全访问的属性,相当于您问题中的access_bar
。这就是通常在Python中完成这种事情的方式。
class Foo:
_bar = 'bar'
@property
def bar(self):
# do extra things here
return self._bar
用户仍然可以编写foo._bar
或foo._Foo__bar
(用于私有属性),以在没有任何警告的情况下从外部获取该属性,但是,如果他们知道围绕下划线的约定,他们可能会有所感触这样做会很不舒服,并要注意风险。
答案 3 :(得分:1)
这是通过添加元类以使其也适用于类属性并取消使用inspect
模块,而是向__getattribute__
添加警告标志来改进Alex's answer的另一种尝试。功能本身。
class FooType(type):
def __getattribute__(self, item):
if item == "bar":
print("Warning: accessing bar directly from class")
return item.__getattribute__(self, item)
class Foo(object, metaclass=FooType):
bar = 'bar'
def access_bar(self):
return self.__getattribute__('bar', warn=False)
def __getattribute__(self, item, warn=True):
if item == 'bar' and warn:
print('Warning: accessing bar directly from instance')
return super().__getattribute__(item)
print(Foo.bar)
#Warning: accessing bar directly from class
#bar
print(Foo().bar)
#Warning: accessing bar directly from instance
#bar
print(Foo().access_bar())
#bar