I have a scheme like:
class Base(object):
param, d=0, 1
def get_all(self):
while True:
a = self.get_xxx(param)
if not a:
break
handle(a)
param += d
class A(Base):
def get_xxx(param):
return some_method(param)
class B(Base):
def get_xxx(param):
return other_method(param)
Then, I was informed that for B, after each get_xxx param should be a+1 instead of param+d. That means I need to extract the param change logic at the end of get_all. I came up with a scheme using iterator:
class Base(object):
def get_all(self):
get_xxx = self.get_xxx()
while True:
a = get_xxx.next()
if not a:
break
handle(a)
class A(Base):
def get_xxx():
param, d = 0, 1
while True:
yield somemethod(param)
param += d
class B(Base):
def get_xxx():
param = 0
while True:
a = somemethod(param)
param = a + 1
yield a
Problem solved, but somehow I feel uncomfortable. So I wonder if there's a better solution? Many thanks!
I would make things like param and d instance attributes:
class Base(object):
def __init__(self):
self.param = 0
self.d = 1
then you don't have to pass anything explicitly into get_xxx(). You could replace
param += d
with
self.iterate_param(a):
in Base.get_all() then define iterate_param() appropriately in your two subclasses, i.e.
class A(Base):
...
def iterate_param(self, a):
self.param += self.d
class B(Base):
...
def iterate_param(self, a):
self.param = a + 1
Related
I have a python class as below.
class A(object):
def __init__(self, logger):
self.b = B()
self.logger = logger
def meth1(self):
self.b.mymethod1()
def meth2(self):
self.meth1()
self.b.mymethod2()
.........
class B(object):
---------
How can I count how many time I accessed self.b variable on the invocation of meth2() or any method of class A. Is there any way, I can log the usage of self.b variable?
make 'b' a property and and increase the counter corresponding to be in the setter.
#property
def b(self):
self.b_counter += 1
return self._b
and in your class replace b with _b
If you don't want to make a property, you can log the read/write access using __getattribute__ (not __getattr__ since b exists and would not be called) and __setattr__:
class A(object):
def __init__(self):
# initialize counters first !
self.b_read_counter = 0
self.b_write_counter = 0
# initialize b
self.b = 12
def __getattribute__(self,attrib):
# log read usage
if attrib=="b":
self.b_read_counter+=1
# now return b value
return object.__getattribute__(self, attrib)
def __setattr__(self,attrib,value):
if attrib=="b":
self.b_write_counter+=1
return object.__setattr__(self, attrib,value)
a = A()
a.b = 23 # second write access (first is in the init method)
if a.b == 34: # first read access
print("OK")
if a.b == 34:
print("OK")
if a.b == 34: # third read access
print("OK")
print(a.b_read_counter)
print(a.b_write_counter)
result:
3
2
You can use descriptors for this or just make a property which is basically is descriptor.
class A(object):
def __init__(self, logger):
self._b = B()
self._b_counter = 0
self.logger = logger
#property
def b(self):
self._b_counter += 1
return self._b
def meth1(self):
self.b.mymethod1()
def meth2(self):
self.meth1()
self.b.mymethod2()
You can use property, somtehing like:
class A(object):
def __init__(self, logger):
self._b = B()
self._count = 0
self.logger = logger
#property
def b(self):
self._count += 1
return self._b
...
...
I want local variable of a class to be changed by other class. My script is similar to the following :
import datetime
b = []
class P:
def __init__(self):
self.count = 1
self.create()
def create(self):
global b
a = C(self.count)
for i in range(10):
a.print_name()
print b
class C:
def __init__(self, *data):
self.test = data[0]
#staticmethod
def print_name():
global b
b.append(datetime.datetime.now())
o = P()
How to avoid use of a global variable . On web i found use of "super " can resolve the issue . Please help in this regard .
Make C constructor to accept P instance. And call the method of P to append item to instance attribute of P object.
class P:
def __init__(self):
self.count = 1
self.items = []
self.create()
def append(self, item):
self.items.append(item)
def create(self):
a = C(self, self.count) # <-- Pass P instance (self)
for i in range(10):
a.print_name()
print self.items
class C:
def __init__(self, p_instance, *data):
self.p_instance = p_instance # <-- Save P instance to use later
self.test = data[0]
def print_name(self):
self.p_instance.append(datetime.datetime.now()) # <-- Call p instance method
You are probably looking for a class attribute. If you add b as an attribute to the C class, it can be accessed as C.b and C().b, i.e. from a reference to the class or any instance.
class C(object): # classes in py2 should inherit from object!
b = [] # b inside C definition
#classmethod
def print_name(cls):
cls.b.append(datetime.datetime.now())
class P(object):
def __init__(self):
self.count = 1
self.create()
def create(self):
a = C(self.count)
for i in range(10):
a.print_name()
print C.b # or a.b
Of course, you can also place b on P. In this case, do
def print_name():
P.b.append(datetime.datetime.now())
Let's say that I have six different classes and three of them should use the same constant value. What can we do? We either:
Define as global variable
A = 1
class B:
def __init__(self):
self.a = A
class C:
def __init__(self):
self.a = A
class D:
def __init__(self):
self.a = A
Define as class level for 1 class and give it to another class:
class B:
A = 1
def __init__(self):
self.b = 2
class C:
def __init__(self, a):
self.a = a
self.b = 3
b = B()
c = B(a=b.A)
The second way I just made up and as for me it's dirty and not convenient. Is there any way to avoid using a global variable?
Use class inheritance:
class Holder:
a = 4
class A(Holder):
pass
print A().a
You could use inheritance, using B as the base class
class B:
A = 1
def __init__(self):
self.b = 2
class C(B):
def __init__(self):
B.__init__(self)
self.a = B.A
self.b = 3
b = B()
c = C()
print c.a
I would like to maintain count of A and B objects, B is subclassed from A. So the counts should be specific to A and B. For example, if I create 3 A objects and 2 B objects, by virtue of constructor call, count for A becomes 3+2=5, but I would like to keep as 3 (not when used as a subobject as part of B). Please comment on the following code snippet:
class A:
acount = 0 # class variable
def __init__(self, isFullA = True):
if (isFullA):
self.iamFullA = True
A.acount += 1
else:
self.iamFullA = False
def __del__(self):
if (self.iamFullA):
A.acount -= 1
class B(A):
bcount = 0 # class variable
def __init__(self, isFullB = True):
A.__init__(self,False)
if (isFullB):
self.iamFullB = True
B.bcount += 1
else:
self.iamFullB = False
def __del__(self):
if (self.iamFullB):
B.bcount -= 1
#MAIN
L=[]
for i in range(3):
L.append(A())
for i in range(2):
L.append(B())
print "A.acount = " + str(A.acount)
print "B.bcount = " + str(B.bcount)
The output is:
A.acount = 3
B.bcount = 2
You're making it way to complicated - all you need is to have a distinct count class attribute for each class:
class A(object):
_counter = 0
#classmethod
def _inc(cls):
cls._counter += 1
#classmethod
def _dec(cls):
cls._counter -= 1
#classmethod
def get_count(cls):
return cls._counter
def __init__(self):
self._inc()
def __del__(self):
self._dec()
class B(A):
_counter = 0
def __init__(self, wot):
super(B, self).__init__()
self.wot = wot
L=[]
for i in range(3):
L.append(A())
for i in range(2):
L.append(B(i))
print "A.count = {}".format(A.get_count())
print "B.count = {}".format(B.get_count())
Note that I used classmethods to ensure we're accessing the class attribute, as self._counter += 1 in the __init__ would create an instance attribute. You could also get the right behaviour using type(self)._counter += 1 (or self.__class__._counter += 1) but that's a bit ugly imho.
If this is for an API other devs will build upon, you may want to use a custom metaclass to ensure each subclass has it's own _counter, ie:
class CounterType(type):
def __new__(meta, name, bases, attribs):
if "_counter" not in attribs:
attribs["_counter"] = 0
return type.__new__(meta, name, bases, attribs)
class CounterBase(object):
__metaclass__ = CounterType
#classmethod
def _inc(cls):
cls._counter += 1
#classmethod
def _dec(cls):
cls._counter -= 1
#classmethod
def get_count(cls):
return cls._counter
def __init__(self):
self._inc()
def __del__(self):
self._dec()
class A(CounterBase):
pass
class B(A):
def __init__(self, wot):
super(B, self).__init__()
self.wot = wot
L=[]
for i in range(3):
L.append(A())
for i in range(2):
L.append(B(i))
print "A.count = {}".format(A.get_count())
print "B.count = {}".format(B.get_count())
How can ignore the member Trivial._ignore when serializing this object?
import yaml
class Trivial(yaml.YAMLObject):
yaml_tag = u'!Trivial'
def __init__(self):
self.a = 1
self.b = 2
self._ignore = 3
t = Trivial()
print(yaml.dump(t))
prints
!Trivial
_ignore: 3
a: 1
b: 2
def my_yaml_dump(yaml_obj):
my_ob = deepcopy(yaml_obj)
for item in dir(my_ob):
if item.startswith("_") and not item.startswith("__"):
del my_ob.__dict__[item]
return yaml.dump(my_ob)
something like this would ignore anything with a single (leading) underscore
I think this is what you want
class Trivial(yaml.YAMLObject):
yaml_tag = u'!Trivial'
def __init__(self):
self.a = 1
self.b = 2
self._ignore = 3
#classmethod
def to_yaml(cls, dumper, data):
# ...
my_ob = deepcopy(data)
for item in dir(my_ob):
if item.startswith("_") and not item.startswith("__"):
del my_ob.__dict__[item]
return dumper.represent_yaml_object(cls.yaml_tag, my_ob, cls,
flow_style=cls.yaml_flow_style)
although a better method (stylistically)
class SecretYamlObject(yaml.YAMLObject):
hidden_fields = []
#classmethod
def to_yaml(cls,dumper,data):
new_data = deepcopy(data)
for item in cls.hidden_fields:
del new_data.__dict__[item]
return dumper.represent_yaml_object(cls.yaml_tag, new_data, cls,
flow_style=cls.yaml_flow_style)
class Trivial(SecretYamlObject):
hidden_fields = ["_ignore"]
yaml_tag = u'!Trivial'
def __init__(self):
self.a = 1
self.b = 2
self._ignore = 3
print yaml.dump(Trivial())
this is adhering to pythons mantra of explicit is better than implicit