Reputation: 9808
Imagine the following code (which is totally useless if taken alone):
# define a property with additional methods
class P(property):
def __init__(self, name):
property.__init__(self,
fget=lambda self: self._get(name),
fset=lambda self, v: self._set(name, v))
self._name = name
def some_fn(self):
print('name: ' + self._name)
# define a class with two 'enhanced' properties
class C:
p1 = P('p1')
p2 = P('p2')
def __init__(self):
self._values = {}
def _get(self, name):
return self._values[name]
def _set(self, name, v):
self._values[name] = v
c = C()
c.p1 = 5
c.p2 = c.p1
print(c.p1, c.p2)
I just create a class C
with two properties
which have an extra method some_fn()
.
The problem is now: you can't call some_fn()
easily by just writing c.p1.some_fn()
because you would evaluate c.p1
first, which results in some value which doesn't provide the method any more.
I've tried to find some workarounds / approaches for calling some_fn
in the context of a certain property
, not it's value but I'm not happy yet.
My goal is quite simple:
I want to be able read/assign properties without boilerplate:
c.p1 = c.p2
instead of c.p1.set(c.p2.get())
The way I call the extra method/function must be easy to read/write
I want to write code that can be statically verified by pylint
, mypy
etc. so some_fn('c.p1') is not an option because it can't be checked whether 'c.p1' is a valid attribute of an existing object
c`.
some_fn
doesn't have to be a method. It can be a function or any other way to request functionality in context of a property
I don't even need real properties
. Any other way to write s.th.
like c.p1 == c.p2
(e.g. using __getattr__
/__setattr__
) would be fine, too as long as the get/set operations are still trackable.
I collected some code to make clear, what I'm talking about:
# ==== What I want to do ==============
c.p1.some_fn() # <-- this is what I want to write but
# it's invalid since it evaluates to
# 5.some_fn()
some_fn(c.p1) # <-- something like this looks OK, too but
# it evalueates to some_fn(5) (useless)
# ==== These are options that came to mind but I'm not happy with ======
getattr(C, 'p1').some_fn() # <-- this works but it is ugly
some_fn("c.p1") # <-- this is possible, too but I can't
# check integrity statically (pylint/mypy)
c.p1.value = c.p2.value # <-- this is a valid approach but it
c.p1.some_fn() # increases
some_fn(c.p1) # (again) # <-- This can acutally work if you `inspect`
# the call stack inside `C._get()` but
# it's black magic and incredibly slow
with some_fn(): # <-- this can work when `some_fn` changes
c.p1 # some global state which get's evaluated
# inside `C._get()`
Upvotes: 0
Views: 59
Reputation: 282026
My goal is quite simple: I want to be able read/assign properties without boilerplate:
c.p1 = c.p2
If that is the goal here, it sounds like you've misunderstood properties, because they already work like that.
class C(object):
@property
def p1(self):
# get value
@p1.setter
def p1(self, val):
# set value
@property
def p2(self):
# get value
@p2.setter
def p2(self, val):
# set value
Then if you have an object c = C()
, you can do c.p1 = c.p2
, and it'll just work. Sticking more methods onto a property
object is the wrong way to go.
If you really want to stick methods onto properties, retrieve the property through the class:
C.p1.some_fn()
Upvotes: 1