Related
So in my program, a certain function (good_function()) needs to use the string name (attribute_name) of an object when referencing an attribute(object_name.attribute) of an object(object_name). This attribute is also another object from a different class. However, when I pull out this attribute to be used, it brings up the class object name (<main.Class2 object at abcde12345>) instead of the name of the attribute (attribute_name). The current output and setup is as follows.
class Class():
def __init__(self, attribute):
pass
class Class2():
pass
attribute_name = Class2()
object_name = Class(attribute_name)
object_name.attribute = attribute_name
def good_function(thing):
#doesn't really matter
pass
good_function(object_name.attribute)
print(object_name.attribute)
>>> <__main__.Class2 object at abcde12345>
It reads "object_name.attribute"(attribute_name) "as the attribute_name"'s object ID name thingamajiggy (<main.Class2 object at abcde12345>) instead of just "attribute_name". So my question is: Is there a way to translate the callsign (<main.Class2 object at abcde12345>) into the "attribute name" to which it corresponds? (see desired output below) Thanks in advance, I hope this wasn't too confusing, and I'll be as active as I can in responses. The desired output and setup is below.
cclass Class():
def __init__(self, attribute):
pass
object_name.attribute = 'attribute_name'
def magic_function(object):
#solve for here
return object
def good_function(thing):
#doesn't really matter
pass
variable = magic_function(object_name.attribute)
good_function(variable)
print(variable)
>>> attribute_name
If I'm understanding correctly, then I don't think what you want is possible, assuming the actual reference attribute is just a native type.
However, if you made the attribute an instance of your own custom class then any instance could implement the __str__ method to display whatever you wanted:
class MyClass():
def __str__(self):
return 'MyClass str'
This may have been answered somewhere else, but I was wondering if there was any way to remove an attribute/method decorated with #property in a subclass.
Example:
from datetime import datetime
class A():
def __init__(self, num):
self._num = num
#property
def id(self):
return self._num * datetime.now().timestamp()
class B(A):
def __init__(self, id, num):
super().__init__(num)
self.id = id
The above code does not run if you attempt to create an instance of class B. AttributeError: can't set attribute
The base class uses a property because it needs to evaluate its ID on the fly, while my sub class is able to know its ID when it is created. The id attribute is accessed OFTEN, and I am seeing a significant performance hit because I have to use a property to serve this attribute, instead of just accessing it directly. (From what I have read, properties increase time-to-access by 5x). My application is currently spending around 10% of runtime getting this property.
Is there any way I can short-circuit the property in a sub class?
I'm going to go through several possibilities here. Some of them do what you literally asked. Some of them don't, but they may be better options anyway.
First, your example base class changes the value of obj.id on every access due to the passage of time. That's really bizarre and doesn't seem like a useful concept of "ID". If your real use case has a stable obj.id return value, then you can cache it to avoid the expense of recomputation:
def __init__(self):
...
self._id = None
#property
def id(self):
if self._id is not None:
return self._id
retval = self._id = expensive_computation()
return retval
This may mitigate the expense of the property. If you need more mitigation, look for places where you access id repeatedly, and instead, access it once and save it in a variable. Local variable lookup outperforms attribute access no matter how the attribute is implemented. (Of course, if you actually do have weird time-variant IDs, then this sort of refactoring may not be valid.)
Second, you can't override a property with a "regular" attribute, but you can create your own version of property that can be overridden this way. Your property blocks attribute setting, and takes priority over "regular" attributes even if you force an entry into the instance __dict__, because property has a __set__ method (even if you don't write a setter). Writing your own descriptor without a __set__ would allow overriding. You could do it with a generic LowPriorityProperty:
class LowPriorityProperty(object):
"""
Like #property, but no __set__ or __delete__, and does not take priority
over the instance __dict__.
"""
def __init__(self, fget):
self.fget = fget
def __get__(self, instance, owner=None):
if instance is None:
return self
return self.fget(instance)
class Foo(object):
...
#LowPriorityProperty
def id(self):
...
class Bar(Foo):
def __init__(self):
super(Bar, self).__init__()
self.id = whatever
...
Or with a role-specific descriptor class:
class IDDescriptor(object):
def __get__(self, instance, owner=None):
if instance is None:
return self
# Remember, self is the descriptor. instance is the object you're
# trying to compute the id attribute of.
return whatever(instance)
class Foo(object):
id = IDDescriptor()
...
class Bar(Foo):
def __init__(self):
super(Bar, self).__init__()
self.id = whatever
...
The role-specific descriptor performs better than the generic LowPriorityProperty, but both perform worse than property due to implementing more logic in Python instead of C.
Finally, you can't override a property with a "regular" attribute, but you can override it with another descriptor, such as another property, or such as the descriptors created for __slots__. If you're really, really pressed for performance, __slots__ is probably more performant than any descriptor you could implement manually, but the interaction between __slots__ and the property is weird and obscure and you'll probably want to leave a comment explaining what you're doing.
class Foo(object):
#property
def id(self):
...
class Bar(Foo):
__slots__ = ('id',)
def __init__(self):
super(Bar, self).__init__()
self.id = whatever
...
add a class C as common ancestor, without id. inherit A and B from it and implement id there as needed. Python wont care that id doesn’t exist on C.
refactor non-id code/attributes from A to C.
Suitability depends on whether OP controls class hierarchy and instantiation mechanisms.
I also found a workaround to get it working as is:
from datetime import datetime
class A():
def __init__(self, num):
self._num = num
#property
def id(self):
return self._num * datetime.now().timestamp()
class B(A):
#this fixes the problem
id = None
def __init__(self, id, num):
super().__init__(num)
self.id = id
b = B("id", 3)
print(vars(b))
This will output:
{'_num': 3, 'id': 'id'}
The trick is id = None on class B. Basically, Python's attribute/method lookup mechanism will stop at the first class with id as an attribute in the MRO. With id = None on class B, the lookup stops there and it never gets as far as that pesky #property on A.
If I comment it back out, as per the OP:
self.id = id
AttributeError: can't set attribute
I'm reading Fluent Python chapter 19 > A Proper Look at Properties, and I'm confused about the following words:
Properties are always class attributes, but they actually manage attribute access in the instances of the class.
The example code is:
class LineItem:
def __init__(self, description, weight, price):
self.description = description
self.weight = weight # <1>
self.price = price
def subtotal(self):
return self.weight * self.price
#property # <2>
def weight(self): # <3>
return self.__weight # <4>
#weight.setter # <5>
def weight(self, value):
if value > 0:
self.__weight = value # <6>
else:
raise ValueError('value must be > 0') # <7>
From my previous experiences, class attributes are belong to the class itself and shared by all the instances. But here, weight, the property, is an instance method and the value returned by it is different between instances. How is it eligible to be a class attribute? Doesn't it that all the class attributes should be the same for any instances?
I think I misunderstand something, so I hope to get a correct explanation. Thanks!
A distinction is made because when you define a #property on a class, that property object becomes an attribute on the class. Whereas when you define attributes against an instance of your class (in your __init__ method), that attribute only exists against that object. This might be confusing if you do:
>>> dir(LineItem)
['__class__', ..., '__weakref__', 'subtotal', 'weight']
>>> item = LineItem("an item", 3, 1.12)
>>> dir(item)
['__class__', ..., '__weakref__', 'description', 'price', 'subtotal', 'weight']
Notice how both subtotal and weight exist as attributes on your class.
I think it's also worth noting that when you define a class, code under that class is executed. This includes defining variables (which then become class attributes), defining functions, and anything else.
>>> import requests
>>> class KindOfJustANamespace:
... text = requests.get("https://example.com").text
... while True:
... break
... for x in range(2):
... print(x)
...
0
1
>>> KindOfJustANamespace.text
'<!doctype html>\n<html>\n<head>\n <title>Example Domain...'
A #decorator is just "syntactic sugar". Meaning #property over a function if the same as function = property(function). This applies to functions defined inside a class as well, but now the function is part of the class's namespace.
class TestClass:
#property
def foo(self):
return "foo"
# ^ is the same as:
def bar(self):
return "bar"
bar = property(bar)
A good explanation of property in Python can be found here: https://stackoverflow.com/a/17330273/7220776
From my previous experiences, class attributes are belong to the class itself and shared by all the instances.
That's right.
But here, weight, the property, is an instance method
No, it's a property object. When you do:
#decorator
def func():
return 42
it's actually syntactic sugar for
def func():
return 42
func = decorator(func)
IOW the def statement is executed, the function object created, but instead of beeing bound to it's name, it's passed to the decorator callable, and the name is bound to whatever decorator() returned.
In this case the decorator is the property class itself, so the weight attribute is a property instance. You can check this out by yourself by inspecting LineItem.weight (which will return the property object itself).
and the value returned by it is different between instances.
Well yes of course, how is this surprising ? LineItem.subtotal is a class attribute also (like all methods), yet it returns values from the instance it's called on (which is passed to the function as the self param).
How is it eligible to be a class attribute? Doesn't it that all the class attributes should be the same for any instances?
The class attributes ARE the same for all instances of a class, yes. There's only one single subtotal function for all instances of LineItem.
A property is mainly a shortcut to make a function (or a pair of functions if you specify a setter) look like it's a plain attribute, so when you type mylinitem.weight, what is really executed is LineItem.weight.fget(mylineitem), where fget is the getter function you decorated with #property. The mechanism behind this is known as the "descriptor protocol", which is also used to turn mylineitem.subtotal() into LineItem.subtotal(mylineitem) (python functions implement the descriptor protocol to return "method" objects, which are themselves wrappers around the function and the current instance and insert the instance as first argument to the function call).
So it's not suprising that properties are class attributes - you only need one property instance to "serve" all instances of the class -, and moreover, properties - like all descriptors FWIW - MUST actually be class attributes to work as expected, since the descriptor protocol is only invoked on class attributes (there's no use case for a "per instance" computed attribute since the function in charge of the "computation" will get the instance as parameter).
I finally understand the descriptor and property concept through Simeon Franklin's excellent presentation, the following contents can be seen as a summary on his lecture notes. Thanks to him!
To understand properties, you first need to understand descriptors, because a property is implemented by a descriptor and python's decorator syntactic sugar. Don't worry, it's not that difficult.
What is a descriptor:
a descriptor is any object that implements at least one of methods named __get__(), __set__(), and __delete__().
Descriptor can be divided into two categories:
A data descriptor implements both __get__() and __set__().
A non-data descriptor implements only __get__().
According to python's HowTo:
a descriptor is an object attribute with “binding behavior”, one whose attribute access has been overridden by methods in the descriptor protocol.
Then what is the descriptor protocol? Basically speaking, it's just says that when Python interpreter comes across an attribute access like obj.attr,it will search in some order to resolve this .attr , and if this attr is a descriptor attribute, then this descriptor will take some precedence in this specific order and this attribute access will be translated into a method call on this descriptor according to the descriptor protocol, possibly shadowing a namesake instance attribute or class attribute. More concretely, if attr is a data descriptor, then obj.attr will be translated into the calling result of this descriptor's __get__ method; if attr is not a data descriptor and is an instance attribute, this instance attribute will be matched; if attr is not in above, and it is a non-data descriptor, we get the calling result of this non-data descriptor's __get__ method. Full rules on attribute resolution can be found here .
Now let's talk about property. If you have looked at Python' descriptor HowTo, you can find a pure Python version implementation of property:
class Property(object):
"Emulate PyProperty_Type() in Objects/descrobject.c"
def __init__(self, fget=None, fset=None, fdel=None, doc=None):
self.fget = fget
self.fset = fset
self.fdel = fdel
if doc is None and fget is not None:
doc = fget.__doc__
self.__doc__ = doc
def __get__(self, obj, objtype=None):
if obj is None:
return self
if self.fget is None:
raise AttributeError("unreadable attribute")
return self.fget(obj)
def __set__(self, obj, value):
if self.fset is None:
raise AttributeError("can't set attribute")
self.fset(obj, value)
def __delete__(self, obj):
if self.fdel is None:
raise AttributeError("can't delete attribute")
self.fdel(obj)
def getter(self, fget):
return type(self)(fget, self.fset, self.fdel, self.__doc__)
def setter(self, fset):
return type(self)(self.fget, fset, self.fdel, self.__doc__)
def deleter(self, fdel):
return type(self)(self.fget, self.fset, fdel, self.__doc__)
Apparently,property is a data descriptor!
#property just uses python's decorator syntactic sugar.
#property
def attr(self):
pass
is equivalent to:
attr = property(attr)
So, attr is no longer an instance method as I posted in thie question, but is translated into a class attribute by the decorator syntactic sugar as the author said. It's a descriptor object attribute.
How is it eligible to be a class attribute?
OK, we solved it now.
Then:
Doesn't it that all the class attributes should be the same for any instances?
No!
I steal an example from Simeon Franklin's excellent presentation .
>>> class MyDescriptor(object):
... def __get__(self, obj, type):
... print self, obj, type
... def __set__(self, obj, val):
... print "Got %s" % val
...
>>> class MyClass(object):
... x = MyDescriptor() # Attached at class definition time!
...
>>> obj = MyClass()
>>> obj.x # a function call is hiding here
<...MyDescriptor object ...> <....MyClass object ...> <class '__main__.MyClass'>
>>>
>>> MyClass.x # and here!
<...MyDescriptor object ...> None <class '__main__.MyClass'>
>>>
>>> obj.x = 4 # and here
Got 4
Pay attention to obj.x and its output. The second element in its output is <....MyClass object ...> . It's the specific instance obj . Shortly speaking, because this attribute access has been translated into a __get__ method call, and this __get__ method get the specific instance argument as its method signature descr.__get__(self, obj, type=None) demands, it can return different values according to which instance it is been called by.
Note: my English explanation maybe not clear enough, so I highly recommend you to look at Simeon Franklin's notes and Python's descriptor HowTo.
You didn't misunderstand. Don't worry, just read on. It will become clear in the next chapter.
The same book explains in chapter 20 that they can be a class attributes because of the descriptor protocol. The documentation explains how properties are implemented as descriptors.
As you see from the example, properties are really class attributes (methods). When called, they get a reference to the instance, and writes/reads to its underlying __dict__.
I think the example is wrong, the init shoul look like this:
def __init__(self, description, weight, price):
self.description = description
self.__weight = weight # <1>
self.__price = price
self.__weight and self.__price are the internal attributes hidden in the class by the properties
Excuse me, I am pretty new to oop in python, but I'm wondering how to pass the value of tld_object in gather_site() to the method gather_path()
class MyClass:
def __init__(self):
print "Class Initialized"
def gather_site(self):
tld_object = Tld.objects.filter(id=3)
return tld_object
def gather_path(self):
path_object = PathsOfDomain.objects.filter(FKtoTld=)
models.py
class Tld(models.Model):
##default table PK here.
##fields here
class PathsOfDomain(models.Model):
##default table PK here.
##fields here
FKtoTld = models.ForeignKey(Tld)
Basically is what is happening in table Tld, has a 1:M relationship to PathsOfDomain and I want to be able to get the related paths, based on tld_object which comes from database in gather_site() method
Any help is graciously appreciated. Thank you.
def gather_path(self):
path_object = PathsOfDomain.objects.filter(FKtoTld=3)
I think should work fine ...
class MyClass:
def __init__(self):
print "Class Initialized"
def gather_site(self, id):
# Note I'm using get instead of filter when dealing with PKs.
# Only one object is going to be returned.
self.tld_object = Tld.objects.get(id=id)
return self.tld_object
def gather_path(self):
# At this point you have to have self.tld_object already set,
# Either check it exists or give it a default value.
path_object = PathsOfDomain.objects.filter(FKtoTld=self.tld_object.id)
Is it possible to get the class name within the body of a class definition?
For example,
class Foo():
x = magic() # x should now be 'Foo'
I know that I can do this statically outside of the class body using a class method:
class Bar():
#classmethod
def magic(cls):
print cls.__name__
Bar.magic()
However this isn't what I want, I want the class name in the class body
Ok - got one more solution - this one is actually not that complex!
import traceback
def magic():
return traceback.extract_stack()[-2][2]
class Something(object):
print magic()
It will print out "Something". I'm not sure if extracted stack format is standardised in any way, but it works for python 2.6 (and 2.7 and 3.1)
AFAIK, the class object is not available until the class definition has been "executed", so it's not possible to get it during class definition.
If you need the class name for later use but don't use it during class definition (e.g. to compute other field names, or some such thing), then you can still automate the process using a class decorator.
def classname ( field ):
def decorator ( klass ):
setattr(klass, field, klass.__name__)
return klass
return decorator
(Caveat: not tested.)
With this definition, you can get something like:
#classname(field='x')
class Foo:
pass
and you would get field x with the class name in it, as in:
print Foo.x
Here you have a working solution for your specific case, but beware (I wrote it mainly to demonstrate that it IS indeed possible to do something like this):
You shouldn't use it
It is very specific
It has many limitations
I was just having fun with this
It is black magic
It may not work for your use case
It is not threadsafe
Do I have already said that you shouldn't use it?
Anyway, here you have the code:
import inspect
def NameAwareClassType():
frameInfo = inspect.getouterframes(inspect.currentframe())[1]
codeContext = frameInfo[4][0]
className = codeContext.split(' ', 1)[1].split('(', 1)[0]
class ClassNameGlobalRemoverType(type):
def __new__(mcs, name, bases, dict):
if name == className:
del globals()['__clsname__']
return type.__new__(mcs, name, bases, dict)
class NameAwareClass(object):
__metaclass__ = ClassNameGlobalRemoverType
globals()['__clsname__'] = className
return NameAwareClass
class A(NameAwareClassType()):
print __clsname__
def __init__(self):
pass
print __clsname__
Edit: https://gist.github.com/1085475 — there you have a version which allows to use __clsname__ during method execution; makes not much sense, as self.__class__.__name__ is a better approach and the __clsname__ variable does not hold a string anymore (I'm having fun experimenting with this)
I don't know of an elegant way to do this in Python 2.x -- but it's an interpreted language which means that something relatively simple along the following lines will do what you want and would be safe if you're sure of the code being executed:
classdef = """\
class %(classname)s(object):
x = '%(classname)s'
print x
"""
exec classdef % {'classname': 'Foo'}
foo = Foo()
print foo
class Bar():
#classmethod
def magic(cls):
return cls.__name__
#property
def x(self):
return self.magic()
def y(self):
return self.x
>>> a = Bar()
>>> a.x
'Bar'
>>> a.y()
'Bar'
This way you can use x as an attribute, at least within any instance and static methods. In class methods, you can just get the class name from the cls attribute anyway.