Public, protected and private attributes accessibility - attributes

I have a question about the accessibility of the different access level of class attributes.
I wrote this code:
class struct:
    def __init__(self, dict):
        for key in dict:
            setattr(self, '__'+key, dict[key])
        for key in dict:
            setattr(self, '_'+key, dict[key])
        for key in dict:
            setattr(self, key, dict[key])
    def access_data(self):
        print(self.a)
    def access_protected_data(self):
        print(self._a)
    def access_private_data(self):
        print(self.__a)
mydict = {'a': 2, 'b': 'abc', 'c': [4]}
q = struct(mydict)
q.a = 4
q.access_data()
q._a = 5
q.access_protected_data()
q.__a = 6
q.access_private_data()
The program will print:
4
5
and sets q.__a = 6
 
I don't understand this behaviour. I would think that the program wouldn't be able to set the q.__a=6 outside of the class, at the same time I would expect the program to be able to print q.__a from a function inside the class.
Could you please explain?

Related

Error trying to access a parent variable from his child class

So I have this class:
class UniversalHash(HashClass):
##################################################
def __init__(self):
super().__init__()
self.__MParamK = int(0)
self.__MParamC = int(0)
self.__MParamD = int(0)
# Override #
def FindHash(self, Key):
return (((self.__MParamK * Key) + self.__MParamC) % self.__MParamD) % self.__MParamL
def SetParamK(self, Value):
self.__MParamK = Value
def SetParamC(self, Value):
self.__MParamC = Value
def SetParamD(self, Value):
self.__MParamD = Value
And the parent class:
class HashClass:
##################################################
def __init__(self):
self.__MParamL = int(0)
def SetParamL(self, Value):
self.__MParamL = Value
def GetParamL(self):
return self.__MParamL
def FindHash(self, Key):
pass
When I try to access to the variable __MParamL (the variable created in the parent), it gives me an exception telling me that the variable is not an attribute of this class, I have searched on the web and it seems this is the correct way to write the code (maybe the overridden function is the problem?). Any help is appreciated
When you name an instance attribute with a leading double underscore, it will get name mangled, E.g.,
>>> class A:
... def __init__(self):
... self.x = 42
... self.__y = 42
...
>>> a = A()
>>> vars(a)
{'x': 42, '_A__y': 42}
Instead, you should just use a single underscore, E.g.,
>>> class A:
... def __init__(self):
... self.x = 42
... self._y = 42
...
>>> a = A()
>>> vars(a)
{'x': 42, '_y': 42}

Overload Parameter for Dict

this is my problem:
I have two classes. In the Student class, a dict is passed in the constructor. This dict contains a list of dict. How can I pass the elements from this list to the Course class?
The classes are updated with the dict.
The metaclass is for overloading the _update function which I use in the bouth classes. #singledispatchmethod is for this because I use two constructors. One for the data (individual parameters) and the others for the dict.
from functools import singledispatchmethod
class MetaObject(object):
def _update(self, newDict: dict):
for key, value in newDict.items():
setattr(self, key, value)
class Course(MetaObject):
_name: str
#singledispatchmethod
def __init__(self):
pass
#__init__.register
def _(self, name: str):
self._name = name
#__init__.register(dict)
def _(self, dict: dict):
self._update(dict)
def print(self):
print("name:", self._name)
class Student(MetaObject):
_name: str
_courses: list
#singledispatchmethod
def __init__(self):
pass
#__init__.register
def _(self, name: str, courses: list):
self._name = name
self._courses = courses
#__init__.register(dict)
def _(self, dictValue: dict):
self._update(dictValue)
def print(self):
print("Name:", self._name, "Couses:")
c: Course
for c in self._courses:
print(c)
course1 = Course("Data Structures")
course2 = Course("Computer Networks")
student = Student("Danish", [course1, course2])
std_info = {'_name': "Danish", '_courses': [{"_name": 'Data Structures'}, {"_name": 'Computer Networks'}]}
student = Student(std_info)
student.print()

Conflicts when find and "replace" a method dynamically

