简体   繁体   中英

How do I obtain the reference of a getter/setter method created through @property in Python?

I want to bind some QWidgets to the attributes of an existing class in Python 3 so that any changes made through the GUI are applied to the underlying data objects in a clean and simple fashion.

My existing class looks like this (simplified):

class Player:

    def __init__(self):
        self._health = 100

    @property
    def health(self):
        return self._health

    @health.setter
    def health(self, value):
        self._health = value

PyQt5 allows connecting Qt signals to any method, so I can easily achieve my goal by calling someWidget.valueChanged.connect(player.someSetterMethod) .

However, I use @property and thus, the setter name is identical to the attribute name. When I try using player.health , it is interpreted as an integer (as expected, but obviously not what I want here).

I am aware that I could define getter/setter methods with custom names and then use property() instead of @property , but I am hoping there is a way of obtaining the reference to the setter method so that I can pass it to connect() .

Thank you!

Edit: I doubt it is relevant to this question, but perhaps I should add that in the next step, I want to report changes that are not applied as received back to the GUI.

You'll have to use a lambda , because you need a bound property to get the right context:

someWidget.valueChanged.connect(lambda v: setattr(player, 'health', v))

Property objects do have .fget and .fset attributes, and the property object itself can be accessed on the class:

Player.health.fset
Player.health.fget

but these give you access to the original unbound function objects, which require the self parameter still.

You could use those functions too, but then you'd have to bind them to your instance first:

someWidget.valueChanged.connect(Player.health.fset.__get__(player))

The __get__ method on the function (which is a descriptor ) to provide you with a bound method which passes in the self argument for you (the player instance object in this case).

As seen here https://docs.python.org/3/library/functions.html#property

The returned property object also has the attributes fget, fset, and fdel corresponding to the constructor arguments

So you can access the getter, setter and deleter via these attributes. In your example Player.health.fset(some_instance, new_health)

In order to connect that to your signal you must bind the instance to the setter. This can be done with functools.partial

from functools import partial

someWidget.valueChanged.connect(partial(Player.health.fset, player))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM