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
How to Find String B Missing Characters Based on String a and Add Them to String B
How to Update the Constant Height Constraint of a Uiview Programmatically
Why Is an Observedobject Array Not Updated in My Swiftui Application
Go to a New View Using Swiftui
Rounding a Double Value to X Number of Decimal Places in Swift
How to Pop to the Root View Using Swiftui
How to Use Instance Method as Callback For Function Which Takes Only Func or Literal Closure
Swift Generic Coercion Misunderstanding
How Does String Substring Work in Swift
Wait Until Swift For Loop With Asynchronous Network Requests Finishes Executing
Creating Custom Tableview Cells in Swift
Attach Parameter to Button.Addtarget Action in Swift
Uncaught Error/Exception Handling in Swift
Share Data Between Main App and Widget in Swiftui For iOS 14