I have a class consisting of a "list" of static methods, A. I want to change its behavior with a class-decorator, Meta, which acts on a specific static method, in this example content, by performing the method m.
My original attempt, CASE=2, didn't work as expected, so I started I case study. I introduced a new class B, which has slightly different implementation of an other method, info but raised a funny error, and a new class C just without the method, info.
case 2: the greedy case
d[i] = classmethod(lambda cls, *args: mcs.m( getattr(target_cls, i)(*args)) ) it doesn't work properly, maybe too many nested dynamic expressions?
case 1: it essentially case 2 but the expression is divided in two lines, and it works
o = getattr(target_cls, i)
d[i] = classmethod(lambda cls, *args: mcs.m(o(*args)))
Here the code
class Meta:
def __new__(mcs, target_cls):
if CASE == 1:
print('case 1')
d = {}
for i in dir(target_cls):
if i == 'content':
o = getattr(target_cls, i)
d[i] = classmethod(lambda cls, *args: mcs.m(o(*args)))
if CASE == 2:
print('case 2')
d = {}
for i in dir(target_cls):
if i == 'content':
d[i] = classmethod(lambda cls, *args: mcs.m( getattr(target_cls, i)(*args)) )
return type('AAA', (target_cls,), d)
#classmethod
def m(mcs, p):
return '--> ', p
class A:
#staticmethod
def content(response):
return 'static_method', response
#staticmethod
def info(response):
return response
class B:
#staticmethod
def content(response):
return 'static_method', response
#staticmethod
def info(response):
response.sort()
return response
class C:
#staticmethod
def content(response):
return 'static_method', response
# call the "content" class-method of each class for all different cases
for cls in (A, B, C):
print(cls.__name__)
for case in range(1,3):
CASE = case
R = Meta(cls)
try:
print(R.content('ppp'))
except Exception as e: print(e)
print()
Output
A
case 1
('--> ', ('static_method', 'ppp'))
case 2
('--> ', 'ppp') # no decoration
B
case 1
('--> ', ('static_method', 'ppp'))
case 2
'str' object has no attribute 'sort' # <- complained about the other method
C # <- this is ok BUT I removed the other method!
case 1
('--> ', ('static_method', 'ppp'))
case 2
('--> ', ('static_method', 'ppp')) # <- here the decoration took place
The question is why case 2 doesn't work, if it is a limitation of the language then of what kind?
Extra question: how to explain the error of class B case 2
I guess that the issue is caused by the loop and the origin is the fact that each statement has not its own scope (in the loop). By passing i as a key parameter of the lambda fixed the problem.
class Meta:
def __new__(mcs, target_cls):
d = {}
for i in dir(target_cls):
if i == 'content':
d[i] = classmethod(lambda cls, *args, m_name=i: mcs.m( getattr(target_cls, m_name)(*args)) )
return type('AAA', (target_cls,), d)
#classmethod
def m(mcs, p):
return '--> ', p
class A:
#staticmethod
def content(response):
return 'static_method', response
#staticmethod
def info(response):
return response
print(A.content)
print(Meta(A).content)
print(Meta(A).content('a'))
print(Meta(A).info)
Output
<function A.content at 0x7f04500740d0> # original static method
<bound method Meta.__new__.<locals>.<lambda> of <class '__main__.AAA'>> # class method
('--> ', ('static_method', 'a'))
<function A.info at 0x7f0450074040>

Dumping custom class objects to a YAML file

