What is the proper way to write getter and setter in Python? - python

I am from the C# background.
I am trying to write getter and setters methods. In other words, I am trying to create properties for a class.
class ParamDefinition:
def __init__(self, type_name):
self.__type_name = type_name
#property
def get_type_name(self):
return self.__type_name
#get_type_name.setter
def set_type_name(self, type_name):
self.__type_name = type_name
def printf(self):
print(self.__type_name)
def test():
compDef = ParamDefinition(None)
compDef.type_name = "int"
compDef.printf()
if __name__ == "__main__":
test()
Output:
None
What is incorrect with my property-definition?

Both the getter and setter need to have the same name:
class ParamDefinition:
def __init__(self, type_name):
self.__type_name = type_name
#property
def type_name(self):
return self.__type_name
#type_name.setter
def type_name(self, type_name):
self.__type_name = type_name
def printf(self):
print(self.__type_name)
def test():
compDef = ParamDefinition(None)
compDef.type_name = "int"
compDef.printf()
if __name__ == "__main__":
test()
Output:
int
EDIT:
While this isn't technically part of the question I thought I should add some more thoughts. You say you are from a C# background, and in C# it's fairly normal to make every field a property by default since you can add extra logic later without breaking the interface, and allows reflection.
These advantages don't really exist with Python and as you can see the boilerplate needed to turn a field into a property is much more significant than in C#. Therefore I'd recommend not using properties in Python until it's really what you need.

Related

Some doubts about #property in python 3

In order not to extend myself too much I will give a basic and hypothetical example of what I am trying to do.
Suppose the following class:
class foo():
def __init__(self):
self.keywords = []
## this method returns the entire list
def get_keywords(self):
return self.keywords
def set_keywords(self, value):
self.keywords.append(value)
But I want to code this in a pythonic way using the #property decorator.
My (wrong) attempt to do this:
class foo:
def __init__(self):
self.key = []
#property
def key(self):
return self.__key
#key.setter
def key(self, value):
self.__key.append(value)
So, whats is wrong in my attempt ?
ps: English is not my native language and I hope my doubt is understandable.
In your original code, self.set_keywords only appends to an existing list; it does not let you initialize the value of keywords to an arbitrary list. This restriction is preserved in your property-based code, which means you cannot assign directly to self.key; you have to initialize the underlying list in __init__ directly.
class foo:
def __init__(self):
# self.key = [] is equivalent to `self.__key.append([])`, but
# self.__key doesn't exist yet. (And would be wrong even if it did.)
self.__key = []
#property
def key(self):
return self.__key
#key.setter
def key(self, value):
self.__key.append(value)
However, this means an assignment like self.key = 3 doesn't actually perform what most people would expect of an assignment. It doesn't overwrite the old value, it adds to it instead. Use the setter to provide a fixed list, but a different method to add to an existing one.
class foo:
def __init__(self):
self.__keys = []
#property
def keys(self):
return self.__keys
#keys.setter
def keys(self, values):
self.__keys = values
def add_key(self, value):
self.__key.append(value)
And finally, it's not necessarily more Pythonic to use a property if you don't actually do any sort of extra work or validation in the getter or setter. If all you are doing is wrapping access to an underlying value, just let the value be used directly.
class foo:
def __init__(self):
self.keys = []
self.keys = [1,2,3]
print(self.keys)
self.keys.append(4)
# etc
The nice thing about properties is that if you start by allowing direct access to keys, then nothing about how you use keys changes if you later decide to replace it with a property.
You can give this a try:
class Foo:
def __init__(self):
self._key = []
#property
def key(self):
return self._key
#key.setter
def key(self, value):
self._key = value
Here are my two cents:
Rename the class foo to Foo
You can't initialize self.key, as this is the property, so initialize the correct variable in the constructor (i.e. __init__)
Private vars are prefixed with one _ scope and not two (two __ are Python internals)
I suppose you rather want my_instance.key = ['spam', 'eggs'] to replace the foo._key value than extend it. Because this is kind of a "setter" and that would result in a weird behaviour, or at least another developer won't expect that behaviour from that setter/function
However, and that's important: As long as you're only doing this, you won't need properties. You can simply initialize self.keys in the constructor and froget about the property and setter function. Later on, when you want to change the behaviour, you can still add the property and setter. That's one reason why we've properties in Python, so that you won't have to refactor your whole code in case "a bit more logic" comes into place.
Btw. if you're really depending everything on those dict functions, you might also want to inherit your class from the dict class. Depends what you're up to.

