Built-in non-data version of property? - python

class Books():
def __init__(self):
self.__dict__['referTable'] = 1
#property
def referTable(self):
return 2
book = Books()
print(book.referTable)
print(book.__dict__['referTable'])
Running:
vic#ubuntu:~/Desktop$ python3 test.py
2
1
Books.referTable being a data descriptor is not shadowed by book.__dict__['referTable']:
The property() function is implemented as a data descriptor.
Accordingly, instances cannot override the behavior of a property.
To shadow it, instead of property built-in descriptor i must use my own descriptor. Is there a built in descriptor like property but which is non-data?

To expand on my comment, why not simply something like this:
>>> class Books():
... def __init__(self):
... self.__dict__['referTable'] = 1
... #property
... def referTable(self):
... try:
... return self.__dict__['referTable']
... except KeyError:
... return 2
...
>>> a = Books()
>>> a.referTable
1
>>> del a.__dict__['referTable']
>>> a.referTable
2
Now, I'd like to note that I don't think this is good design, and you'd be much better off using a private variable rather than accessing __dict__ directly. E.g:
class Books():
def __init__(self):
self._referTable = 1
#property
def referTable(self):
return self._referTable if self._referTable else 2
In short, the answer is no, there is no alternative to property() that works in the way you want in the Python standard library.

There is something very similar to a built-in non-data descriptor -- the class attribute:
class Books():
referTable = 'default'
def __init__(self, referTable=None):
if referTable is not None:
self.referTable = referTable
book = Books()
print(book.referTable)
# default
book.referTable = 'something specific'
print(book.referTable)
# something specific
If you need something more like a property (for example, you want a function to do some heavy-lifting the first time, but then use that first value for all future references), then you will need to build it yourself:
class OneTime(object):
def __init__(self, method):
self.name = method.__name__
self.method = method
def __get__(self, inst, cls):
if inst is None:
return self
result = self.method(inst)
inst.__dict__[self.name] = result
return result
class Books(object):
#OneTime
def referTable(self):
print 'calculating'
return 1 * 2 * 3 * 4 * 5
b = Books()
print b.__dict__
print b.referTable
print b.__dict__
print b.referTable
With the following results:
{}
calculating
120
{'referTable': 120}
120

Related

How to build a class that exposes data while calling a instance of it? [duplicate]

This question already has answers here:
How to properly implement/overload "__repr__ "?
(3 answers)
Closed 5 years ago.
Really don't know how to explain this without an example.
My goal is to create python class that shows data while calling the object itself.
A user defined class should works like this:
>>> class MyObject(object):
>>> def __init__(self):
>>> self.a = 12
>>>
>>> i = MyObject()
>>> i
<__main__.MyObject object at 0x7f667e7a78d0>
While if I work with a class like Uuid4:
>>> import uuid
>>> u = uuid.uuid4()
>>> u
UUID('cf27caba-d109-403c-a09e-fc59fb2a57a4')
Another object that act like this is the one created with scapy:
# scapy
Welcome to Scapy
>>>
>>> i = IP()
>>> i.src = '192.168.1.12'
>>> i
<IP src=192.168.1.12 |>
So my goal is to create a MyObject class that acts like Uuid4() or IP() while called:
MyObject(a='12') or MyObject(12) or <MyObject a=12 |>
I thought it was how the class is defined, but looking at the Uuid4() sourcecode gives me no hint on this...
Or am I missing something?!
You can define the __repr__ method on your class, and have it describe the contents of class instance.
For instance, UUID has this:
def __repr__(self):
return 'UUID(%r)' % str(self)
For your class, you could write this:
class MyClass(object):
def __init__(self, a):
self.a = a
def __repr__(self):
return 'MyClass(%r)'%(self.a,)
You need to define the __repr__ method to return the string you want.
class MyObject(object):
def __init__(self):
self.a = 12
def __repr__(self):
return "MyObject(%s)" % (self.a,)
The general rule is that when possible, repr(a) should return a string that could be (or at least resembles one that could be) evaluated to create an object identical to a.
you will need to implement repr() or str() in your class
for example :
def __str__(self):
return self.a
and when you will do
print i
you will get what you wanted
You should override the __repr__ and __str__ methods with your version of the string / representation of the class
class MyObject(object):
def __init__(self):
self.a = 12
def __repr__(self):
return 'MyObject(a=%s)' % self.a
def __str__(self):
return 'MyObject(a=%s)' % self.a
i = MyObject()
i
>> MyObject(a=12)
You can implement a __str__ method:
class MyObject(object):
def __init__(self):
self.a = 12
def __str__(self):
return "<MyObject a={} |>".format(self.a)
i = MyObject()
print(i)
Output:
<MyObject a=12 |>

