How to read the object name from memory? - python

I wrote a simple class code like below.
class Fridge:
def __init__(self):
self.isOpened = False
self.foods = []
def open(self):
self.isOpened = True
def put(self, thing):
if self.isOpened:
self.foods.append(thing)
def close(self):
self.isOpened = False
class Food:
pass
And then import the module...
import class_practice as fridge
f = fridge.Fridge()
apple = fridge.Food()
elephant = fridge.Food()
f.open()
f.put(apple)
f.put(elephant)
print(f.foods)
The print output is
[<class_practice.Food object at 0x7fe761fce5f8>, <class_practice.Food object at 0x7fe761fce710>]
In this case, if I want to print out f.foods as the object name of [apple, elephant],
how could I do?
##Revised##
I want to extract data from
[<class_practice.Food object at 0x7fe761fce5f8>, <class_practice.Food object at 0x7fe761fce710>]
as the form of ['apple', 'elephant'].
It is like,
a = 'hello'
b = id(a)
print(ctypes.cast(b, ctypes.py_object).value)
And then, the result is 'hello'

Store the value in a instance attribute, and return it from the __repr__ dunder method:
class Food:
def __init__(self, value):
self.value = value
def __repr__(self):
return self.value
You will need to pass the value when constructing Food:
apple = fridge.Food("apple")
elephant = fridge.Food("elephant")

Or try the following:
class Fridge:
def __init__(self):
self.isOpened = False
self.foods = []
def open(self):
self.isOpened = True
def put(self, thing):
if self.isOpened:
self.foods.append(thing)
def close(self):
self.isOpened = False
class Food:
def __init__(self, value):
self.value = value
def __repr__(self):
return self.value
import class_practice as fridge
f = fridge.Fridge()
f.open()
f.put(fridge.Food('apple'))
f.put(fridge.Food('elephant'))
print(f.foods)
Output:
[apple, elephant]

Related

Python set attribute equal to another attribute

Is it possible to have a class attribute targeting another attribute from the same object and have a function to update the value of the target?
class MyObject(object):
def __init__(self):
self.var_1 = 1
self.var_2 = 2
self.var_3 = 3
self.current_var = self.var_1
def update_var(self, value):
self.current_var = ...
Expected outcome:
>>> x = MyObject()
>>> x.update_var(10)
>>> x.var_1
10
>>> x.current_var = x.var_2
>>> x.update_var(5)
>>> x.var_2
5
You can use the __dict__ of the object or as said by #bla setattr,
And Enum so you don't use string to specify the attribute:
from enum import Enum
class MyObject(object):
def __init__(self):
self.var_1 = 1
self.var_2 = 2
self.var_3 = 3
self.current_var = None
def update_var(self, value):
if self.current_var is None:
raise Exception('Current var is not set')
self.__dict__[self.current_var.name] = value
setattr(self, self.current_var.name, value) # Same result
m = MyObject()
attrs = vars(m)
attrs_enum = Enum("attrs_enum", attrs)
m.var_1 # 1
m.current_var = attrs_enum.var_1
m.update_var(10)
m.var_1 # 10
m.current_var = attrs_enum.var_2
m.var_2 # 2
m.update_var(20)
m.var_2 # 20
I don't like using a string to specify the attribute, but this is solution
I suggest making current_var a property that acts as a proxy for a given instance attribute. You can use set_current_var to update the proxy target.
Code
class MyObject(object):
current_var = 1
def __init__(self):
self.var_1 = 1
self.var_2 = 2
self.var_3 = 3
def set_current_var(self, name):
self._current_var = name
#property
def current_var(self):
return getattr(self, self._current_var)
#current_var.setter
def current_var(self, value):
setattr(self, self._current_var, value)
Example
x = MyObject()
print(x.var_1) # 1
x.set_current_var('var_1')
print(x.current_var) # 1
x.current_var = 4
print(x.var_1) # 4
You can create a wrapper class for your MyObject attribute values. That way, a reference will exist from the contents of current_var to the attribute bound in __dict__:
class _int:
def __init__(self, _val):
self.value = _val
def __repr__(self):
return str(self.value)
class MyObject(object):
def __init__(self):
self.var_1 = _int(1)
self.var_2 = _int(2)
self.var_3 = _int(3)
self.current_var = self.var_1
def update_var(self, value):
self.current_var.value = value
x = MyObject()
x.update_var(10)
print(x.var_1)
x.current_var = x.var_2
x.update_var(5)
print(x.var_2)
Output:
10
5

python prototype structure, not working

