With a boring class, object instance attribute shadow class attributes:
class C(object):
a="class_a"
def __init__(self, a):
self.a = a
c = C(a="obja")
print c.a # obja
But if my class attributes are declared in a named_tuple base:
class C(collections.namedtuple("CBase", ['a', ])):
a="class_a"
c = C(a="obja")
print c.a # class_a !!??!
... so, declaring my instance attribute through the name tuple causes that attribute to be shadowed by the class attribute ... which not what you'd expect.
Why is this?
namedtuple "attributes" are implemented as descriptors (specifically, propertys) on the class itself, not attributes in the traditional sense (all the actual data is stored in unnamed indices of the tuple). In this case, the namedtuple (roughly) defines:
#property
def a(self):
return self[0]
Since the property is a class level attribute, when you define a on the subclass, it shadows equivalent definitions in the parent class.
Related
class MyClass():
def __init__(self):
self.attribute_1 = "foo"
self.attribute_2 = "bar"
#property
def attribute_1(self):
return self._attribute_1
#attribute_1.setter
def attribute_1(self,s):
self._attribute_1 = s
#property
def attribute_2(self):
return self._attribute_2
#attribute_2.setter
def attribute_2(self,s):
self._attribute_2 = s
>>> ob = MyClass()
>>> ob.attribute_1 = 'fizz' #Ok
>>> ob.atribute_1 = 'buzz' #want to throw an exception because this has no setter or #property def
I would like my class to complain if we try and set an attribute that has not been decorated with property and a setter. I have tried using slots but can't get it working with the property decorator. 'attribute' in __slots__ conflicts with class variable
Any thoughts?
__slots__ should contain all instance variables, in your case it is _attribute_1 and _attribute_2 (the ones with underscores used internally) so just do that:
class MyClass():
__slots__ = ["_attribute_1", "_attribute_2"]
pass # rest of implementation
note that if your property is just directly forwarding you might as well just put the public variables in the slots and only have properties for fields that need more validation or other logic. having slots is effectively a property really:
>>> MyClass._attribute_1
<member '_attribute_1' of 'MyClass' objects>
I want to access an attribute of the class instance that called a function :
for example:
class A:
def a(self):
return B.q
class B:
q=0
def b(self):
M=A()
return M.a()
c=B()
c.q = 6
print(c.b())
the output will be 0 but I want it to print the q attribute of the instance c of the class B which has the value 6
Pass the instance as a parameter.
class A:
def a(self, b):
return b.q
class B:
q=0
def b(self):
M=A()
return M.a(self)
c=B()
c.q = 6
print(c.b())
This appears to be very bad program design. What are you trying to accomplish with this?
You have a class attribute and an instance attribute -- in that class -- of the same name, q. This makes your code difficult to follow and to maintain.
You have method B.b instantiate an instance of class A. You immediately call A.a, which has been assigned the questionable task of returning an instance attribute from and object of class B.
Clean up your design.
Use init appropriately for each class.
Design your class methods to work appropriately with the characteristics of instances of that class. Your question strongly suggests that your design is not yet clean in your mind, nor in code.
define an init method so that you can work with the instance attributes instead of the class variable
class A:
def a(self):
return B.q
class B:
def __init__(self):
self.q = 0
def b(self):
M=A()
return M.a()
c=B()
c.q = 6
print(c.b())
I have a class with __slots__:
class A:
__slots__ = ('foo',)
If I create a subclass without specifying __slots__, the subclass will have a __dict__:
class B(A):
pass
print('__dict__' in dir(B)) # True
Is there any way to prevent B from having a __dict__ without having to set __slots__ = ()?
The answer of #AKX is almost correct. I think __prepare__ and a metaclass is indeed the way this can be solved quite easily.
Just to recap:
If the namespace of the class contains a __slots__ key after the class body is executed then the class will use __slots__ instead of __dict__.
One can inject names into the namespace of the class before the class body is executed by using __prepare__.
So if we simply return a dictionary containing the key '__slots__' from __prepare__ then the class will (if the '__slots__' key isn't removed again during the evaluation of the class body) use __slots__ instead of __dict__.
Because __prepare__ just provides the initial namespace one can easily override the __slots__ or remove them again in the class body.
So a metaclass that provides __slots__ by default would look like this:
class ForceSlots(type):
#classmethod
def __prepare__(metaclass, name, bases, **kwds):
# calling super is not strictly necessary because
# type.__prepare() simply returns an empty dict.
# But if you plan to use metaclass-mixins then this is essential!
super_prepared = super().__prepare__(metaclass, name, bases, **kwds)
super_prepared['__slots__'] = ()
return super_prepared
So every class and subclass with this metaclass will (by default) have an empty __slots__ in their namespace and thus create a "class with slots" (except the __slots__ are removed on purpose).
Just to illustrate how this would work:
class A(metaclass=ForceSlots):
__slots__ = "a",
class B(A): # no __dict__ even if slots are not defined explicitly
pass
class C(A): # no __dict__, but provides additional __slots__
__slots__ = "c",
class D(A): # creates normal __dict__-based class because __slots__ was removed
del __slots__
class E(A): # has a __dict__ because we added it to __slots__
__slots__ = "__dict__",
Which passes the tests mentioned in AKZs answer:
assert "__dict__" not in dir(A)
assert "__dict__" not in dir(B)
assert "__dict__" not in dir(C)
assert "__dict__" in dir(D)
assert "__dict__" in dir(E)
And to verify that it works as expected:
# A has slots from A: a
a = A()
a.a = 1
a.b = 1 # AttributeError: 'A' object has no attribute 'b'
# B has slots from A: a
b = B()
b.a = 1
b.b = 1 # AttributeError: 'B' object has no attribute 'b'
# C has the slots from A and C: a and c
c = C()
c.a = 1
c.b = 1 # AttributeError: 'C' object has no attribute 'b'
c.c = 1
# D has a dict and allows any attribute name
d = D()
d.a = 1
d.b = 1
d.c = 1
# E has a dict and allows any attribute name
e = E()
e.a = 1
e.b = 1
e.c = 1
As pointed out in a comment (by Aran-Fey) there is a difference between del __slots__ and adding __dict__ to the __slots__:
There's a minor difference between the two options: del __slots__ will give your class not only a __dict__, but also a __weakref__ slot.
How about a metaclass like this and the __prepare__() hook?
import sys
class InheritSlots(type):
def __prepare__(name, bases, **kwds):
# this could combine slots from bases, I guess, and walk the base hierarchy, etc
for base in bases:
if base.__slots__:
kwds["__slots__"] = base.__slots__
break
return kwds
class A(metaclass=InheritSlots):
__slots__ = ("foo", "bar", "quux")
class B(A):
pass
assert A.__slots__
assert B.__slots__ == A.__slots__
assert "__dict__" not in dir(A)
assert "__dict__" not in dir(B)
print(sys.getsizeof(A()))
print(sys.getsizeof(B()))
For some reason, this still does print 64, 88 – maybe an inherited class's instances are always a little heavier than the base class itself?
From this answer to "what is a metaclass?" I got this:
You write class Foo(object) first, but the class object Foo is not created in memory yet.
Python will look for metaclass in the class definition. If it finds it, it will use it to create the object class Foo. If it doesn't, it will use type to create the class.
Having tested it, it seems that the attributes of the class are instantiated before the constructor of the class is run. What am I misunderstanding?
Test code:
class meta(type):
def __init__(cls, name, bases, dic):
type.__init__(cls, name, bases, dic)
print hasattr(cls, "a")
cls.a = "1"
class A(object):
a = "a"
__metaclass__ = meta
class B(object):
__metaclass__ = meta
class C(object):
__metaclass__ = meta
a = "a"
print A.a
print B.a
print C.a
Output:
True
False
True
1
1
1
The class body is run before the class is constructed, yes.
The body of the class provides a temporary namespace, and all local names in that namespace are given as a dictionary to construct the class object, together with the base classes and a name for the class.
You can do this with the type() constructor too:
>>> Foo = type('Foo', (), {'a': 1})
>>> Foo.a
1
The class body is basically executed as a function, with the local namespace of that function being used to create the class attributes, the 3rd argument to type() above.
In python 3 you have a little more influence on that process with the __prepare__ hook on a metaclass. __prepare__ should be a class method that returns a initial namespace for the class body; use it to inject extra names into the generated class body before the class body is executed:
class MyMeta(type):
#classmethod
def __prepare__(mcl, name, bases):
return {'a': 1}
If I create a class A as follows:
class A:
def __init__(self):
self.name = 'A'
Inspecting the __dict__ member looks like {'name': 'A'}
If however I create a class B:
class B:
name = 'B'
__dict__ is empty.
What is the difference between the two, and why doesn't name show up in B's __dict__?
B.name is a class attribute, not an instance attribute. It shows up in B.__dict__, but not in b = B(); b.__dict__.
The distinction is obscured somewhat because when you access an attribute on an instance, the class dict is a fallback. So in the above example, b.name will give you the value of B.name.
class A:
def _ _init_ _(self):
self.name = 'A'
a = A()
Creates an attribute on the object instance a of type A and it can therefore be found in: a.__dict__
class B:
name = 'B'
b = B()
Creates an attribute on the class B and the attribute can be found in B.__dict__ alternatively if you have an instance b of type B you can see the class level attributes in b.__class__.__dict__