Property Getters and Setters

Using @property versus getters and setters

Prefer properties. It's what they're there for.

The reason is that all attributes are public in Python. Starting names with an underscore or two is just a warning that the given attribute is an implementation detail that may not stay the same in future versions of the code. It doesn't prevent you from actually getting or setting that attribute. Therefore, standard attribute access is the normal, Pythonic way of, well, accessing attributes.

The advantage of properties is that they are syntactically identical to attribute access, so you can change from one to another without any changes to client code. You could even have one version of a class that uses properties (say, for code-by-contract or debugging) and one that doesn't for production, without changing the code that uses it. At the same time, you don't have to write getters and setters for everything just in case you might need to better control access later.

when to use getter and setter with property?

You should generally prefer to use "protected" variables (such as those starting with _) with properties (not separate functions that users need to call, that's just clunky), as it confers some advantages. This encapsulation is very handy as it:

  • lets you control the internal data completely, such as preventing people entering ages like -42 (which they will do if they can); and
  • lets you change the underlying implementation in any manner you want, without affecting clients.

For example on that last point, you may want to maintain a separate structure of all names and simply store references to those names in your Person class. This can allow you to store many more names, as the surname "Von Grimmelshausen" would be stored once (in the separate structure) and as much smaller indexes in all the Person objects that use it.

You can then totally change the naive getter from:

@property
def surname(self):
return self._surname

to:

@property
def surname(self):
return self._surname_db[self._surname_index]

without any changes to clients.

javascript getter and setter within object property within class

I'm trying to do is get that same functionality, but where the property is not loose on the top level of the class, but within an object property inside the class.

Then you need to create that object somewhere first. As you will want to have a separate object (with different property values) for each instance, create that instance-specific object in the constructor:

class B {
#innerObjProp;
constructor() {
this.#innerObjProp = {};
}
}

and then define your getters/setters in that object, not on the class level, with the usual ES5 syntax for getters/setters in object literals:

class B {
#innerObjProp;
constructor() {
let b = "b"; // a local variable as a place to store the value
this.#innerObjProp = {
get b() {
// do some stuff that b depends on...
// ...
// ... and then ultimately return it:
return b;
},
set b(arg) {
// do some stuff that depends on b or vice versa...
// ...
// ... and then ultimately set b to something:
b = something();
}
};
}
}

Notice that this is a code smell. If your class has grown so large that you don't want to put some things at its "top level", something is wrong with your design, and you should consider splitting the class into multiple smaller classes.

Property getters and setters

Setters and Getters apply to computed properties; such properties do not have storage in the instance - the value from the getter is meant to be computed from other instance properties. In your case, there is no x to be assigned.

Explicitly: "How can I do this without explicit backing ivars". You can't - you'll need something to backup the computed property. Try this:

class Point {
private var _x: Int = 0 // _x -> backingX
var x: Int {
set { _x = 2 * newValue }
get { return _x / 2 }
}
}

Specifically, in the Swift REPL:

 15> var pt = Point()
pt: Point = {
_x = 0
}
16> pt.x = 10
17> pt
$R3: Point = {
_x = 20
}
18> pt.x
$R4: Int = 10

Difference between using getter&setter and public properties

A getter/setter is generally useful for when, on property access, the class wants to do something in addition to simply setting/retrieving the data. For example:

class MyClass {  constructor() {    this.setHistory = [];  }  set item(newVal) {    this.setHistory.push(newVal);    this._item = newVal;  }  get item() {    return this._item;  }}
const f = new MyClass();f.item = 'foo';f.item = 'bar';console.log(f.setHistory);

Using getter and setter with three attributes

There is flaw in your implementation.

Setting a depends on b being already set. If you swap the 2 assignment statements in the __init__ it will solve your current problem. However note there is big flaw in your implementation. If you change b that change will not be reflected in c.

There is no need to use getters and setters for a and b.

class Test:
def __init__(self, p1=50, p2=20):
self.a = p1
self.b = p2


@property
def c(self):
return self.b - self.a // 5

Properties (getters and setters) in Ceylon

Getters are declared like defining a function with no parameter list. The getter body then behaves like a normal function and must return the calculated value of the property.

variable String local_var = "Hello world!";

// Getter
String name1 {
return local_var;
}

// Also getter, using functional syntax for body
String name2 => local_var;

Setters are declared using the assign keyword. The setter body then behaves like a void function, performing whatever mutation of the local environment is appropriate and must not return a value. The incoming value being assigned can be referred to in the body via the name of the property.

// Setter
assign name1 {
local_var = name1; // name1 here is value being assigned
}

// Also setter, using modified functional syntax
assign name2 => local_var = name2;

Unlike most programming languages, properties can be top level members of the package, not just members of a class:

class Circle(shared variable Float radius) {
// Class-level getter
shared Float area {
return pi * radius ^ 2;
}

// Class-level setter
assign area {
radius = sqrt(area / pi);
}
}

Circle window = Circle(1.0);

// Top-level getter
Circle outer_window => Circle(window.radius * 2);

// Top-level setter
assign outer_window => window.radius = outer_window.radius / 2;

Dynamic Property Getter and Setter

Well, you can do what you want to some extent, but in Python, properties are looked-up based in the class of an object, which means you would need to create a separate class for each combination of attributes you wanted (which must be called to create an instance of it).

Explanation

In the code below defines a function named make_class() to replace the generic A class in your question. It handles mutable default arguments properly by automatically detecting them and assigning copies of their values to the class instance attributes when one is created (preventing all instance from sharing a single class-level attribute).

from collections.abc import MutableMapping, MutableSequence, MutableSet
import copy

MUTABLES = MutableMapping, MutableSequence, MutableSet # Mutable containers

def make_class(classname, **options):
"""Return a class with the specified attributes implemented as properties.
"""
class Class:
def __init__(self):
"""Initialize instance attribute storage name values."""
for key, value in options.items():
if isinstance(value, MUTABLES): # Mutable?
value = copy.deepcopy(value) # Avoid mutable default arg.
setattr(self, '_' + key.lower(), value)

for key, value in options.items(): # Create class' properties.
setattr(Class, key.lower(), managed_attribute(key))

Class.__name__ = classname
return Class

def managed_attribute(name):
"""Return a property that stores values under a private non-public name."""
storage_name = '_' + name.lower()

@property
def prop(self):
return getattr(self, storage_name)

@prop.setter
def prop(self, value):
setattr(self, storage_name, value)

return prop


A = make_class('A', dimension=2, name="Unknown Alphabet")
a = A()
print(a.name) # -> Unknown Alphabet
print(a.dimension) # -> 2


SantaClaus = make_class('SantaClaus', location="North Pole", vehicle="Teleportation",
naughty_kids_list=[])

santa_clause = SantaClaus()
print(santa_clause.location) # -> North Pole
print(santa_clause.vehicle) # -> Teleportation
print(santa_clause.naughty_kids_list) # -> []



Related Topics



Leave a reply



Submit