whenever i print the c1 object, it prints:
<main.Car object at 0x7fde8b29a240>
however i added the str method, to format it to a proper string, why is it not printing a readable string?
import copy
class Prototype:
def __init__(self):
# constructor method to create the object
self._objects = {}
def register_object(self, name, obj):
# this method is used to register an object
self._objects[name] = obj
def unregister_object(self, name):
# this method is used to unregister an object
del self._objects[name]
def clone(self, name, **attr):
obj = copy.deepcopy(self._objects.get(name))
obj.__dict__.update(attr)
return obj
class Car:
def __init__(self):
self.name = "Skylark"
self.color = "blue"
self.options = "extra horsepower in engine"
def __str__(self):
return '{} | {} | {}'.format(self.name, self.color, self.options)
c = Car()
prototype = Prototype()
prototype.register_object('skylark',c)
c1 = prototype.clone('skylark')
print(c1)
There is a problem with the indentation in your code. I've corrected this and can get the desired answer too. The indentation is a bit off for the function defs. in both the classes.
I've called this file as test.py
import copy
class Prototype:
def __init__(self):
# constructor method to create the object
self._objects = {}
def register_object(self, name, obj):
# this method is used to register an object
self._objects[name] = obj
def unregister_object(self, name):
# this method is used to unregister an object
del self._objects[name]
def clone(self, name, **attr):
obj = copy.deepcopy(self._objects.get(name))
obj.__dict__.update(attr)
return obj
class Car:
def __init__(self):
self.name = "Skylark"
self.color = "blue"
self.options = "extra horsepower in engine"
def __str__(self):
return '{} | {} | {}'.format(self.name, self.color, self.options)
c = Car()
prototype = Prototype()
prototype.register_object('skylark',c)
c1 = prototype.clone('skylark')
print(c1)
When I run the file
$ python test.py
The output is:
#Output: Skylark | blue | extra horsepower in engine

Accessing class methods inside another class at same scope

Trying to get a work around for getting access to a class method in another class while being inside a class. Code below will probably explain my goal.
class Access(object):
def __init__(self):
pass
def select(self, value):
Store.keep(value)
class Store(object):
def __init__(self):
self.store_value = 0
def keep(self, value):
self.store_value = value
x = Access()
y = Store()
x.select(10)
y.store_value
##Want the output of 10
I don't see any way to do what you want without Access having a reference to a Store object.
The closest thing you can do is
class Access(object):
def __init__(self):
pass
def select(self, value):
Store.keep(value)
class Store(object):
#classmethod
def keep(cls, value):
cls.store_value = value
x = Access()
y = Store()
x.select(10)
print y.store_value #will print 10
#but
z = Store()
print z.store_value #will print 10 too
Where store_value is shared by all instances of Store.
You could pass an instance to select also and use Store.keep(inst, value):
class Access(object):
def __init__(self):
pass
def select(self, inst, value):
Store.keep(inst, value)
class Store(object):
def __init__(self):
self.store_value = 0
def keep(self, value):
self.store_value = value
x = Access()
y = Store()
x.select(y, 10)
print(y.store_value)
10

Automatically create (and keep) an object when accessed

I would like to do something like this:
class A:
def hello(): print "Hello"
# I do not want to explicitly setup a:
a = A()
# a = A() -> I want this to happen automatically when I access a
# My first try is this:
def a():
return A()
# Also, I do not want to call a as a function a(): it must be an object
# And it must stay alive and initialized
a.hello() # a is created, as object of class A
a.hello() # I do not want a second instantiation
How can I implement this? properties? cached-properties? They are only for classes: a is a module-level object.
Maybe something like this:
class A(object):
def hello(self):
print "Hello"
class LazyA(object):
def __init__(self):
self.instance = None
def __getattr__(self, k):
if self.instance is None:
self.instance = A()
return getattr(self.instance, k)
a = LazyA()
def lazyinit(cls):
class p(object):
def __init__(self, *args, **kws):
self._init = lambda: cls(*args, **kws)
self._obj = None
def __getattr__(self, k):
if not self._obj:
self._obj = self._init()
return getattr(self._obj, k)
return p
Example:
#lazyinit
class A(object):
def __init__(self, a, b):
print("initializing...")
self.x = a + b + 2
def foo(self):
return self.x
x = A(39, 1)
print x
print x.foo()
print x.foo()
Generalization of the answer by Pavel:
class LazyClass(object):
def __init__(self, myclass, *args, **kwargs):
self.instance = None
self.myclass = myclass
self.args = args
self.kwargs = kwargs
def __getattr__(self, k):
if self.instance is None:
self.instance = self.myclass(*self.args, **self.kwargs)
return getattr(self.instance, k)
class A(object):
def __init__ (self, name):
self.name = name
print "Created"
def hello(self):
print "Hello " + self.name
import unittest
class TestLazyClass(unittest.TestCase):
def setUp(self):
self.a = LazyClass(A, 'Daniel')
def test_it(self):
self.a.hello()
self.a.hello()

Python static dictionary in class that supports item assignment

I have a class that contains a static dictionary:
class MyClass:
my_dict = {}
def __init__(self, name):
self.name = name
MyClass.my_dict[self.name] = []
def __call__(self, data):
MyClass.my_dict[self.name].append(data)
Whenever I want to update the dictionary, I have to use MyClass.my_dict[key], but I'd like the class itself to support item assignment so I can just use MyClass[key] to do the same thing. Is there a way to do this? I'm using Python 2.7.
So, here's what I ended up doing:
class MyClassType(type):
my_dict = {}
def __getitem__(cls, key):
return cls.my_dict[key]
def __setitem__(cls, key, value):
cls.my_dict[key] = value
def __str__(cls):
return cls.my_dict.__str__()
def iteritems(cls):
return cls.my_dict.iteritems()
class MyClass(object):
__metaclass__ = MyClassType
def __init__(self, name):
self.name = name
MyClass[self.name] = []
def __call__(self, data):
MyClass[self.name].append(data)

Categories