@property decorator在Python中是如何工作的?

@property decorator在Python中是如何工作的?,python,properties,decorator,python-decorators,python-internals,Python,Properties,Decorator,Python Decorators,Python Internals,我想了解内置函数属性是如何工作的。使我困惑的是,属性也可以用作装饰器,但它仅在用作内置函数时才接受参数,而在用作装饰器时不接受参数 此示例来自: property的参数包括getx、setx、delx和一个文档字符串 在下面的代码中,属性用作装饰器。它的对象是x函数,但在上面的代码中,参数中没有对象函数的位置 class C: def __init__(self): self._x = None @property def x(self):

我想了解内置函数
属性
是如何工作的。使我困惑的是,
属性
也可以用作装饰器,但它仅在用作内置函数时才接受参数,而在用作装饰器时不接受参数

此示例来自:

property
的参数包括
getx
setx
delx
和一个文档字符串

在下面的代码中,
属性
用作装饰器。它的对象是
x
函数,但在上面的代码中,参数中没有对象函数的位置

class C:
    def __init__(self):
        self._x = None

    @property
    def x(self):
        """I'm the 'x' property."""
        return self._x

    @x.setter
    def x(self, value):
        self._x = value

    @x.deleter
    def x(self):
        del self._x
在这种情况下,如何创建
x.setter
x.deleter
装饰器?

这只是创建只读属性的快捷方式。所以

@property
def x(self):
    return self._x
相当于

def getx(self):
    return self._x
x = property(getx)

第一部分很简单:

@property
def x(self): ...

def x(self): ...
x = property(x)
  • 反过来,这是一种简化的语法,用于仅使用getter创建
    属性
下一步是使用setter和deleter扩展此属性。这是通过适当的方法实现的:

@x.setter
def x(self, value): ...
返回一个新属性,该属性继承旧的
x
加上给定的setter的所有内容

x.deleter
的工作方式相同。

函数
属性()
返回一个特殊的:

>>属性()
此对象具有额外的方法:

真的和

def foo(self): return self._foo
foo = property(foo)
因此
foo
函数被
property(foo)
替换,我们在上面看到的是一个特殊对象。然后,当您使用
@foo.setter()
时,您要做的是调用上面我向您展示的
property().setter
方法,该方法返回属性的新副本,但这次用修饰的方法替换setter函数

下面的序列还通过使用这些decorator方法创建一个full-on属性

首先,我们用一个getter创建一些函数和一个
属性
对象:

>>> def getter(self): print('Get!')
... 
>>> def setter(self, value): print('Set to {!r}!'.format(value))
... 
>>> def deleter(self): print('Delete!')
... 
>>> prop = property(getter)
>>> prop.fget is getter
True
>>> prop.fset is None
True
>>> prop.fdel is None
True
接下来,我们使用
.setter()
方法添加一个setter:

>>> prop = prop.setter(setter)
>>> prop.fget is getter
True
>>> prop.fset is setter
True
>>> prop.fdel is None
True
最后,我们使用
.deleter()
方法添加一个删除器:

>>> prop = prop.deleter(deleter)
>>> prop.fget is getter
True
>>> prop.fset is setter
True
>>> prop.fdel is deleter
True
最后但并非最不重要的一点是,
属性
对象充当了一个对象,因此它具有用于连接实例属性获取、设置和删除的属性和方法:

>>> class Foo: pass
... 
>>> prop.__get__(Foo(), Foo)
Get!
>>> prop.__set__(Foo(), 'bar')
Set to 'bar'!
>>> prop.__delete__(Foo())
Delete!
描述符Howto包括
属性()
类型的


下面是如何实现
@property
的一个简单示例:

class Thing:
    def __init__(self, my_word):
        self._word = my_word 
    @property
    def word(self):
        return self._word

>>> print( Thing('ok').word )
'ok'
否则,
word
仍然是一个方法而不是一个属性

class Thing:
    def __init__(self, my_word):
        self._word = my_word
    def word(self):
        return self._word

>>> print( Thing('ok').word() )
'ok'
这包括:

class C(object):
    def __init__(self):
        self._x = None

    @property
    def x(self):
        """I'm the 'x' property."""
        return self._x

    @x.setter
    def x(self, value):
        self._x = value

    @x.deleter
    def x(self):
        del self._x
同:

class C(object):
    def __init__(self):
        self._x = None

    def _x_get(self):
        return self._x

    def _x_set(self, value):
        self._x = value

    def _x_del(self):
        del self._x

    x = property(_x_get, _x_set, _x_del, 
                    "I'm the 'x' property.")