I would like some help on dumping a custom class object to a YAML file. A representation of my class looks like below:
from classes.enum_classes import Priority, Deadline
class Test(yaml.YAMLObject):
yaml_tag = u'!RandomTestClass'
def __init__(self):
self._name = ""
self._request_id = ""
self._order = None
self._priority = Priority.medium
self._deadline = Deadline.label_c
The last two parameters are objects of different classes, both of which are Enum derived classes. I am trying to dump the contents of an object of Test class to a YAML output file. My __repr__ method for the Test class looks so:
def __repr__(self):
return "(name=%r, request=%r, order=%r, priority=%r, deadline=%r)" % \
((str(self.name) + str(self.order)), self.request_id, self.order,
self.priority.name, self._deadline.name)
Working off the constructors and representers section of the PyYAML documentation and the example provided there (especially considering that the authors use lists for some of the class variables), I would expect my YAML file to display the actual display tags in the __repr__ method, rather than the variable names themselves. This is what I see currently:
--- !ContainerClass
_requests: !!python/object/apply:collections.defaultdict
args:
- !!python/name:builtins.list ''
dictitems:
'108':
- !RandomTestClass
_deadline: &id002 !Deadline '3'
_name: '108.1'
_order: '1'
_priority: &id006 !Priority '1'
_request_id: '108'
- !RandomTestClass
_deadline: &id002 !Deadline '3'
_name: '108.2'
_order: '2'
_priority: &id006 !Priority '1'
_request_id: '108'
_name: TestContainer
I want it to look like so:
---
Requests:
- name: '108.1'
- requestID: '108'
- priority: '1'
- order: '1'
- deadline: '3'
- name: '108.2' <for the second entry in the list and so on>
Name: ContainerClass
No amount of fiddling around with the __repr__ method or anything else has resulted in the output I would like. So there are two issues I would love to get some help with.
How do I get a sane, readable representation? I am guessing I will have to write a custom representer, so if someone could guide me with some pointers, since I was not able to find much information on that any way.
Getting rid of those pointers, or whatever we would want to call them next to priority and deadline. Priority and Deadline are the two classes referenced in my __init___ method above, that are Enum subclasses. Since they are already subclasses, any attempts to subclass them to yaml.YAMLObject result in an error with mixins. To get around that, some posts suggested I do so:
class Priority(Enum):
low = 0
medium = 1
high = 2
class Deadline(Enum):
label_a = 0
label_b = 1
label_c = 2
label_d = 3
def priority_enum_representer(dumper, data):
return dumper.represent_scalar('!Priority', str(data.value))
def deadline_enum_representer(dumper, data):
return dumper.represent_scalar('!Deadline', str(data.value))
yaml.add_representer(Deadline, deadline_enum_representer)
yaml.add_representer(Priority, priority_enum_representer)
Any information/pointers on solving these two issues will be much much appreciated. Apologies for the long post, but I have learnt that more information generally leads to much more precise help.
UPDATE:
My YAML file is written based on a list of these RandomTestClass objects that are stored in a defaultdict(list) in a ContainerClass.
class ContainerClass(yaml.YAMLObject):
yaml_tag = u'ContainerClass'
def __init__(self):
self._name = ""
self._requests = defaultdict(list)
def __repr__(self):
return "(Name=%r, Requests=%r)" % \
(self._name, str(self._requests))
#property
def requests(self):
return self._requests
#requests.setter
def requests(self, new_req, value=None):
if type(new_req) is dict:
self._requests = new_req
else:
try:
self._requests[new_req].append(value)
except AttributeError:
# This means the key exists, but the value is a non-list
# entity. Change existing value to list, append new value
# and reassign to the same key
list_with_values \
= [self._requests[new_req], value]
self._requests[new_req] = list_with_values
The ContainerClass holds instances of Test objects. In another class, which is the entry point for my code containing __main__, I create multiple instances of Test objects, that are then stored in an ```ContainerClass`` object and dumped out to the YAML file.
# requisite imports here, based on
# how the files are stored
from classes.Test import Test
from classes.ContainerClass import ContainerClass
class RunTestClass:
if __name__ == '__main__':
yaml_container = ContainerClass()
test_object_a = Test()
test_object_a._name = '108.1'
test_object_a._order = 1
test_object_a._request_id = '108'
yaml_container._name = "TestContainer"
yaml_container._requests[test_object_a._request_id] = test_object_a
test_object_b = Test()
test_object_b._name = '108.2'
test_object_b._order = 2
test_object_b._request_id = '108'
yaml_container._name = "TestContainer"
yaml_container._requests[test_object_b._request_id] = test_object_b
with open(output_file, mode='w+') as outfile:
for test_class_object in yaml_container._requests:
yaml.dump(test_class_object, outfile, default_flow_style=False,
explicit_start=True, explicit_end=True)
UPDATE:
Adding a single, consolidated file to the question, executable to replicate the issue.
import yaml
from enum import Enum
from collections import defaultdict
class Priority(Enum):
low = 0
medium = 1
high = 2
class Deadline(Enum):
label_a = 0
label_b = 1
label_c = 2
label_d = 3
def priority_enum_representer(dumper, data):
return dumper.represent_scalar('!Priority', str(data.value))
def deadline_enum_representer(dumper, data):
return dumper.represent_scalar('!Deadline', str(data.value))
yaml.add_representer(Deadline, deadline_enum_representer)
yaml.add_representer(Priority, priority_enum_representer)
class Test(yaml.YAMLObject):
yaml_tag = u'!RandomTestClass'
def __init__(self):
self._name = ""
self._request_id = ""
self._order = None
self._priority = Priority.medium
self._deadline = Deadline.label_c
#property
def name(self):
return self._name
#name.setter
def name(self, name):
self._name = name
#property
def request_id(self):
return self._request_id
#request_id.setter
def request_id(self, r_id):
self._request_id = r_id
#property
def order(self):
return self._order
#order.setter
def order(self, order):
self._order = order
#property
def priority(self):
return self._priority
#priority.setter
def priority(self, priority):
self._priority = priority
#property
def deadline(self):
return self._deadline
#deadline.setter
def deadline(self, deadline):
self._deadline = deadline
def __str__(self):
return self.name + ", " + self._request_id + ", " + str(self.order) + ", " \
+ str(self.priority) + ", " + str(self.deadline)
class ContainerClass(yaml.YAMLObject):
yaml_tag = u'ContainerClass'
def __init__(self):
self._name = ""
self._requests = defaultdict(list)
def __repr__(self):
return "(Name=%r, Requests=%r)" % \
(self._name, str(self._requests))
#property
def name(self):
return self._name
#name.setter
def name(self, name):
self._name = name
#property
def requests(self):
return self._requests
def set_requests(self, new_req, value=None):
if type(new_req) is dict:
self._requests = new_req
else:
try:
self._requests[new_req].append(value)
except AttributeError:
# This means the key exists, but the value is a non-list
# entity. Change existing value to list, append new value
# and reassign to the same key
print("Encountered a single value, converting to a list and appending new value")
list_with_values \
= [self._requests[new_req], value]
self._requests[new_req] = list_with_values
yaml_container = ContainerClass()
yaml_container.name = "TestContainer"
test_object_a = Test()
test_object_a._name = '108.1'
test_object_a._order = 1
test_object_a._request_id = '108'
yaml_container.set_requests(test_object_a.request_id, test_object_a)
test_object_b = Test()
test_object_b._name = '108.2'
test_object_b._order = 2
test_object_b._request_id = '108'
yaml_container.set_requests(test_object_b.request_id, test_object_b)
with open('test.yaml', mode='w+') as outfile:
yaml.dump(yaml_container, outfile, default_flow_style=False,
explicit_start=True, explicit_end=True)
There are different ways to solve this. Generally, you want to define a classmethod to_yaml in ContainerClass that will be called by the dumper, and implement the transition from native structure to YAML node graph there.
A minimal solution would be to just construct the structure you want to have as normal dict with a list in it, and tell the dumper to use that instead of the real structure:
#classmethod
def to_yaml(cls, dumper, data):
rSeq = []
for value in data._requests.values():
for t in value:
rSeq.extend([
{"name": t._name},
{"requestID": t._request_id},
{"priority": t._priority},
{"order": t._order},
{"deadline": t._deadline}
])
return dumper.represent_mapping("tag:yaml.org,2002:map",
{"Requests": rSeq, "Name": data._name})
This will give you
---
Name: TestContainer
Requests:
- name: '108.1'
- requestID: '108'
- priority: &id001 !Priority '1'
- order: 1
- deadline: &id002 !Deadline '2'
- name: '108.2'
- requestID: '108'
- priority: *id001
- order: 2
- deadline: *id002
...
YAML generates anchors & aliases for priority and requestID because the values refer the same objects. You can avoid those by doing
yaml.Dumper.ignore_aliases = lambda *args : True
before you dump the YAML.
You can be more sophisticated and iterate the properties instead of hard coding the names, but that is beyond the scope of this answer. If you want to load this YAML again into the same structure, you will need to add another classmethod from_yaml implementing the reverse transformation.

how can i iterate class objects while using generator in python?

i want to compare the 2000 pairs of a and b, and print the matching pairs and count of them.can anyone help me to get rid of it.it shows this error TypeError: 'seq_generator' object is not iterable at line 34
class generator(object):
def __init__(self,s,start_A,fact_A):
self.s=s
self.start_A=start_A
self.fact_A = fact_A
def seq_gen_A(self):
while self.s>0:
self.gen_A=(self.start_A*self.fact_A)%2147483647
self.g=self.gen_A
self.start_A=self.gen_A
self.bin_A=(bin(self.gen_A)[-16:])
yield self.bin_A
self.s=self.s-1
def next(self):
for i in self.seq_gen_A():
return i
def main():
s=200
count=0
a=generator(s,65,16807)
b=generator(s,8921,48271)
print("Matching pair")
print("*************")
for i in range(0,s):
if next(a)==next(b):
count+=1
print(a,b)
print('Matching pair count',count)
You are defining your generator not correctly. You need methods __iter__ and __next__:
class generator(object):
def __init__(self, s, start_A, fact_A):
self.s = s
self.start_A = start_A
self.fact_A = fact_A
def __iter__(self):
return self
def __next__(self):
if self.s <= 0:
raise StopIteration()
gen_A = (self.start_A*self.fact_A)%2147483647
self.start_A = gen_A
yield bin(gen_A)[-16:]
self.s -= 1

Resources