generic Class in Python - python

I want to do a generic class in Python with one method
This class does not generate its instances
Some attributes are set in the body of the class
Method of this class uses the set attributes and in the generated classes the output of this method depends on these attributes
Method has only one input
I know that without metaclasses will not do, but I do not know how to apply them :)
something like this:
class GenericClass:
attr_a = ''
attr_b = ''
def count(text):
return len(text)/attr_a + attr_b
class A(GenericClass):
attr_a = 2
attr_b = 1
text = "Hello, I'm under the water"
print(A.count(text))
# 14

Defining count as a class method would make that work:
#classmethod
def count(cls, text):
return len(text) / cls.attr_a + cls.attr_b

class GenericClass:
def _count(text, a, b):
return len(text)/a + b
class A(GenericClass):
attr_a = 2
attr_b = 1
def count(text):
return GenericClass._count(text, A.attr_a, A.attr_b)
text = "Hello, I'm under the water"
print(A.count(text))

Related

Saving class instance state from inside class

I have read over the answers on Saving an Object (Data persistence) but it isn't really what I was looking for. I don't want to save the class state in a file.
Here's what I'm trying to implement:
class A():
def some_function(self):
# save class state here - (*)
if something:
#make changes to class attributes
if something_again():
# revert back to class state at - (*)
How can I save the class state at a particular point?
You could implement something like this
class A():
def __init__(self):
self.prev_state = dict()
self.field_1 = 1
self.field_2 = 2
self.save_fields = (
"field_1",
"field_2"
)
self.save_state()
def save_state(self):
for f in self.save_fields:
self.prev_state[f] = getattr(self, f)
def restore_state(self):
for f in self.save_fields:
setattr(self, f, self.prev_state[f])
a = A()
a.field_1 += 1
print(a.field_1) # 2
a.restore_state()
print(a.field_1) # 1

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 |>

Instantiating a subclass python

Just a simple class definition withh subclasses to show inheritance
import datetime
class LibaryItem: #The base class definition
def __init__(self, t, a, i): # initialiser method
self.__Title = t
self.__Author_Artist = a
self.__ItemID = i
self.__OnLoan = False
self.DueDate = datetime.date.today()
def GetTitle(self):
return(self.__Title)
# All other Get methods go here
def Borrowing(self):
self.__OnLoan = True
self.__DueDate = self.__DueDate + datetime.timedelta(weeks = 3)
def Returning(self):
self.OnLoan = False
def PrintDetails(self):
print(self.__Title, '; ', self.__Author_Artist,'; ',end='') # end='' Appends a space instead of a newline
print(self.__ItemID, '; ', self.__OnLoan,'; ', self.__DueDate)
class Book(LibaryItem):# A subclass definition
def __init__(self, t, a, i): # Initialiser method
LibaryItem.__init__(self, t, a, i)
# This statement calls the constructor for the base class
self.__IsRequested = False
self.__RequestBy = 0
def GetIsRequested(self):
return(self.__IsRequested)
class CD(LibaryItem):
def __init__(self, t, a, i): # Initialiser method
LibaryItem.__init__(self, t, a, i)
self.__Genre = ""
def GetGenre(self):
return(self.__Genre)
def SetGenre(self, g):
self.__Genre = g
Instantiating a subclass
ThisBook = Book('Title', 'Author', 'ItemID')
ThisCD = CD('Title', 'Author', 'ItemID')
This is my problem here I don't understand why the ThisBook the object's attribute doesn't change from False its default value to True.
# Using A method
print(ThisBook.GetIsRequested())
ThisBook.IsRequested = True
print(ThisBook.GetIsRequested())
Thank you a reason to why this doesn't work would be helpful
You probably meant to do
ThisBook.__IsRequested = True
which you can't do because of name mangling. You could write another setter.
But before you dive too deeply into writing a lot of getters and setters you should be aware that the pythonic way is to not use them. Or, if additional logic is required, to use the #property decorator.
class LibaryItem:
def __init__(self, title, author, itemid): # initialiser method
self.title = title
self.author = author
self.itemid = itemid
self._onloan = False
self.duedate = datetime.date.today()
#property
def onloan(self):
return self._onloan
#onloan.setter
def onloan(self, value):
if value:
self.duedate += datetime.timedelta(weeks = 3)
self._onloan = value
def __str__(self):
return "%s; %s; %s; %s; %s" % (self.title, self.author, self.itemid, self.onloan, self.duedate)
class Book(LibaryItem):
def __init__(self, title, author, itemid):
LibaryItem.__init__(self, title, author, itemid)
self.requested = False
self.requestby = 0
and then
ThisBook = Book('Title', 'Author', 'ItemID')
print(ThisBook.requested)
ThisBook.requested = True
ThisBook.onloan = True
print(ThisBook.duedate)
You can't access a field with 2 underscores prefix like that (see What is the meaning of a single- and a double-underscore before an object name?).
You need to write a proper setter:
def SetIsRequested(self, val):
self.__IsRequested = val
What you are experiencing is the typical silliness of dynamic languages. A field on class can be set w/o being declared and the interpreter can't help you by pointing out that you've just created a new field called "IsRequested" in your class. Saves you some typing but costs you in ability of your interpreter and IDE to prevent you from messing up.

Creating an object with a reference to the object that created it

I have a program where an object creates another object. However, the second object that gets created needs to be able to access the first. Is this possible?
EG (pseudocode)
class parentObject():
parentVar = 1
# Create Child
x = childObject()
class childObject():
#Assign Var to the Var of the childs parent
childVar = parent.parentVar
>>> x.childVar = 1
is there a straitforward way to do this?
UPDATE:
I don't want to inheret the class, I need to be able to access the actual object that created it, as each object created from that class has different values.
Why not inherit the class?
class parentObject():
parentVar = 1
class childObject(parentObject):
childVar = parentObject.parentVar
>>> x = childObject()
>>> print(x.childVar)
1
If you are going to have different instances of the class, you should do it as this instead:
class parentObject(object):
def __init__(self):
self.parentVar = 1
class childObject(parentObject):
def __init__(self):
super(childObject, self).__init__()
self.childVar = self.parentVar
>>> x = childObject()
>>> print(x.childVar)
1
If you want a reference to the "parent" class, but inheritance is illogical, consider sending self in to the constructor:
class Room:
def __init__(self, name):
self.name = name
self.furniture = []
def add_chair(self):
self.furniture.append(Chair(self))
def __str__(self):
return '{} with {}'.format(self.name, self.furniture)
class Chair:
def __init__(self, room):
self.room = room
def __str__(self):
return 'Chair in {}'.format(self.room.name)
r = Room('Kitchen')
r.add_chair()
r.add_chair()
print r
print r.furniture[0]
Output:
Kitchen with [<__main__.Chair instance at 0x01F45F58>, <__main__.Chair instance at 0x01F45F80>]
Chair in Kitchen

Built-in non-data version of property?

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

Categories

Resources