I have browsed the web and pydoc to find my answer without success.
My issue is the following:
I want to define a class with properties, as I would do habitually.
class Container(object):
def __init__(self, content):
assert isinstance(content, dict), "The container can only contain a dictionary"
self._content = content
#property
def name():
try:
return self._content["its_name"]
except KeyError:
raise AttributeError
Now, to access the content's field "its_name", I can use container.name, with a slight modification between the field's name and the attribute's.
I would like to have a default behavior when no specific getter property is set.
I mean, if I call container.description, I want my class to try returning self._content["description"], and throw an AttributeError if there is no such key.
While still calling the specific property for cases like container.name.
Thanks in advance for your help.
This is what the __getattr__ special method is for:
def __getattr__(self, attrname):
# Only called if the other ways of accessing the attribute fail.
try:
return self._content[attrname]
except KeyError:
raise AttributeError
Note that if for some reason you try to retrieve an unknown attribute when the _content attribute doesn't exist, the line
return self._content[attrname]
will recursively invoke __getattr__ in an attempt to get the _content attribute, and that call will call __getattr__, and so on until stack overflow.
Related
I am reading mmdetecton project on github, and I'm so confused with code(I screened out all other irrelevant factors.):
class A:
def __init__(self, a):
self.a = a
self._dict_test = {"b": a}
def __getattr__(self, item):
print("You call __getattr__ !")
return getattr(self._dict_test, item)
test = A(2)
judge = test.get("b", False)
print("a is", test.a)
print("judge is ", judge)
print(test.__dict__)
I didn't declare the get() function in the class, I checked the documentation where it says:
Attribute references are translated to lookups in this dictionary, e.g., m.x is equivalent to m.dict["x"].
So,
(1)I wonder how should my code be interpreted? is it test.__dict__.get(), or test.__dict__['get()']
Has this ever happened to anyone?
(2)why getattr is invoked???
I check the doc where it says
getattr Called when the default attribute access fails with an AttributeError
but isn't get() the dict's function ? why get() fails with an AttributeError?
I am searching for a long time on net. But no use, and thanks in advance!
If you remove the __getattr__ method, you will see an exception:
judge = test.get("b", False)
AttributeError: 'A' object has no attribute 'get'
because there is no get defined in the A class.
With the __getattr__ method, test.get evaluates to getattr(self._dict_test, item) inside that method which is getattr(test._dict_test, "get") which is test._dict_test.get which is the usual dict.get method for test._dict_test, not test.__dict__.
I am creating a class for retrieving details about a computer such as host_name, kernel_version, bios_version, and so on. Some details are more expensive to collect than others so I have a get_* function to retrieve them, but keep the results cached in the object if they are needed again. I am considering implementing them to look like a dictionary object so the kernel version can be retrieved as so:
system = System()
kver = system['kernel_version']
This will call the instance method get_kernel_version(self) internally to retrieve the data. If the kernel version is retrieved a second time from the above instantiated object, it will returned the cached result from the original call to get_kernel_version(self). Note that all these key/value pairs are read-only, there are a fixed number of them based on the available get_* methods, and no new keys can be added later so it doesn't feel like a regular dictionary. There also shouldn't be a need to call something like the values() function which would simply cause all the get_* functions to be needlessly hit. Also, the syntax is a little more verbose than I'd like. Using system.kernel_version instead seems more natural for this use case.
I'm considering whether a better approach is to use dynamic attributes on a class instance. However, I need a natural way to retrieve a list of all attributes, but not the internal methods supporting them. I would probably use the __dir__ special method to return a list similar the keys() list of the dictionary. I would want to see kernel_version and host_name in the list, but not __class__ or get_kernel_version. This seems to go against recommended practice for the definition of __dir__ so I'm not sure if this is the right approach to use.
I could return a proxy class instance whose sole job calls back to a concrete class with the get_* functions when it doesn't have the appropriate attribute already defined.
Here is an example of a version I'm experimenting with implementing the dictionary approach:
class System(dict):
def __getitem__(self, key):
try:
return getattr(self, 'get_'+key)()
except AttributeError as ex:
raise KeyError(ex.message)
def __setitem__(self, key, value):
raise Exception('Read-only')
def __delitem__(self, key, value):
raise Exception('Read-only')
def keys(self):
return [ x[4:] for x in dir(self) if x.startswith('get_') ]
def get_host_name(self):
return 'localhost'
def get_kernel_version(self):
return '4.7.0'
system = System()
print repr(system.keys())
for key in system.keys():
print '{0}: {1}'.format(key, system[key])
try:
system['bios']
except Exception as ex:
print str(ex)
try:
system['kernel_version'] = '5.0'
except Exception as ex:
print str(ex)
Which produced the following output:
['host_name', 'kernel_version']
host_name: localhost
kernel_version: 4.7.0
"'System' object has no attribute 'get_bios'"
Read-only
The code above does not yet implement the caching of values yet, but that is easy to add. However, it's feeling more like I should be doing this as attributes. I am just not sure if when doing so I should abuse __dir__ to emulate the same functionality above I get with keys().
Should I stick with emulating a read-only dictionary or present a class instance with dynamic attributes?
I think sticking with the read-only dictionary subclass approach you're using is fine. However your implementation could be improved somewhat by creating a generic read-only dictionary superclass from which to derive your specific subclass, and using a metaclass to create the value returned by the keys() method. Doing both is illustrated below.
This means you don't have to "abuse" dir() (there's no such thing as a __dir__ attribute) any longer. You can also use reuse the generic MetaReadonlyDict and ReadonlyDict classes to create other similar types.
class MetaReadonlyDict(type):
def __new__(mcls, classname, bases, classdict):
classobj = type.__new__(mcls, classname, bases, classdict)
prefix = classdict['prefix']
_keys = set(name[len(prefix):] for name in classdict
if name.startswith(prefix))
setattr(classobj, 'keys', lambda self: list(_keys)) # define keys()
return classobj
class ReadonlyDict(dict):
def __getitem__(self, key):
try:
return getattr(self, self.prefix + key)()
except AttributeError as ex:
raise Exception(
"{} object has no {!r} key".format(self.__class__.__name__, key))
def __setitem__(self, key, value):
verb = "redefined" if key in self else "defined"
raise Exception(
"{} object is read-only: {!r} "
"key can not be {}".format(self.__class__.__name__, key, verb))
def __delitem__(self, key):
raise Exception(
"{} object is read-only: {!r} "
"key can not be deleted".format(self.__class__.__name__, key))
def __contains__(self, key):
return key in self.keys()
class System(ReadonlyDict):
__metaclass__ = MetaReadonlyDict
prefix = '_get_'
def _get_host_name(self):
return 'localhost'
def _get_kernel_version(self):
return '4.7.0'
system = System()
print('system.keys(): {!r}'.format(system.keys()))
print('values associated with system.keys():')
for key in system.keys():
print(' {!r}: {!r}'.format(key, system[key]))
try:
system['bios']
except Exception as ex:
print(str(ex))
try:
system['kernel_version'] = '5.0'
except Exception as ex:
print(str(ex))
try:
del system['host_name']
except Exception as ex:
print(str(ex))
Output:
system.keys(): ['kernel_version', 'host_name']
values associated with system.keys():
'kernel_version': '4.7.0'
'host_name': 'localhost'
System object has no 'bios' key
System object is read-only: 'kernel_version' key can not be redefined
System object is read-only: 'host_name' key can not be deleted
Hey so right now I'm developing backend api using Google ProtoRPC and Endpoints. I'm using the endpoints-proto-datastore library.
So strange things happen here, here is the EndpointsModel class
class AssetData(EndpointsModel):
type = msgprop.EnumProperty(AssetType, indexed=True)
def auth_id_set(self, value):
if ApplicationID.get_by_id(value) is None:
raise endpoints.UnauthorizedException('no auth_id')
self._auth_id = value
#EndpointsAliasProperty(required=True, setter=auth_id_set, property_type=messages.IntegerField)
def auth_id(self):
return self._auth_id
def app_id_set(self, value):
if ApplicationID.query(ApplicationID.app_id == value).get() is None:
raise endpoints.UnauthorizedException('wrong app_id')
self._app_id = value
if self.check_auth_app_id_pair(self.auth_id, value):
self._app_id = value
else:
raise endpoints.BadRequestException('auth_id and app_id mismatch')
#EndpointsAliasProperty(required=True, setter=app_id_set)
def app_id(self):
return self._app_id
#staticmethod
def check_auth_app_id_pair(authen_id, applic_id):
dat = ApplicationID.get_by_id(authen_id)
if dat.app_id != applic_id:
return False
else:
return True
and this is the API class
#endpoints.api(...)
class AssetDatabaseAPI(remote.Service):
#AssetData.query_method(query_fields=('limit', 'order', 'pageToken', 'type', 'auth_id', 'app_id'),
path='assets', http_method='GET', name='assets.getAssetMultiple')
def assets_get_multiple(self, query):
return query
When I deploy this, everytime I tried to access assets.getMultipleAssets it just gives me this error
raised BadRequestError(Key path element must not be incomplete: [ApplicationID: ]). Strangely enough this only happen to method using #Model.query_method, I have other methods using the same system but using #Model.method and it just runs ok.
If I tried it in development server, sometimes it just gives me RuntimeError: BadRequestError('missing key id/name',) then if I just re-save the .py file and retry it, it will work (sometimes not and another re-save can also make the error happens again).
Can anyone tell me my mistake?
Thanks
I think your problem is how you call this method - it's a static method, so you have to access it through class, not the instance (self):
if AssetData.check_auth_app_id_pair(self.auth_id, value):
self._app_id = value
else:
raise endpoints.BadRequestException('auth_id and app_id mismatch')
Let's have a class representing a Django controller, with one of methods called _onSuccess :
class ConfirmController(object):
...
def _onSuccess(self, controller):
...
The class is instantiated later with:
def credit_confirm_info(request, payment_module, template='/some/template.html'):
controller = ConfirmController(request, payment_module)
controller.confirm() # this method calls self._onSuccess
return controller.response
credit_confirm_info = never_cache(credit_confirm_info)
I'm trying to use subclass of ConfirmController:
class ConfirmControllerEx(ConfirmController):
def _onSuccess(self, controller):
# shortened to demonstrate even simple call to super
# causes a different behaviour
super(ConfirmControllerEx, self)._onSuccess(controller)
I've probably missed something at python learning but can anybody explain why is not the above sublassed _onSuccess equivalent to the original method ?
If I do use the above sublass ConfirmControllerEx:
def credit_confirm_info(request, payment_module, template='/some/template.html'):
controller = ConfirmControllerEx(request, payment_module)
controller.confirm() # this method calls self._onSuccess
return controller.response
credit_confirm_info = never_cache(credit_confirm_info)
I'm getting NoneType has no method has_header error, like credit_confirm_info is called again but with request parameter equal to None.
I expect the sublass and subclassed method _onSuccess with the plain call to super won't differ from the original. Am I missing something here ?
Update (traceback of the exception):
Traceback:
File "/home/dunric/Projects/Example.com/satchmo/lib/python2.7/site-packages/django/core/handlers/base.py" in get_response
111. response = callback(request, *callback_args, **callback_kwargs)
File "/home/dunric/Projects/Example.com/satchmo/gastroceny_cz/localsite/views.py" in cod_confirm_info
279. template='shop/checkout/cod/confirm.html')
File "/home/dunric/Projects/Example.com/satchmo/lib/python2.7/site-packages/django/views/decorators/cache.py" in _wrapped_view_func
90. add_never_cache_headers(response)
File "/home/dunric/Projects/Example.com/satchmo/lib/python2.7/site-packages/django/utils/cache.py" in add_never_cache_headers
129. patch_response_headers(response, cache_timeout=-1)
File "/home/dunric/Projects/Example.com/satchmo/lib/python2.7/site-packages/django/utils/cache.py" in patch_response_headers
119. if not response.has_header('Last-Modified'):
Exception Type: AttributeError at /checkout/cod/confirm/
Exception Value: 'NoneType' object has no attribute 'has_header'
I'm not up on the specifics of django involved here, but this method:
def _onSuccess(self, controller):
# shortened to demonstrate even simple call to super
# causes a different behaviour
super(ConfirmControllerEx, self)._onSuccess(controller)
Is not equivalent to the _onSuccess of the parent class. It calls the parent implementation through super, but it ignores whatever that call returns and just returns None (implicitly, by execution reaching the end of the method definition). Given you later get an error that seems to indicate you have a None object (instance of NoneType) where something else was expected, this would be my guess at the error. That's not going to be it if the contract of the _onSuccess method is to always return None, however.
i have to get static information from one 'module' to another. I'm trying to write logger with information about code place from where we're logging.
For example, in some file:
LogObject.Log('Describe error', STATIC_INFORMATION)
Static information is class name, file name and function name.
I get it from this:
__file__
self.__class__.__name__
sys._getframe().f_code.co_name
But i don't want to write this variables during logging. Can i create some function and call it. For example:
LogObject.Log('Describe error', someFunction())
How can i use it for getting static information?
I don't think "static" is the world you're looking for. If I understand you correctly, you want to write a function that will return the filename, class name and method name of the caller.
Basically, you should use sys._getframe(1) to access the previous frame, and work from there.
Example:
def codeinfo():
import sys
f = sys._getframe(1)
filename = f.f_code.co_filename
classname = ''
if 'self' in f.f_locals:
classname = f.f_locals['self'].__class__.__name__
funcname = f.f_code.co_name
return "filename: %s\nclass: %s\nfunc: %s" % (filename, classname, funcname)
Then from a method somewhere you can write
logger.info("Some message \n %s" % codeinfo())
First, please use lower-case names for objects and methods. Only use UpperCase Names for Class definitions.
More importantly, you want a clever introspective function in every class, it appears.
class Loggable( object ):
def identification( self ):
return self.__class__.__module__, self.__class__.__name__, sys._getframe().f_code.co_name
class ARealClass( Loggable ):
def someFunction( self ):
logger.info( "Some Message from %r", self. identification() )
If all of your classes are subclasses of Loggable, you'll inherit this identification function in all classes.