python classes getters and setters static method and class method

class Spam(object):
#a_string = 'candy'
def __init__(self, sold=0, cost=0):
self.sold = sold
self.cost = cost
#staticmethod
def total_cost():
return True
#classmethod
def items_sold(cls, how_many):
#property
def silly_walk(self):
return print (self.a_string)
#silly_walk.setter
def silly_walk(self, new_string):
self.a_string = new_string.upper()
def do_cost(self):
if self.total_cost():
print('Total cost is:', self.cost)
.
from spam import Spam
def main ():
cost = 25
sold = 100
a_string = 'sweets'
sp = Spam(100, 25)
sp.do_cost()
sw = Spam.silly_walk(a_string)
sw.silly_walk()
if __name__ == '__main__':
main()
so im new to python and i don't understand how to use the setters and getters in this. so what i want to do is:
use #property to create a setter and getter for a property named silly_walk. Have the setter upper case the silly_walk string.
Show example code that would access the static method.
Show example code that would use the silly_walk setter and getter.
im getting very confused with what "self" does in the class and im not sure if what im doing is correct
update:
problem was the #classmethod not having a return and indentation error, so everything is fixed thanks everybody
self is convention. Since you're inside a class, you don't have functions there you have methods. Methods expect a reference to the object calling them as the first argument, which by convention is named self. You can call it anything you like.
class Foo(object):
def __init__(itsa_me_maaaario, name):
itsa_me_maaario.name = "Mario"
That works just as well.
As for the rest of your code -- what's your QUESTION there? Looks like your setter is a bit weird, but other than that it should work mostly okay. This is better:
class Spam(object): # inherit from object in py2 for new-style classes
def __init__(self, a_string, sold=0, cost=0) # put the positional arg first
...
#staticmethod
def total_cost():
# you have to do something meaningful here. A static method can't access
# any of the objects attributes, it's really only included for grouping
# related functions to their classes.
#classmethod
def items_sold(cls, how_many):
# the first argument to a classmethod is the class, not the object, so
# by convention name it cls. Again this should be something relevant to
# the class not to the object.
#property
def silly_walk(self):
return self.a_string
# don't call itself.
#silly_walk.setter
def silly_walk(self, new_string):
self.a_string = new_string
# it really just hides the attribute.
For instance I have a class I built to abstract a computer system I'm in charge of. It might be something like:
class System(object):
type_ = "Base system"
def __init__(self, sitenum, devicenum, IP):
self._sitenum = sitenum
self._devicenum = devicenum
self._IP = IP
# the leading underscores are a flag to future coders that these are
# "private" variables. Nothing stopping someone from using it anyway,
# because System()._IP is still that attribute, but it makes it clear
# that they're not supposed to be used that way.
#staticmethod
def ping_system(IP):
subprocess.call(["ping",IP], shell=True) # OH GOD SECURITY FLAW HERE
# group this with Systems because maybe that's how I want it? It's an
# aesthetic choice. Note that this pings ANY system and requires an
# argument of an IP address!
#classmethod
def type_of_system(cls):
return cls.type_
# imagine I had a bunch of objects that inherited from System, each w/
# a different type_, but they all inherit this....
#property
def description(self):
return "Site {}, Device {} # {}".format(self._sitenum,
self._devicenum,
self._IP)
#description.setter
def description(self, *args):
if len(args) == 3:
self._sitenum, self._devicenum, self._IP = args
elif len(args) == 1 and len(args[0]) == 3:
self._sitenum, self._devicenum, self._IP = args[0]
else:
raise ValueError("Redefine description as Sitenum, Devicenum, IP")
Example:
computer = System(1, 1, '192.168.100.101')
System.ping_system('192.160.100.101') # works
computer.type_of_system # "Base system"
computer.description # "Site 1, Device 1 # 192.168.100.101"
new_description = [1, 2, '192.168.100.102']
computer.description = new_description
# invokes description.setter
computer._devicenum # is 2 after the setter does its magic.

