_u_init上的Python类属性验证__

_u_init上的Python类属性验证__,python,oop,getter-setter,Python,Oop,Getter Setter,我试图在下面的代码中使用setter验证类的一个属性。我要验证的属性名为“\uux”,并设置为在“init”方法上传递的参数。当我将“self_uuuux”更改为“self.x”时,它就如我所期望的那样工作了。我想知道的是它是如何使用“self.x”的,而我在getter和setter方法中的任何地方都不返回“x”属性,以及为什么它不使用“self.” class P: def __init__(self, x): self.__x = x # not working

我试图在下面的代码中使用setter验证类的一个属性。我要验证的属性名为“\uux”,并设置为在“init”方法上传递的参数。当我将“self_uuuux”更改为“self.x”时,它就如我所期望的那样工作了。我想知道的是它是如何使用“self.x”的,而我在getter和setter方法中的任何地方都不返回“x”属性,以及为什么它不使用“self.”

class P:
    def __init__(self, x):
        self.__x = x  # not working
        # self.x = x  # working

    @property
    def x(self):
        return self.__x

    @x.setter
    def x(self, x):
        if x < 0:
            self.__x = 0
        else:
            self.__x = x


p = P(-5)
print(p.x)  # prints -5
P类:
定义初始化(self,x):
self.\uuux=x#不工作
#self.x=x#正在工作
@财产
def x(自我):
返回自我
@x、 塞特
def x(self,x):
如果x<0:
自。uux=0
其他:
自
p=p(-5)
印刷品(p.x)#印刷品-5

是这样的。想象一下有一个校园恶霸,我们叫他丹,他以你为目标。还有贝丝,你很喜欢她。通常情况下,你想避开丹和贝丝见面,但丹不在乎,如果他看到你,他会打你的头

现在你也和乔交朋友了。他是个温和的巨人。非常好的人。他说到他家来,他会确保不让丹进来。一切都很好:当丹来到乔的门口时,他已经转身离开了;当贝丝来时,乔让她进来

关键的一点是:它只在丹开门的时候起作用。如果你听到门铃声自己出去,它就不起作用了


在这里,如果你做了self.x=-5,Joe检查号码,发现是Dan,给他打了个零。但是如果你做了自己,乔就再也见不到丹了。你头上有一个防喷器


self.\uux
只是一个变量,它自己无法进行任何检查
self.x是一个函数(其中两个函数是真的,一个用于读,一个用于写),它可以做任何它想做的事情-设置
self.\uuux
或拒绝。

它是这样的。想象一下有一个校园恶霸,我们叫他丹,他以你为目标。还有贝丝,你很喜欢她。通常情况下,你想避开丹和贝丝见面,但丹不在乎,如果他看到你,他会打你的头

现在你也和乔交朋友了。他是个温和的巨人。非常好的人。他说到他家来,他会确保不让丹进来。一切都很好:当丹来到乔的门口时,他已经转身离开了;当贝丝来时,乔让她进来

关键的一点是:它只在丹开门的时候起作用。如果你听到门铃声自己出去,它就不起作用了


在这里,如果你做了self.x=-5,Joe检查号码,发现是Dan,给他打了个零。但是如果你做了自己,乔就再也见不到丹了。你头上有一个防喷器

self.\uux
只是一个变量,它自己无法进行任何检查
self.x
是一个函数(其中两个函数是真的,一个用于读,一个用于写),它可以做任何它想做的事情-设置
self.\uuuux
或拒绝。

让我们从“@decorator”语法开始。它实际上只是语法上的糖,所以

@decorate
def myfunc():
    pass
这只是

def myfunc():
    pass

myfunc = decorate(myfunc)
请注意,python函数也是对象(以及类和模块FWIW),因此您可以将函数作为参数传递给其他函数、从函数返回函数、将函数存储为变量或属性等

现在使用
属性
类(是的,它是一个类):它只是的一个通用实现,它是支持计算属性的python机制

property
的简单python实现看起来大致类似(我忽略了
fdel
\u del\u
部分):

最后:虽然在初始值设定项中创建对象的所有实例属性(
\uuuu init\uuuu
方法)是一种很好的做法,但实际上您可以随时随地设置现有属性或新属性。除了少数类型(主要出于实现原因)使用完全不同的方式存储属性(如果您想了解更多信息,可以查找
插槽
),普通Python对象主要是伪装的dict,因此
myobj.foo='bar'
通常只将
'bar'
存储在
self.\uu dict\uuuu['foo']
。当然,如果不使用计算属性;)

好的,现在我们有了构建块,让我们分析一下你的课堂上发生了什么:

class P:
    # let's ignore the initializer for now

    @property
    def x(self):
        return self.__x

    @x.setter
    def x(self, x):
        if x < 0:
            self.__x = 0
        else:
            self.__x = x
当我们这样做时:

p.x = 5
属性解析规则(在
对象中实现.\uuuu setattr\uuuuuuuuuuuuuuu(self,name,value)
)实际上会在“p”上查找“x”,找到我们的“x”属性,因为它是一个绑定描述符(它有一个
\uuuuuu set\uuuuuuuuuuuuuuuuuuu方法),所以调用
x.\uuu set\uuuuuuuuup(p,5)
,这反过来会调用
self.fset(p,5)
(cf
属性)__()
definition),它将调用
p.\u setx(5)

如果我们得到了初始值设定项:

class P:
    def __init__(self, x):
        self.x = x

    # getter / setter / property definition  here
然后非常精确的事情发生了(除了
p
实例被命名为
self
而不是
p
)-它实际上最终调用了
p.\u setx(self,x)

与原始实现的唯一区别在于,使用
属性时有一个decorator,getter和setter函数不会成为类的方法,它们只作为
x
属性对象的
fget
fset
属性存在语法,实际上只是语法上的糖分,所以

@decorate
def myfunc():
    pass
这只是

def myfunc():
    pass

myfunc = decorate(myfunc)
请注意,python函数也是对象(以及类和模块FWIW),因此您可以将函数作为参数传递给其他函数、从函数返回函数、将函数存储为变量或属性等

现在使用
属性
类(是的,它是一个类):它只是的一个通用实现,它是支持计算属性的python机制

p的朴素python实现
class P:
    def __init__(self, x):
        self.x = x

    # getter / setter / property definition  here