conditional class inheritance in python

I am trying to dynamically create classes in Python and am relatively new to classes and class inheritance. Basically I want my final object to have different types of history depending on different needs. I have a solution but I feel there must be a better way. I dreamed up something like this.
class A:
def __init__(self):
self.history={}
def do_something():
pass
class B:
def __init__(self):
self.history=[]
def do_something_else():
pass
class C(A,B):
def __init__(self, a=False, b=False):
if a:
A.__init__(self)
elif b:
B.__init__(self)
use1 = C(a=True)
use2 = C(b=True)
You probably don't really need that, and this is probably an XY problem, but those happen regularly when you are learning a language. You should be aware that you typically don't need to build huge class hierarchies with Python like you do with some other languages. Python employs "duck typing" -- if a class has the method you want to use, just call it!
Also, by the time __init__ is called, the instance already exists. You can't (easily) change it out for a different instance at that time (though, really, anything is possible).
if you really want to be able to instantiate a class and receive what are essentially instances of completely different objects depending on what you passed to the constructor, the simple, straightforward thing to do is use a function that returns instances of different classes.
However, for completeness, you should know that classes can define a __new__ method, which gets called before __init__. This method can return an instance of the class, or an instance of a completely different class, or whatever the heck it wants. So, for example, you can do this:
class A(object):
def __init__(self):
self.history={}
def do_something(self):
print("Class A doing something", self.history)
class B(object):
def __init__(self):
self.history=[]
def do_something_else(self):
print("Class B doing something", self.history)
class C(object):
def __new__(cls, a=False, b=False):
if a:
return A()
elif b:
return B()
use1 = C(a=True)
use2 = C(b=True)
use3 = C()
use1.do_something()
use2.do_something_else()
print (use3 is None)
This works with either Python 2 or 3. With 3 it returns:
Class A doing something {}
Class B doing something []
True
I'm assuming that for some reason you can't change A and B, and you need the functionality of both.
Maybe what you need are two different classes:
class CAB(A, B):
'''uses A's __init__'''
class CBA(B, A):
'''uses B's __init__'''
use1 = CAB()
use2 = CBA()
The goal is to dynamically create a class.
I don't really recommend dynamically creating a class. You can use a function to do this, and you can easily do things like pickle the instances because they're available in the global namespace of the module:
def make_C(a=False, b=False):
if a:
return CAB()
elif b:
return CBA()
But if you insist on "dynamically creating the class"
def make_C(a=False, b=False):
if a:
return type('C', (A, B), {})()
elif b:
return type('C', (B, A), {})()
And usage either way is:
use1 = make_C(a=True)
use2 = make_C(b=True)
I was thinking about the very same thing and came up with a helper method for returning a class inheriting from the type provided as an argument.
The helper function defines and returns the class, which is inheriting from the type provided as an argument.
The solution presented itself when I was working on a named value class. I wanted a value, that could have its own name, but that could behave as a regular variable. The idea could be implemented mostly for debugging processes, I think. Here is the code:
def getValueClass(thetype):
"""Helper function for getting the `Value` class
Getting the named value class, based on `thetype`.
"""
# if thetype not in (int, float, complex): # if needed
# raise TypeError("The type is not numeric.")
class Value(thetype):
__text_signature__ = "(value, name: str = "")"
__doc__ = f"A named value of type `{thetype.__name__}`"
def __init__(self, value, name: str = ""):
"""Value(value, name) -- a named value"""
self._name = name
def __new__(cls, value, name: str = ""):
instance = super().__new__(cls, value)
return instance
def __repr__(self):
return f"{super().__repr__()}"
def __str__(self):
return f"{self._name} = {super().__str__()}"
return Value
Some examples:
IValue = getValueClass(int)
FValue = getValueClass(float)
CValue = getValueClass(complex)
iv = IValue(3, "iv")
print(f"{iv!r}")
print(iv)
print()
fv = FValue(4.5, "fv")
print(f"{fv!r}")
print(fv)
print()
cv = CValue(7 + 11j, "cv")
print(f"{cv!r}")
print(cv)
print()
print(f"{iv + fv + cv = }")
The output:
3
iv = 3
4.5
fv = 4.5
(7+11j)
cv = (7+11j)
iv + fv + cv = (14.5+11j)
When working in IDLE, the variables seem to behave as built-in types, except when printing:
>>> vi = IValue(4, "vi")
>>> vi
4
>>> print(vi)
vi = 4
>>> vf = FValue(3.5, 'vf')
>>> vf
3.5
>>> vf + vi
7.5
>>>