python: multiple objects that can modify the attributes of a single 'master' object

Suppose I have a single instance of a master object that contains a set of parameters, then multiple instances of slave objects that should be able to access and modify the attributes of the master. In my particular case the slaves are wxPython GUI objects, where there might be multiple GUI controls that can modify the same parameter.
Obviously this is trivial if I explicitly refer to master.parameter when the slave wants to update it. However I would really prefer not to have to do this, since it would require me to write different functions to handle events from each slave object.
I'm currently doing something like this, with the master having separate get_value and set_value methods for each property:
class Master(object):
def __init__(self):
self.value = 0
def get_value(self):
return self.value
def set_value(self,value):
self.value = value
class Slave(object):
def __init__(self,getfunc,setfunc):
self.getfunc = getfunc
self.setfunc = setfunc
def update(self,value):
self.setfunc(value)
def run():
master = Master()
slave = Slave(master.get_value,master.set_value)
print "\nMaster: %i\nSlave: %i" %(master.value,slave.getfunc())
slave.update(1)
print "\nMaster: %i\nSlave: %i" %(master.value,slave.getfunc())
if __name__ == "__main__":
run()
What I really want to be able to do is set something like slave.bound_value, which would behave like a pointer to master.value, so that when any slave modifies its bound_value then the corresponding attribute of master is updated. I'm fully aware that Python doesn't support pointers, but I was wondering if there's a nice Pythonic way to achieve the same thing?
You can accomplish what your are asking by making bound_value a property attribute that wraps the calls to the master's get_value and set_value methods. This will make it appear that bound_value is just a member variable of the Slave class.
class Slave(object):
def __init__(self,getfunc,setfunc):
self.getfunc = getfunc
self.setfunc = setfunc
#property
def bound_value(self):
return self.getfunc()
#bound_value.setter
def bound_value(self, value):
self.setfunc(value)
Then, you can simply refer to slave.bound_value like it is a member variable whenever you want to get or set the value.
Thanks to bogatron for setting me on the right path - here's what I opted for in the end:
class Master(object):
value = 0
class Slave(object):
def __init__(self,master,attrname):
self._master = master
self._attrname = attrname
#property
def value(self):
return self._master.__getattribute__(self._attrname)
#value.setter
def value(self,newvalue):
self._master.__setattr__(self._attrname,newvalue)
def run():
master = Master()
slave = Slave(master,'value')
print master.value,slave.value
slave.value = 2
print master.value,slave.value
if __name__ == "__main__":
run()

Python extension methods

