I was wondering if it would be possible to have a property setter to also return a value. The code below tries to explain superficially the problem.
Basically I need to set a property to an object, but before I need to check if it is unique. I was wondering if there is a way to the return the unique name to the user directly, without needing to query the object for its new name afterwards.
class MyClass(object):
def __init__(self,ID):
self._ID = ID
#property
def Name(self):
return DBGetName(self._ID)
#Name.setter
def Name(self, value):
UniqueName = DBGetUniqueName(self._ID,value)
return DBSetName(UniqueName)
Myinstance = MyClass(SomeNumber)
#What I do now
Myinstance.Name = "NewName"
Uniquename = Myinstance.Name
#What I was wondering if possible. Line below is syntactically invalid, but shows the idea.
Name = (Myinstance.Name = "NewName")
Edit:
It is a pseudo code and I forgot to actually pass the value to the inner function. My bad.
A setter certainly can return a value.
But it isn't very useful to do so, because setters are generally used in assignment statements—as in your example.
The problem is that in Python, assignment is not an expression, it's a statement. It doesn't have a value that you can use, and you can't embed it in another statement. So, there is no way to write the line you want to write.
You can instead call the setter explicitly… but in that case, it's a lot clearer to just write it as a regular method instead of a property setter.
And in your case, I think a regular method is exactly what you want. You're completely ignoring the value passed to the setter. That's going to confuse readers of your code (including you in 6 months). It's not really a setter at all, it's a function that creates a unique name. So, why not call it that?
def CreateUniqueName(self):
UniqueName = DBGetUniqueName(self._ID)
return DBSetName(UniqueName)
(It's worth noting that DBSetName returning its argument is itself not very Pythonic…)
If you're wondering why Python works this way, see Why can't I use an assignment in an expression? from the official FAQ.
More generally, the expression-statement distinction, together with associated features like mutating methods (e.g., list.sort) returning None instead of self, leads to a simpler, more regular language. Of course there's a cost, in that it leads to a much less fluent language. There's an obvious tradeoff, and Python is about as far to the extreme as you can get. (Compare to JavaScript, which is about as far to the opposite extreme as you can get.) But most people who love Python think it made the right tradeoff.
I started with a similar question, but I only needed to get 'generic' information from a setter in order to automate GUI creation; The GUI code looks through a list of attributes, finds those that have setters and then creates input fields. However some inputs are strings, others floats etc. and the GUI code generates appropriate input fields. I know this is a kludge, but I put that information in the docstring for the getter.
I realise this is not an answer to your question but might help someone looking like I was!
class Dog():
def __init__(self):
self._name = None
return
#property
def name(self):
"""Doggos are the best!"""
return self._name
#name.setter
def name(self, n):
self._name = n
return
def main():
terrier = Dog()
terrier.name = "Rover"
print("Dog's name is ", terrier.name)
print(type(terrier).name.__doc__)
# also works with...
print(getattr(type(terrier), 'name').__doc__)
return
if __name__ == '__main__':
main()
With Python3.8 or greater:
class MyClass(object):
def __init__(self,ID):
self._ID = ID
#property
def Name(self):
return DBGetName(self._ID)
#Name.setter
def Name(self, value):
UniqueName = DBGetUniqueName(self._ID,value)
return DBSetName(UniqueName)
Myinstance = MyClass(SomeNumber)
Myinstance.Name = (Uniquename := Myinstance.Name) # Python >= 3.8
Related
I'm trying to add flexibility to a python class, so that it notices when one of the init arguments is already an instance of that class. Skip "Initial situation" if you don't mind, how I got here.
Initial situation
I have this class:
class Pet:
def __init__(self, animal):
self._animal = animal
#property
def present(self):
return "This pet is a " + self._animal
...
and there are many functions which accept an instance of this class as an argument (def f(pet, ...)). Everything worked as expected.
I then wanted to add some flexibility to the usage of these functions: if the caller passes a Pet instance, everything keeps on working as before. In all other cases, a Pet instance is created. One way to achieve that, is like this:
def f(pet_or_animal, ...):
if isinstance(pet_or_animal, Pet): #Pet instance was passed
pet = pet_or_animal
else: #animal string was passed
pet = Pet(pet_or_animal)
...
This also works as expected, but these lines are repeated in every function. Not DRY, not good.
Goal
So, I'd like to extract the if/else from each of the functions, and integrate it into the Pet class itself. I tried changing its __init__ method to
class PetA: #I've changed the name to facilitate discussion here.
def __init__(self, pet_or_animal):
if isinstance(pet_or_animal, PetA):
self = pet_or_animal
else:
self._animal = pet_or_animal
...
and start each function with
def f(pet_or_animal, ...):
pet = PetA(pet_or_animal)
...
However, that is not working. If a Pet instance is passed, everything is good, but if a string is called, a Pet instance is not correctly created.
Current (ugly) solution
What is working, is to add a class method to the class, like so:
class PetB: #I've changed the name to facilitate discussion here.
#classmethod
def init(cls, pet_or_animal):
if isinstance(pet_or_animal, PetB):
return pet_or_animal
else:
return cls(pet_or_animal)
def __init__(self, animal):
self._animal = animal
...
and also change the functions to
def f(pet_or_animal, ...):
pet = PetB.init(pet_or_animal) #ugly
...
Questions
Does anyone know, how to change class PetA so, that it has the intended behavior? To be sure, here is the quick test:
pb1 = PetB.init('dog')
pb2 = PetB.init(pb1) #correctly initialized; points to same instance as pb1 (as desired)
pa1 = PetA('cat')
pa2 = PetA(pa1) #incorrectly initialized; pa1 != pa2
More generally, is this the right way to go about adding this flexibility? Another option I considered was writing a separate function to just do the checking, but this too is rather ugly and yet another thing to keep track of. I'd rather keep everything neat and wrapped in the class itself.
And one final remark: I realize that some people might find the added class method (petB) a more elegant solution. The reason I prefer to add to the __init__ method (petA) is that, in my real-world use, I already allow for many different types of initialization arguments. So, there is already a list of if/elif/elif/... statements that check, just which of the possibilities is used by the creator. I'd like to extend that by one more case, namely, if an initialized instance is passed.
Many thanks
I believe your current "ugly" solution is actually the correct approach.
This pushes the flexibility up as far as possible, since it is messy. Even though python allows for arbitrary types and values to float around, your users and yourself will thank you for keeping that constrained to the outermost levels.
I would think of it as (don't need to implement it this way)
class Pet:
#classmethod
def from_animal(cls, ...):
...
#classmethod
def from_pet(cls, ...):
...
#classmethod
def auto(cls, ...):
if is_pet(...):
return cls.from_pet(...)
def __init__(cls, internal_rep):
...
etc.
It is a code smell if you don't know whether your function is taking an object or an initializer. See if you can do processing as up-front as possible with user input and standardize everything beyond there.
You could use a function instead to get the same behaviour you want:
def make_pet_if_required(pet_or_animal):
if isinstance(pet_or_animal, PetA):
return pet_or_animal
else:
return Pet(pet_or_animal)
And then:
def f(pet_or_animal, ...):
pet = make_pet_if_required(pet_or_animal)
...
For more "beauty" you can try turning that function call into a decorator.
The property decorator is a great way to "protect" attributes one wants to set once and never change again. I usually deal with this this way (btw., following a the advice here):
self._name = 'foo'
#property
def name(self):
return self._name
so trying to set name directly yields an AttributeError.
However, I often see the following pattern:
#name.setter
def name(self, value):
self._name = value
#property
def name(self):
return self._name
which seems a little counter-intuitive, as it enables exactly what I want to avoid, and requires extra coding, i.e, theoretically
self.name = 'bar'
would suffice, although it is clear that this would be the worst way to deal with the problem.
The best explanation I can come up with is something like a message from the author saying "you should not change this attribute but if you really want to, there is a mechanism to do it without changing a 'protected' attribute". But then, python doesn't really protect attributes.
So, what's the point, which is more pythonic and why?
You're correct that there's no good reason to use a property if you're not doing anything special in the getter or setter. However, if you do want to do something special (like validate new values, or normalize them in some way), then it makes a lot of sense.
For example, this class's foo attribute will always be clamped between 0 and 1 (and non-numerical values will cause an error immediately):
class Foo:
_foo = 1.0
#foo
def probability(self):
return self._foo
#foo.setter
def foo(self, value):
if value < 0:
value = 0
elif value > 1:
value = 1
self._foo = value
An example with a trivial setter, but a complicated getter might be something like this (deferring an expensive initialization that might not be needed):
class Foo:
_foo = None
def initialize_foo(self):
self._foo = some_expensive_calculation()
#property
def foo(self):
if self._foo is None:
self.initialize_foo() # need the default value
return self._foo
#foo.setter
def foo(self, value):
self._foo = value
If the setter and getter are just directly writing and reading the protected variable, then they're pointless, and using it is not Pythonic; it's just wasting time on property overhead for each access. The attribute should just be made public and the property removed.
The advantage to properties is when you need to replace that simple public attribute with something more powerful, because you can make a property that continues to act like it should for code that was using the attribute, but performs additional work as well. Unless you have additional work though, stick with the attribute if you'd allow it to be written anyway.
Note: Technically, a getter and a setter isn't 100% equivalent to the attribute, since without a deleter, it's not behaviorally identical to the raw attribute. But enforcing non-deletability in your API is silly; developers who go around calling del obj.attr on random attributes of third-party class instances (or almost any instance really) deserve what's coming to them, and you shouldn't be defending against that nonsense at the expense of slowing down and complicating normal use patterns.
The goal of this question is to determine whether or not I can wrap setting an object's attribute, without just writing a setter and then wrapping the setter.
I am trying to implement an Observer pattern and I don't want to write more code than I need to (so of course I'll write a big long StackOverflow question, hah - I figure the long-term payoff is worth it).
I started experimenting by trying to wrap obj.__setattr__ with a function but it did not do what I expected it would do, so now I am wondering if I can even wrap the assignment or changing of an object's attribute if I do not just write a setter.
This is what I tried:
class A(object):
pass
def wrapper(obj, func):
def inner(*args, **kwargs):
print "called it"
return func(*args, **kwargs)
return inner
Stick = A()
Stick.__setattr__ = wrapper(Stick, Stick.__setattr__)
Stick.x = 14 #does not print "called it"
If I just write a setter it would make for an easy hook, something like:
class A(object):
def __init__(self, x):
self.x = x
def set_x(self, new_x):
self.x = x
But I'd like to be able to implement the Observer pattern in such a way that whenever obj.x changes for any reason, the listener updates. If obj.x is an int for example I could be either setting it outright or using obj.x += some_int to set it, and so I'm wondering if there is a way of wrapping any/all setting of obj.x without, for example, writing obj.set_x(), obj.add_to_x(), obj.subtract_from_x(), obj.times_x(), etc etc.
EDIT: Thanks for pointing me at properties, but I don't see how it can help me to wrap this in the manner I'm implementing thus far.
For example, if I have an object as such:
class Foo(object):
def __init__(self, ex):
self._x = ex
#property
def x(self):
return self._x
#x.setter
def x(self, value):
self._x = value
...that's fine, and I see that I can modify the function #x.setter wraps directly, but I was hoping to create something which I can use in the following (imaginary pseudocode) way:
A.x.setter = observing_function(A, A.x.setter)
...such that when A.x changes, observing_function is called and does what it is going to do.
If it informs the answer at all -- I am working on a 'scoreboard' to display the score and lives of a central character in a video game. Instead of constantly checking during each loop or setting over and over (which I'm doing now, which seems excessive), I just want it to actually fire when the character's score/lives change, and a wrapper seemed the nicest way to do that.
I was hoping to avoid this:
def add_to_score(self, pts):
self.score += pts
scoreboard_object.text = self.score
...because that to me is awful, even though it'd work. Also it seems like a lot of code just to establish an observer pattern for two variables :P
But this is why I'd prefer to wrap the setter after the fact. I have two different objects that don't necessarily need to have hard-coded data about each other; just a player object with a self.score attribute and a scoreboard object with a self.text attribute, and while writing the 'glue' between them is of course necessary, I'd hoped writing methods to set_score and set_text wouldn't be crucial just to implement an Observer pattern.
If ultimately I can't skip writing a setter (or setters), then I suppose I'll go ahead and do it that way; I'd just hoped to avoid it.
And really while this is now a very specific example, I am also asking in a generic sense as well, because it seems really handy to be able to just watch an attribute for changes instead of coding around every attribute to be ready for maybe watching some changes of some other object. :/
Special methods, descriptors, and all other ways of mucking with attribute access only work on classes. You can't override them on objects.
Use an event (or pub/sub or whatever we're calling it now) system. Make the character responsible for emitting events, but not for remembering specifically who wants them.
class ScoreChanged(Event):
...
class Character(ListenerMixin):
#property
def score(self):
return self._score
#score.setter
def score(self, new):
old = self._score
self._score = new
self.fire_event(ScoreChanged(self, old, new))
protag = Character()
scoreboard = Scoreboard()
scoreboard.listen_event(protag, ScoreChanged, scoreboard.on_score_change)
protag.score += 10
The objects necessarily get entangled somewhere, but it becomes an implementation detail rather than a major part of your code. In particular, the scoreboard doesn't have to be a global, and the character still works fine even when the scoreboard doesn't exist.
There are examples of implementations and existing libraries on this question, but if you're writing a game, it's possible you're already using a library that has its own built in. I know pyglet does.
Special functions of new-style class instances are looked up against their class not the instance, so:
class A(object):
pass
def wrapper(func):
def inner(*args, **kwargs):
print "called it"
return func(*args, **kwargs)
return inner
Stick = A()
A.__setattr__ = wrapper(A.__setattr__)
Stick.x = 14 # prints "called it"
Stick.x *= 2 # also prints "called it"
I was just wondering if it's considered wildly inappropriate, just messy, or unconventional at all to use the init method to set variables by calling, one after another, the rest of the functions within a class. I have done things like, self.age = ch_age(), where ch_age is a function within the same class, and set more variables the same way, like self.name=ch_name() etc. Also, what about prompting for user input within init specifically to get the arguments with which to call ch_age? The latter feels a little wrong I must say. Any advice, suggestions, admonishments welcome!
I always favor being lazy: if you NEED to initialize everything in the constructor, you should--in a lot of cases, I put a general "reset" method in my class. Then you can call that method in init, and can re-initialize the class instance easily.
But if you don't need those variables initially, I feel it's better to wait to initialize things until you actually need them.
For your specific case
class Blah1(object):
def __init__(self):
self.name=self.ch_name()
def ch_name(self):
return 'Ozzy'
you might as well use the property decorator. The following will have the same effect:
class Blah2(object):
def __init__(self):
pass
#property
def name():
return 'Ozzy'
In both of the implementations above, the following code should not issue any exceptions:
>>> b1 = Blah1()
>>> b2 = Blah2()
>>> assert b1.name == 'Ozzy'
>>> assert b2.name == 'Ozzy'
If you wanted to provide a reset method, it might look something like this:
class Blah3(object):
def __init__(self, name):
self.reset(name)
def reset(self, name):
self.name = name
I have a question that is puzzling me recently about which is the best way to retrieve attributes from outside.
Let say I have a class:
class Thing:
def __init__(self, whatever):
self.whatever = whatever
x = Thing('foo')
Now I know that if I want to retrieve whatever attribute I can do this:
x.whatever
I have the habit (probably because I come from other oo languages) to define methods to retrieve class attributes as needed and use them insted of retrieve them directly, like:
class Thing:
def __init__(self, whatever):
self.whatever = whatever
def getWhatever(self):
return self.whatever
In my little experience I've found that using this approach make things easier to mantain in the long term because if I edit the structure of data attributes I have to edit only the specific method.
But since I am not really a python veteran I'd love to know if I am doin' it right or if some other approaches are better and more pythonic. Thoughts?
Defining explicit getters and setters is a bad practice in Python. Instead, use properties:
class Thing(object): # New-style class
def __init__(self, whatever):
self._whatever = whatever
#property
def whatever(self):
return self._whatever # Insert complicated calculation here
So instead of pre-planning by using get methods, just introduce a property when you actually need advanced behavior, and not any earlier.
#phihag has the right idea, and mentions in their answer, but to be more explicit about it: The first step is simply to use the attribute directly:
class Thing(object):
def __init__(self, whatever):
self.whatever = whatever
t = Thing(12)
assert t.whatever == 12
Later, if you find you need to make the whatever attribute more sophisticated, you can turn it into a property:
class Thing(object):
def __init__(self, whatever):
self._whatever = whatever
#property
def whatever(self):
return something_complicated(self._whatever)
t = Thing(12)
assert t.whatever == 12
This way, the calling code doesn't change, and you have a nice clean API to your object.
check python property() http://docs.python.org/library/functions.html#property