class C(object):
    def __init__(self):
        self._x = None

    def _x_get(self):
        return self._x

    def _x_set(self, value):
        self._x = value

    def _x_del(self):
        del self._x

    x = property(_x_get, doc="I'm the 'x' property.")
    x = x.setter(_x_set)
    x = x.deleter(_x_del)
class C(object):
    def __init__(self):
        self._x = None

    def _x_get(self):
        return self._x
    x = property(_x_get, doc="I'm the 'x' property.")

    def _x_set(self, value):
        self._x = value
    x = x.setter(_x_set)

    def _x_del(self):
        del self._x
    x = x.deleter(_x_del)
同:

class C(object):
    def __init__(self):
        self._x = None

    def _x_get(self):
        return self._x

    def _x_set(self, value):
        self._x = value

    def _x_del(self):
        del self._x

    x = property(_x_get, _x_set, _x_del, 
                    "I'm the 'x' property.")
class C(object):
    def __init__(self):
        self._x = None

    def _x_get(self):
        return self._x

    def _x_set(self, value):
        self._x = value

    def _x_del(self):
        del self._x

    x = property(_x_get, doc="I'm the 'x' property.")
    x = x.setter(_x_set)
    x = x.deleter(_x_del)
class C(object):
    def __init__(self):
        self._x = None

    def _x_get(self):
        return self._x
    x = property(_x_get, doc="I'm the 'x' property.")

    def _x_set(self, value):
        self._x = value
    x = x.setter(_x_set)

    def _x_del(self):
        del self._x
    x = x.deleter(_x_del)
同:

class C(object):
    def __init__(self):
        self._x = None

    def _x_get(self):
        return self._x

    def _x_set(self, value):
        self._x = value

    def _x_del(self):
        del self._x

    x = property(_x_get, _x_set, _x_del, 
                    "I'm the 'x' property.")
class C(object):
    def __init__(self):
        self._x = None

    def _x_get(self):
        return self._x

    def _x_set(self, value):
        self._x = value

    def _x_del(self):
        del self._x

    x = property(_x_get, doc="I'm the 'x' property.")
    x = x.setter(_x_set)
    x = x.deleter(_x_del)
class C(object):
    def __init__(self):
        self._x = None

    def _x_get(self):
        return self._x
    x = property(_x_get, doc="I'm the 'x' property.")

    def _x_set(self, value):
        self._x = value
    x = x.setter(_x_set)

    def _x_del(self):
        del self._x
    x = x.deleter(_x_del)
这与:

class C(object):
    def __init__(self):
        self._x = None

    @property
    def x(self):
        """I'm the 'x' property."""
        return self._x

    @x.setter
    def x(self, value):
        self._x = value

    @x.deleter
    def x(self):
        del self._x

属性可以用两种方式声明

  • 为属性创建getter、setter方法,然后将它们作为参数传递给属性函数
  • 使用@属性装饰器

你可以看看我写的几个例子

我阅读了这里的所有帖子,意识到我们可能需要一个真实的例子。实际上,为什么我们有@property? 因此,考虑使用认证系统的烧瓶应用程序。 您可以在
models.py
中声明模型用户:

class User(UserMixin, db.Model):
    __tablename__ = 'users'
    id = db.Column(db.Integer, primary_key=True)
    email = db.Column(db.String(64), unique=True, index=True)
    username = db.Column(db.String(64), unique=True, index=True)
    password_hash = db.Column(db.String(128))

    ...

    @property
    def password(self):
        raise AttributeError('password is not a readable attribute')

    @password.setter
    def password(self, password):
        self.password_hash = generate_password_hash(password)

    def verify_password(self, password):
        return check_password_hash(self.password_hash, password)
在这段代码中,我们通过使用
@property
来“隐藏”属性
password
,当您试图直接访问它时,它会触发
AttributeError
断言,而我们使用@property.setter来设置实际实例变量
password\u hash

现在,在
auth/views.py
中,我们可以使用以下命令实例化用户:

...
@auth.route('/register', methods=['GET', 'POST'])
def register():
    form = RegisterForm()
    if form.validate_on_submit():
        user = User(email=form.email.data,
                    username=form.username.data,
                    password=form.password.data)
        db.session.add(user)
        db.session.commit()
...
请注意,当用户填写表单时,来自注册表的属性
password
。密码确认在前端通过
EqualTo('Password',message='Passwords must match')
进行(如果您想知道,但这是一个与表单相关的不同主题)