OK, in C# we have something like:
public static string Destroy(this string s) {
return "";
}
So basically, when you have a string you can do:
str = "This is my string to be destroyed";
newstr = str.Destroy()
# instead of
newstr = Destroy(str)
Now this is cool because in my opinion it's more readable. Does Python have something similar? I mean instead of writing like this:
x = SomeClass()
div = x.getMyDiv()
span = x.FirstChild(x.FirstChild(div)) # so instead of this
I'd like to write:
span = div.FirstChild().FirstChild() # which is more readable to me
Any suggestion?
You can just modify the class directly, sometimes known as monkey patching.
def MyMethod(self):
return self + self
MyClass.MyMethod = MyMethod
del(MyMethod)#clean up namespace
I'm not 100% sure you can do this on a special class like str, but it's fine for your user-defined classes.
Update
You confirm in a comment my suspicion that this is not possible for a builtin like str. In which case I believe there is no analogue to C# extension methods for such classes.
Finally, the convenience of these methods, in both C# and Python, comes with an associated risk. Using these techniques can make code more complex to understand and maintain.
You can do what you have asked like the following:
def extension_method(self):
#do stuff
class.extension_method = extension_method
I would use the Adapter pattern here. So, let's say we have a Person class and in one specific place we would like to add some health-related methods.
from dataclasses import dataclass
#dataclass
class Person:
name: str
height: float # in meters
mass: float # in kg
class PersonMedicalAdapter:
person: Person
def __init__(self, person: Person):
self.person = person
def __getattr__(self, item):
return getattr(self.person, item)
def get_body_mass_index(self) -> float:
return self.person.mass / self.person.height ** 2
if __name__ == '__main__':
person = Person('John', height=1.7, mass=76)
person_adapter = PersonMedicalAdapter(person)
print(person_adapter.name) # Call to Person object field
print(person_adapter.get_body_mass_index()) # Call to wrapper object method
I consider it to be an easy-to-read, yet flexible and pythonic solution.
You can change the built-in classes by monkey-patching with the help of forbidden fruit
But installing forbidden fruit requires a C compiler and unrestricted environment so it probably will not work or needs hard effort to run on Google App Engine, Heroku, etc.
I changed the behaviour of unicode class in Python 2.7 for a Turkish i,I uppercase/lowercase problem by this library.
# -*- coding: utf8 -*-
# Redesigned by #guneysus
import __builtin__
from forbiddenfruit import curse
lcase_table = tuple(u'abcçdefgğhıijklmnoöprsştuüvyz')
ucase_table = tuple(u'ABCÇDEFGĞHIİJKLMNOÖPRSŞTUÜVYZ')
def upper(data):
data = data.replace('i',u'İ')
data = data.replace(u'ı',u'I')
result = ''
for char in data:
try:
char_index = lcase_table.index(char)
ucase_char = ucase_table[char_index]
except:
ucase_char = char
result += ucase_char
return result
curse(__builtin__.unicode, 'upper', upper)
class unicode_tr(unicode):
"""For Backward compatibility"""
def __init__(self, arg):
super(unicode_tr, self).__init__(*args, **kwargs)
if __name__ == '__main__':
print u'istanbul'.upper()
You can achieve this nicely with the following context manager that adds the method to the class or object inside the context block and removes it afterwards:
class extension_method:
def __init__(self, obj, method):
method_name = method.__name__
setattr(obj, method_name, method)
self.obj = obj
self.method_name = method_name
def __enter__(self):
return self.obj
def __exit__(self, type, value, traceback):
# remove this if you want to keep the extension method after context exit
delattr(self.obj, self.method_name)
Usage is as follows:
class C:
pass
def get_class_name(self):
return self.__class__.__name__
with extension_method(C, get_class_name):
assert hasattr(C, 'get_class_name') # the method is added to C
c = C()
print(c.get_class_name()) # prints 'C'
assert not hasattr(C, 'get_class_name') # the method is gone from C
I'd like to think that extension methods in C# are pretty much the same as normal method call where you pass the instance then arguments and stuff.
instance.method(*args, **kwargs)
method(instance, *args, **kwargs) # pretty much the same as above, I don't see much benefit of it getting implemented in python.
After a week, I have a solution that is closest to what I was seeking for. The solution consists of using getattr and __getattr__. Here is an example for those who are interested.
class myClass:
def __init__(self): pass
def __getattr__(self, attr):
try:
methodToCall = getattr(myClass, attr)
return methodToCall(myClass(), self)
except:
pass
def firstChild(self, node):
# bla bla bla
def lastChild(self, node):
# bla bla bla
x = myClass()
div = x.getMYDiv()
y = div.firstChild.lastChild
I haven't test this example, I just gave it to give an idea for who might be interested. Hope that helps.
C# implemented extension methods because it lacks first class functions, Python has them and it is the preferred method for "wrapping" common functionality across disparate classes in Python.
There are good reasons to believe Python will never have extension methods, simply look at the available built-ins:
len(o) calls o.__len__
iter(o) calls o.__iter__
next(o) calls o.next
format(o, s) calls o.__format__(s)
Basically, Python likes functions.