Python: How to do extra stuff when a specific attribute of an object is accessed?

Let's say I have a class in Python:
class Foo(object):
a = 1
b = 2
I'd like to do some extra stuff when I access 'a' but NOT 'b'. So, for example, let's assume that the extra stuff I'd like to do is to increment the value of the attribute:
> f = Foo()
> f.a # Should output 2
> f.a # Should output 3
> f.a # Should output 4
> f.b # Should output 2, since I want the extra behavior just on 'a'
It feels like there is a way through __getattr__ or __getattribute__, but I couldn't figure that out.
The extra thing can be anything, not necessarily related to the attribute (like print 'Hello world').
Thanks.
What you are looking for is a property, which can be used nicely as a decorator:
class Foo(object):
_a = 2
#property
def a(self):
Foo._a += 1
return Foo._a - 1
b = 2
The function is called whenever you try to access foo_instance.a, and the value returned is used as the value for the attribute. You can also define a setter too, which is called with the new value when the attribute is set.
This is presuming you want the odd set-up of class attributes you only ever access from instances. (_a and b here belong to the class - that is, there is only one variable shared by all instances - as in your question). A property, however, is always instance-owned. The most likely case is you actually want:
class Foo(object):
def __init__(self):
self._a = 2
self.b = 2
#property
def a(self):
self._a += 1
return self._a - 1
Where they are instance attributes.
If you really do want the equivalent of #property for a class variable, you have to build the descriptor yourself.
You almost certainly don't want to do this—see Lattyware's answer for how to make normal instance variables, and turn one of them into a #property.
But here's how you could do it:
class IncrementOnGetDescriptor(object):
def __init__(self, initval=None):
self.val = initval
def __get__(self, obj, objtype):
self.val += 1
return self.val - 1
def __set__(self, obj, val):
self.val = val
class Foo(object):
a = IncrementOnGetDescriptor(2)
b = 2
Now you can test it:
>>> f = Foo()
>>> f.a
2
>>> Foo.a
3
>>>> f.a
4
Turning this into a #classproperty decorator is left as an exercise for the reader.
PS, this still isn't exactly like a normal class variable. Setting Foo.a = 10 will replace your magic auto-incrementing value with a normal 10, while setting foo.a = 10 will update the class with an auto-incrementing 10 instead of storing an instance variable in f. (I originally had the __set__ method raise AttributeError, because normally you'd want an auto-incrementing magic variable be read-only, but I decided to show the more complex version just to show all the issues you have to deal with.)

python reference a property like a function