我希望这个例子会有用

这里是另一个例子:

##
## Python Properties Example
##
class GetterSetterExample( object ):
    ## Set the default value for x ( we reference it using self.x, set a value using self.x = value )
    __x = None


##
## On Class Initialization - do something... if we want..
##
def __init__( self ):
    ## Set a value to __x through the getter / setter... Since __x is defined above, this doesn't need to be set...
    self.x = 1234

    return None


##
## Define x as a property, ie a getter - All getters should have a default value arg, so I added it - it will not be passed in when setting a value, so you need to set the default here so it will be used..
##
@property
def x( self, _default = None ):
    ## I added an optional default value argument as all getters should have this - set it to the default value you want to return...
    _value = ( self.__x, _default )[ self.__x == None ]

    ## Debugging - so you can see the order the calls are made...
    print( '[ Test Class ] Get x = ' + str( _value ) )

    ## Return the value - we are a getter afterall...
    return _value


##
## Define the setter function for x...
##
@x.setter
def x( self, _value = None ):
    ## Debugging - so you can see the order the calls are made...
    print( '[ Test Class ] Set x = ' + str( _value ) )

    ## This is to show the setter function works.... If the value is above 0, set it to a negative value... otherwise keep it as is ( 0 is the only non-negative number, it can't be negative or positive anyway )
    if ( _value > 0 ):
        self.__x = -_value
    else:
        self.__x = _value


##
## Define the deleter function for x...
##
@x.deleter
def x( self ):
    ## Unload the assignment / data for x
    if ( self.__x != None ):
        del self.__x


##
## To String / Output Function for the class - this will show the property value for each property we add...
##
def __str__( self ):
    ## Output the x property data...
    print( '[ x ] ' + str( self.x ) )


    ## Return a new line - technically we should return a string so it can be printed where we want it, instead of printed early if _data = str( C( ) ) is used....
    return '\n'

##
##
##
_test = GetterSetterExample( )
print( _test )

## For some reason the deleter isn't being called...
del _test.x
基本上,与C(对象)示例相同,只是我使用了x来代替。。。我也不在uu init中初始化-。。。好。。我知道,但是它可以被删除,因为_x被定义为类的一部分

输出为:

[ Test Class ] Set x = 1234
[ Test Class ] Get x = -1234
[ x ] -1234
[ Test Class ] Get x = None
[ x ] None
如果我在init中注释掉self.x=1234,则输出为:

[ Test Class ] Set x = 1234
[ Test Class ] Get x = -1234
[ x ] -1234
[ Test Class ] Get x = None
[ x ] None
如果我在getter函数中将_default=None设置为_default=0(因为所有getter都应该有一个默认值,但它不是由我看到的属性值传入的,所以你可以在这里定义它,实际上它并不坏,因为你可以定义默认值一次,然后在任何地方都使用它),例如:def x(self,_default=0):

注意:getter逻辑只是让值被它操纵,以确保它被它操纵-打印语句也是如此

注意:我已经习惯了Lua,能够在调用单个函数时动态创建10+个helper,我为Python做了一些类似的东西,但没有使用属性,它在一定程度上可以工作,但是,即使函数是在使用之前创建的,有时在创建之前调用它们仍然存在一些问题,这很奇怪,因为它不是那样编码的。。。我更喜欢Lua元表的灵活性,并且我可以使用实际的setter/getter,而不是直接访问变量。。。不过,我很喜欢用Python构建某些东西的速度——例如gui程序。虽然我设计的一个可能没有很多额外的库是可能的-如果我在AutoHotkey编码,我可以直接访问我需要的DLL调用,同样可以在爪哇,C,C++,和更多-也许我还没有找到正确的东西,但对于这个项目,我可以从Python切换…< / P> 注意:此论坛中的代码输出已损坏-我必须在代码的第一部分添加空格才能使其正常工作-复制/粘贴时,请确保将所有空格转换为选项卡。。。。我使用Python的制表符,因为在一个文件中
class Celsius:
def __init__(self, temperature = 0):
    self.set_temperature(temperature)

def to_fahrenheit(self):
    return (self.get_temperature() * 1.8) + 32

def get_temperature(self):
    return self._temperature

def set_temperature(self, value):
    if value < -273:
        raise ValueError("Temperature below -273 is not possible")
    self._temperature = value
class Celsius:
def __init__(self, temperature = 0):
    self.temperature = temperature

def to_fahrenheit(self):
    return (self.temperature * 1.8) + 32

def get_temperature(self):
    print("Getting value")
    return self.temperature

