How to access class instance attributes indirectly?
Use the getattr()
function to get an attribute of an object if you have its name in a variable, and setattr()
to set it in similar circumstances.
class Test:
def __init__(self):
self.testval = 0
test=Test()
A = "testval"
print(test.testval)
setattr(test, A, 1)
print(test.testval)
You can also define your class to have a __setitem__
method; then you can use dictionary-like syntax to set attributes.
class Test:
def __init__(self):
self.testval = 0
def __setitem__(self, key, value):
setattr(self, key, value)
test=Test()
A = "testval"
print(test.testval)
test[A] = 1
print(test.testval)
Finally (well, there are other ways you can handle this, but I'm only going to mention one more)... finally, you could make a class that holds a reference to an object and an attribute name. This is convenient when you want to pass around such references.
class Test:
def __init__(self):
self.testval = 0
class IndirectAttribute:
def __init__(self, obj, attr):
self.obj = obj
self.attr = attr
def set(self, value):
setattr(self.obj, self.attr, value)
test = Test()
A = IndirectAttribute(test, "testval")
print(test.testval)
A.set(1)
print(test.testval)
Can I access a class variable from an instance?
Use self.__class__.classAttr
. This should work for both old & new style classes.
Why does getting a class property from an instance raise an AttributeError?
That is due to the way attribute lookup works. Upon trying to retrieve an
attribute in an instance, Python does:
call the instance's class
__getattribute__
(not the metaclass__getattribute__
), which in turn will:Check the instance's class, and its superclasses following the method resolution order, for the attribute. It does not proceed to the class of the class (the metaclass) - it follows the inheritance chain..
- if the attribute is found in the class and it has a
__get__
method, making it a descriptor: the__get__
method is called with the instance and its class as parameters - the returned value is used as the attribute value- note: for classes using
__slots__
, each instance attribute is recorded in a special descriptor - which exists in the class itself and has a__get__
method, so instance attributes for slotted classes are retrieved at this step
- note: for classes using
- if there is no
__get__
method, it just skips the search at the class.
- if the attribute is found in the class and it has a
check the instance itself: the attribute should exist as an entry in the instances
__dict__
attribute. If so, the corresponding value is returned. (__dict__
is an special attribute which is accessed directly in cPython, but would otherwise follow the descriptor rule for slotted attributes, above)The class (and its inheritance hierarchy) are checked again for the attribute, this time, regardless of it having a
__get__
method. If found, that is used. This attribute check in the class is performed directly in the class and its superclasses__dict__
, not by calling their own__getattribute__
in a recursive fashion. (*)
The class (or superclasses)
__getattr__
method is called, if it exists, with the attribute name. It may return a value, or raise AttributeError(__getattr__
is a different thing from the low level__getattribute__
, and easier to customize)AttributeError is raised.
(*) This is the step that answers your question: the metaclass is not searched for an attribute in the instance. In your code above, if you try to use A.cls_prop
as a property, instead of A().cls_prop
it will work: when retrieving an attribute directly from the class, it takes the role of "instance" in the retrieval algorithm above.
(**) NB. This attribute retrieval algorithm description is fairly complete, but for attribute assignment and deletion, instead of retrieval, there are some differences for a descriptor, based on whether it features a __set__
(or __del__
) method, making it a "data descriptor" or not: non-data descriptors (such as regular methods, defined in the instance's class body), are assigned directly on the instance's dict, therefore overriding and "switching off" a method just for that instance. Data descriptors will have their __set__
method called.
how to make properties defined in the metaclass work for instances:
As you can see, attribute access is very customizable, and if you want to define "class properties" in a metaclass that will work from the instance, it is easy to customize your code so that it works. One way is to add to your baseclass (not the metaclass), a __getattr__
that will lookup custom descriptors on the metaclass and call them:
class Base(metaclass=Meta):
def __getattr__(self, name):
metacls = type(cls:=type(self))
if hasattr(metacls, name):
metaattr = getattr(metacls, name)
if isinstance(metaattr, property): # customize this check as you want. It is better not to call it for anything that has a `__get__`, as it would retrieve metaclass specific stuff, such as its __init__ and __call__ methods, if those were not defined in the class.
attr = metaattr.__get__(cls, metacls)
return attr
return super().__getattr__(name)
and:
In [44]: class A(Base):
...: pass
...:
In [45]: a = A()
In [46]: a.cls_prop
Out[46]: True
Python - how to access instance properties in parent classes with super(class, self)?
The self
always refers to one and the same object. When you do super().__init__()
, the self
in the parent's __init__
is your instance of Child
. GrandParent.__init__
just sets an attribute on that object. By chaining all those __init__
s, you're in effect just doing this:
o = object()
o._name = 'grand parent'
o._name = 'parent'
o._name = 'child'
You're just overwriting the _name
attribute, of which there's only one. All the different @property
s just return the value of this one _name
attribute, of which your object only has one, and whose value is 'child'
.
If you want your object to have a separate _name
attribute per parent, you will actually have to create separate attributes. The easiest way is probably with Python's double-underscore name mangling a.k.a. "private attributes":
>>> class A:
... def __init__(self):
... self.__foo = 'bar'
... @property
... def foo(self):
... return self.__foo
...
>>> class B(A):
... def __init__(self):
... super().__init__()
... self.__foo = 'baz'
... @property
... def foo(self):
... return super().foo
...
>>> B().foo
'bar'
>>> vars(B())
{'_A__foo': 'bar', '_B__foo': 'baz'}
The actual attributes are named _A__foo
and _B__foo
and thereby don't conflict with each other.
How do I access a property on a base class that is for a web component?
You can't access Navbar.ns
because you aren't creating an instance (object) of Navbar, and this.ns
will be applied for each new
call to navbar, e.g. const navbar = new Navbar(); navbar.ns; // <-- wce
. You aren't creating an instance of Navbar
, so you can create a static field, which allows you to access a field without creating a class instance.
In base.js
:
class Base extends HTMLElement {
constructor() {
super();
}
static get ns() {
return 'wce';
}
}
export default Base;
static
allows us to access class fields without, and only without creating a new
instance.
Now, when you call NavBar.ns
it will return "wce"
using a getter.
However, you also wanted to be able to access .ns
when you (customElements.define
) create a new instance. You'll have to set an addition this
call:
class Base extends HTMLElement {
constructor() {
super();
this.ns = 'hello';
}
static get ns() {
return 'world';
}
}
export default Base;
In your case you can change both "hello" and "world" to "wce" if you want them to "work the same way."
Now, let's say you want to access ns
, if you aren't creating an instance you would do:
NavBar.ns; // <-- "world"
But if you were creating an instance (like in customElements.define
), you use the new
operator to access this.ns
:
const navbar = new NavBar();
navbar.ns; // "hello"
(I used "hello" and "world" instead of "wce" just for the illustration.)
Now with the added code you could use it as in your example:
/* "wce-navbar" */
customElements.define(`${NavBar.ns}-navbar`, NavBar);
Some docs about static
.
ES6 class / instance properties
I don't get this; static variables in a class based language would appear to serve the same purpose as properties defined on the prototype in JS.
No, static variables are more like properties defined on the constructor. Variables on the prototype would be closer to instance variables, but they’re not nearly as useful because they’re shared between instances. (So if you modify a mutable property on the prototype, it will be reflected in all other instances of that type.)
This also answers your other questions, I think, but to recap:
variables on the prototype are not like static variables in that they appear to belong to every instance rather than just the class
variables on the prototype are not like instance variables in that each instance of the class doesn’t have its own instance of the variable
therefore, variables on the prototype are not that useful and they should be assigned to in the constructor (instance variables) or assigned to the constructor (class variables)
they’re also properties, not variables
And a non-ES6-sugared example:
function Something() {
this.instanceProperty = 5;
}
Something.staticProperty = 32;
Something.prototype.prototypeProperty = 977;
var s = new Something();
console.log(s.instanceProperty); // 5
console.log(s.prototypeProperty); // 977? If you want a class property,
// this is not what you want
console.log(s.staticProperty); // undefined; it’s not on the instance
console.log(Something.staticProperty); // 32; rather, it’s on the class
console.log(Something.prototypeProperty); // undefined; this one isn’t
Related Topics
Swift: How to Add a Class Method in 'string" Extension
Nsdatepicker in Nsstatusbar Nssmenuitem Not Receiving Input
Preferredstatusbarupdateanimation Being Ignored
Member Operator '==' Must Have at Least One Argument of Type
Is The for Loop Condition Evaluated Each Loop in Swift
Uitextview Contentoffset Is Set
Swift 4 Date Picker Wrong Value Using Minuteinterval
How to Group Items in a Nspopupbutton
How to Observe Object's Property in Rxswift
More Precision Than Double in Swift
Avaudioconverter with Avaudioconverterinputblock Stutters Audio After Processing
Swift Nwlistener Listen, Cancel, and Relisten Successfully
Pass Type to Generic Function and Compare
Nscalendar in Swift - Init Can Return Nil, But Isn't Optional
How to Restore In-App Purchases Correctly
Instantiating a Nested Class Using Nsclassfromstring in Swift
How to Write to a Variable from Within The Firebase Getdocument Function (Swift)