How do you pythonically set multiple properties without referencing them individually? Below is my solution.
class Some_Class(object):
def __init__(self):
def init_property1(value): self.prop1 = value
def init_property2(value): self.prop2 = value
self.func_list = [init_property1, init_property2]
#property
def prop1(self):
return 'hey im the first property'
#prop1.setter
def prop1(self, value):
print value
#property
def prop2(self):
return 'hey im the second property'
#prop2.setter
def prop2(self, value):
print value
class Some_Other_Class(object):
def __init__(self):
myvalues = ['1 was set by a nested func','2 was set by a nested func']
some_class= Some_Class()
# now I simply set the properties without dealing with them individually
# this assumes I know how they are ordered (in the list)
# if necessary, I could use a map
for idx, func in enumerate(some_class.func_list):
func(myvalues[idx])
some_class.prop1 = 'actually i want to change the first property later on'
if __name__ == '__main__':
test = Some_Other_Class()
this became necessary to do when I had many many properties to initialize with user defined values. My code otherwise would look like a giant list of setting each property individually (very messy).
Note that many people have good answers below and I think I have reached a good solution. This is a re-edit mostly trying to clearly state the question. But, if anyone has a better approach please share!
just use the #property decorator
>>> class A:
... a=2
... #property
... def my_val(self,val=None):
... if val == None:return self.a
... self.a = val
...
>>> a=A()
>>> a.my_val
2
>>> a.my_val=7
>>> a.my_val
7
something like this?
if you only want to allow setting then dont give it a default val
>>> class A:
... a=2
... #property
... def my_val(self,val):
... self.a = val
...
>>> a=A()
>>> a.my_val
<Exception>
>>> a.my_val=7
>>> a.a
7
or if you only want to allow retrieval just ommit the 2nd arg
>>> class A:
... a=2
... #property
... def my_val(self):
... return self.a
...
...
>>> a=A()
>>> a.my_val
2
>>> a.my_val=7
<Exception>
I ... finally think I know what you're trying to do, and you don't need to do it the way you're approaching it. Let me take a stab at this.
class someclass(object):
def __init__(self):
func_list = [self.setter1, self.setter2]
value_list = [1, 2]
# These lines don't need to be this complicated.
# for ind in range(len(func_list)):
# func_list[ind](value_list[ind])
for idx, func in enumerate(func_list):
func(value_list[idx])
# Or even better
for idx, (func, val) in enumerate(zip(func_list, value_list)):
func(val)
def setter1(self, value):
self.a = value
def setter2(self, value):
self.b = value
It's worth pointing out that the idx variable and enumerate calls are superfluous in the second form, but I wasn't sure if you need that elsewhere.
If you look up the property in the object dict, you will get the property descriptor (if any), and likewise with the class; e.g.
a = SomeClass()
descriptor = a.__dict__.get('descriptor', type(a).__dict__.get('descriptor'))
Assuming that descriptor is a descriptor, it will have the following methods:
['deleter', 'fdel', 'fget', 'fset', 'getter', 'setter']
Note the fget and fset.

I need a Python class that keep tracks of how many times it is instantiated

I need a class that works like this:
>>> a=Foo()
>>> b=Foo()
>>> c=Foo()
>>> c.i
3
Here is my try:
class Foo(object):
i = 0
def __init__(self):
Foo.i += 1
It works as required, but I wonder if there is a more pythonic way to do it.
Nope. That's pretty good.
From The Zen of Python: "Simple is better than complex."
That works fine and is clear on what you're doing, don't complicate it. Maybe name it counter or something, but other than that you're good to go as far as pythonic goes.
Abuse of decorators and metaclasses.
def counting(cls):
class MetaClass(getattr(cls, '__class__', type)):
__counter = 0
def __new__(meta, name, bases, attrs):
old_init = attrs.get('__init__')
def __init__(*args, **kwargs):
MetaClass.__counter += 1
if old_init: return old_init(*args, **kwargs)
#classmethod
def get_counter(cls):
return MetaClass.__counter
new_attrs = dict(attrs)
new_attrs.update({'__init__': __init__, 'get_counter': get_counter})
return super(MetaClass, meta).__new__(meta, name, bases, new_attrs)
return MetaClass(cls.__name__, cls.__bases__, cls.__dict__)
#counting
class Foo(object):
pass
class Bar(Foo):
pass
print Foo.get_counter() # ==> 0
print Foo().get_counter() # ==> 1
print Bar.get_counter() # ==> 1
print Bar().get_counter() # ==> 2
print Foo.get_counter() # ==> 2
print Foo().get_counter() # ==> 3
You can tell it's Pythonic by the frequent use of double underscored names. (Kidding, kidding...)
If you want to worry about thread safety (so that the class variable can be modified from multiple threads that are instantiating Foos), the above answer is in correct. I asked this question about thread safety here. In summary, you would have to do something like this:
from __future__ import with_statement # for python 2.5
import threading
class Foo(object):
lock = threading.Lock()
instance_count = 0
def __init__(self):
with Foo.lock:
Foo.instance_count += 1
Now Foo may be instantiated from multiple threads.
Could we use decorators ? So for example ..
class ClassCallCount:
def __init__(self,dec_f):
self._dec_f = dec_f
self._count = 0
def __call__(self, *args, **kwargs):
self._count +=1
return self._dec_f(*args, **kwargs)
def PrintCalled(self):
return (self._count)
#ClassCallCount
def somefunc(someval):
print ('Value : {0}'.format(someval))
somefunc('val.1')
somefunc('val.2')
somefunc('val.3')
somefunc('val.4')
## Get the # of times the class was called
print ('of times class was called : {0}'.format(somefunc._count))

Categories

Resources