python


Python __get__ differences between static instance and member


I'm having trouble understanding what is going on to make a difference in static object and member objects (those created in constructor).
The following will run the overridden get():
class A(object):
class B(object):
def __init__(self, initval=None, name='var'):
self.val = initval
self.name = name
def __get__(self, obj, objtype):
print('B Retrieving', self.name)
return self.val
b = B(10, 'var "b"')
But, if I pull b in to the constructor it does not:
class A(object):
class B(object):
def __init__(self, initval=None, name='var'):
self.val = initval
self.name = name
def __get__(self, obj, objtype):
print('B Retrieving', self.name)
return self.val
def __init__(self)):
self.b = A.B(10, 'var "b"')
I really want to make this work in the latter and maybe this isn't the right way to do it.
Can someone please explain what is going on here in a call to print(a.b) where a = A()?
Also, is there a way to have print(a.b) call a member function from b?
Your b object is a descriptor. That means that Python treats it differently than most other objects when it is bound as a class variable. Specifically, in your class-variable code, A().b gets turned into the function call A.__class__.__dict__["b"].__get__(A(), A). Python uses descriptors all over internally. It's part of how method binding and most __magic__ methods work.
When a descriptor is stored as an instance variable no special treatment is given. Lookup up a instance variable that's a descriptor just gets you the descriptor object, not the result of calling its __get__ method.
If you need to be able to set the value that your descriptor returns on a per-instance basis, you may want to have the descriptor check an attribute on the instance it's been called on, rather than an attribute on itself:
class B(object):
def __init__(self, name='var'):
self.name = name
def __get__(self, obj, objtype):
print('B Retrieving', self.name)
return obj._bval # lookup the value on the object, not on the descriptor
class A(object):
b = B() # assign the descriptor as an class variable
def __init__(self):
self._bval = 10 # initialize the value
Note that I've unnested your classes, mostly just for clarity. It wasn't strictly wrong to have the B class defined within A, but it was confusing and offered no real benefits over making B a top-level class.
By implementing __get__, you turned your class B into a descriptor class. Descriptors are objects that take care of attribute access by performing custom logic on an instance.
In order to make descriptors work, you need to declare them as members on the type. Only then will Python call __get__ and __set__ methods of the object properly.
The reason why doing self.b = SomeDescriptor() does not work is because by assinging something to self.b, you are directly changing the object’s underlying __dict__:
>>> class A(object): pass
>>> x = A()
>>> x.b = B(10, '')
>>> x.__dict__
{'b': <__main__.B object at 0x000000437141F208>}
As you can see x.b has the value of that B object. That is the descriptor object. And when you just try to access x.b, you just get that descriptor object back. The __get__ is never called.
When you set the descriptor on the type however, a member b does not exist in the object’s __dict__, so Python will look further up in the inheritance chain and will find the descriptor object for b at which point it will also execute the descriptor:
>>> class A(object): pass
>>> A.b = B(10, '')
>>> x = A()
>>> x.__dict__
{}
>>> x.b
B Retrieving
10

Related Links

Python : splitting string with multiple characters
Python Function Decoration In This Instance
Convert mp3 to wav on the fly using ffmpeg in Python
Python: How to get the output from gsmsmsd Daemon?
saving scrapped items to json/csv/xml file using scrapy
Ban reason remove
PyInstaller failing to include some modules from C:\Python27\Lib
Python pandas Removing UserWarning and looping efficiently
Plotting a simple graph
Knowing an item's location in an array [duplicate]
Getting the number of digits of nonnegative integers (Python) [duplicate]
How to mask clouds from Python numpy array for a linear regression model?
How to insert an item into a sublist if sublist is a certain length?
Can't get un-stacked bar plot in python pandas
how can i use python to deploy proxies from the command line
HTMLTestRunner not working

Categories

HOME
xbox-live
sql-server
app-inventor
ibm-watson-cognitive
admin-on-rest
angular-cli
sed
raspbian
bower
boost-thread
fparsec
json-ld
qpython3
thunderbird-addon
extract
webdav
phonegap-cli
spring-cloud-contract
codeblocks
netflix-feign
diagram
jboss-eap-7
data-synchronization
qt-installer
gwtp
x-frame-options
titan
riak-ts
grub2
pycrypto
fop
nmf
net-snmp
rhmap
maximo
gzip
datadog
superscript
encase
preg-grep
npm-publish
swagger-editor
magiczoomplus
nashorn
react-native-router-flux
stereo-3d
filepath
recycle-bin
production-environment
amazon-machine-learning
rhel6
decompress
google-maps-ios
volume
jexl
execl
pycurl
iron.io
shinyjs
android-navigationview
firepath
spoofing
instruments
nofollow
metalsmith
gradle-eclipse
nssplitview
fps
codesign
picking
logcat
aerogear
yoothemes
altbeacon
loose-typing
kendo-menu
retro-computing
webhdfs
urn
team-build
castle-windsor-3
harp
mdm-zinc
lexicographic
named-ranges
alphablending
cpu-speed
qtestlib
scala-2.11
sid
facebook-wall
adaptive-compression
slick-2.0
mbox
internal
gfs
confusion-matrix
nscolor
stagefright
manage.py
mstsc
sharpmap
graph-coloring
prng
gdataxml
pstree
gjs
maven-ant-tasks
v4l
goliath
dcpu-16
noir
ruby-debug
drawtext
rtsp-client
webrat
swfloader
callgrind
evb
data-execution-prevention

Resources

Mobile Apps Dev
Database Users
javascript
java
csharp
php
android
MS Developer
developer works
python
ios
c
html
jquery
RDBMS discuss
Cloud Virtualization
Database Dev&Adm
javascript
java
csharp
php
python
android
jquery
ruby
ios
html
Mobile App
Mobile App
Mobile App