def set_temperature(self, value):
    if value < -273:
        raise ValueError("Temperature below -273 is not possible")
    print("Setting value")
    self.temperature = value

temperature = property(get_temperature,set_temperature)
temperature = property(get_temperature,set_temperature)
# make empty property
temperature = property()
# assign fget
temperature = temperature.getter(get_temperature)
# assign fset
temperature = temperature.setter(set_temperature)
C = Celsius()
C.temperature
# instead of writing C.get_temperature()
class Celsius:
    def __init__(self, temperature = 0):
        self.temperature = temperature

    def to_fahrenheit(self):
        return (self.temperature * 1.8) + 32

    @property
    def temperature(self):
        print("Getting value")
        return self.temperature

    @temperature.setter
    def temperature(self, value):
        if value < -273:
            raise ValueError("Temperature below -273 is not possible")
        print("Setting value")
        self.temperature = value
class OurClass:

    def __init__(self, a):
        self.x = a


y = OurClass(10)
print(y.x)
class OurClass:

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

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

    @x.setter
    def x(self, x):
        if x < 0:
            self.__x = 0
        elif x > 1000:
            self.__x = 1000
        else:
            self.__x = x
class Money:
    def __init__(self, dollars, cents):
        self.dollars = dollars
        self.cents = cents
money = Money(27, 12)

print("I have {} dollar and {} cents.".format(money.dollars, money.cents))
# prints I have 27 dollar and 12 cents.
class Money:
    def __init__(self, dollars, cents):
        self.total_cents = dollars * 100 + cents
money = Money(27, 12)

print("I have {} dollar and {} cents.".format(money.dollars, money.cents))
class Money:
    def __init__(self, dollars, cents):
        self.total_cents = dollars * 100 + cents

    # Getter and setter for dollars...
    @property
    def dollars(self):
        return self.total_cents // 100

    @dollars.setter
    def dollars(self, new_dollars):
        self.total_cents = 100 * new_dollars + self.cents

    # And the getter and setter for cents.
    @property
    def cents(self):
        return self.total_cents % 100

    @cents.setter
    def cents(self, new_cents):
        self.total_cents = 100 * self.dollars + new_cents
money = Money(27, 12)

print("I have {} dollar and {} cents.".format(money.dollars, money.cents))
# prints I have 27 dollar and 12 cents.
money.dollars += 2
print("I have {} dollar and {} cents.".format(money.dollars, money.cents))
# prints I have 29 dollar and 12 cents.

money.cents += 10
print("I have {} dollar and {} cents.".format(money.dollars, money.cents))
# prints I have 29 dollar and 22 cents.
class UtilityMixin():
    @property
    def get_config(self):
        return "This is property"
util = UtilityMixin()
print(util.get_config)
print(property) #<class 'property'>
class C:
    def __init__(self):
        self._x=None

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

    @x.setter 
    def x(self, value):
        self._x = value

    @x.deleter
    def x(self):
        del self._x

c = C()
c.x="a"
print(c.x)
class C:
    def __init__(self):
        self._x=None

    def g(self):
        return self._x

    def s(self, v):
        self._x = v

    def d(self):
        del self._x

    prop = property(g,s,d)

c = C()
c.x="a"
print(c.x)
prop = property(g,s,d)
prop = property(fget=g,fset=s,fdel=d)
 |    fget
 |      function to be used for getting an attribute value
 |    fset
 |      function to be used for setting an attribute value
 |    fdel
 |      function to be used for del'ing an attribute
 |    doc
 |      docstring
class C:
    def __init__(self):
        self._x=None

    def g(self):
        return self._x

    def s(self, x):
        self._x = x

    def d(self):
        del self._x

    def s2(self,x):
        self._x=x+x


    x=property(g)
    x=x.setter(s)
    x=x.deleter(d)      


c = C()
c.x="a"
print(c.x) # outputs "a"

C.x=property(C.g, C.s2)
C.x=C.x.deleter(C.d)
c2 = C()
c2.x="a"
print(c2.x) # outputs "aa"
function decorator(undecorated_func):
    print("calling decorator func")
    inner():
       print("I am inside inner")
       return undecorated_func
    return inner
   undecorated_function= decorator(undecorated_func) 
class Person:
    def __init__(self,name):
        self._name=name
    @property
    def name(self):
        return self._name
    @name.setter
    def name(self.value):
        self._name=value
name=property(name) # Person.__dict__ you ll see name 
   name=name.setter(name) 
  name=property(name)
  name=name.setter(name)