Virtual classes: doing it right?

I have been reading documentation describing class inheritance, abstract base classes and even python interfaces. But nothing seams to be exactly what I want. Namely, a simple way of building virtual classes. When the virtual class gets called, I would like it to instantiate some more specific class based on what the parameters it is given and hand that back the calling function. For now I have a summary way of rerouting calls to the virtual class down to the underlying class.
The idea is the following:
class Shape:
def __init__(self, description):
if description == "It's flat": self.underlying_class = Line(description)
elif description == "It's spiky": self.underlying_class = Triangle(description)
elif description == "It's big": self.underlying_class = Rectangle(description)
def number_of_edges(self, parameters):
return self.underlying_class(parameters)
class Line:
def __init__(self, description):
self.desc = description
def number_of_edges(self, parameters):
return 1
class Triangle:
def __init__(self, description):
self.desc = description
def number_of_edges(self, parameters):
return 3
class Rectangle:
def __init__(self, description):
self.desc = description
def number_of_edges(self, parameters):
return 4
shape_dont_know_what_it_is = Shape("It's big")
shape_dont_know_what_it_is.number_of_edges(parameters)
My rerouting is far from optimal, as only calls to the number_of_edges() function get passed on. Adding something like this to Shape doesn't seam to do the trick either:
def __getattr__(self, *args):
return underlying_class.__getattr__(*args)
What I am doing wrong ? Is the whole idea badly implemented ? Any help greatly appreciated.
I agree with TooAngel, but I'd use the __new__ method.
class Shape(object):
def __new__(cls, *args, **kwargs):
if cls is Shape: # <-- required because Line's
description, args = args[0], args[1:] #  __new__ method is the
if description == "It's flat": # same as Shape's
new_cls = Line
else:
raise ValueError("Invalid description: {}.".format(description))
else:
new_cls = cls
return super(Shape, cls).__new__(new_cls, *args, **kwargs)
def number_of_edges(self):
return "A shape can have many edges…"
class Line(Shape):
def number_of_edges(self):
return 1
class SomeShape(Shape):
pass
>>> l1 = Shape("It's flat")
>>> l1.number_of_edges()
1
>>> l2 = Line()
>>> l2.number_of_edges()
1
>>> u = SomeShape()
>>> u.number_of_edges()
'A shape can have many edges…'
>>> s = Shape("Hexagon")
ValueError: Invalid description: Hexagon.
I would prefer doing it with a factory:
def factory(description):
if description == "It's flat": return Line(description)
elif description == "It's spiky": return Triangle(description)
elif description == "It's big": return Rectangle(description)
or:
def factory(description):
classDict = {"It's flat":Line("It's flat"), "It's spiky":Triangle("It's spiky"), "It's big":Rectangle("It's big")}
return classDict[description]
and inherit the classes from Shape
class Line(Shape):
def __init__(self, description):
self.desc = description
def number_of_edges(self, parameters):
return 1
Python doesn't have virtual classes out of the box. You will have to implement them yourself (it should be possible, Python's reflection capabilities should be powerful enough to let you do this).
However, if you need virtual classes, then why don't you just use a programming language which does have virtual classes like Beta, gBeta or Newspeak? (BTW: are there any others?)
In this particular case, though, I don't really see how virtual classes would simplify your solution, at least not in the example you have given. Maybe you could elaborate why you think you need virtual classes?
Don't get me wrong: I like virtual classes, but the fact that only three languages have ever implemented them, only one of those three is still alive and exactly 0 of those three are actually used by anybody is somewhat telling …
You can change the class with object.__class__, but it's much better to just make a function that returns an instance of an arbitrary class.
On another note, all class should inherit from object unless you use using Python 3, like this, otherwise you end up with an old-style class:
class A(object):
pass

Categories